# CyberPanel OpenLiteSpeed Module - Complete Usage Guide **Version:** 2.2.0 **Last Updated:** December 28, 2025 **Status:** Production Ready --- ## Table of Contents 1. [Getting Started](#getting-started) 2. [Header Directives](#1-header-directives) 3. [Request Header Directives](#2-request-header-directives) 4. [Environment Variables](#3-environment-variables) 5. [Access Control](#4-access-control) 6. [Redirect Directives](#5-redirect-directives) 7. [Error Documents](#6-error-documents) 8. [FilesMatch Directives](#7-filesmatch-directives) 9. [Expires Directives](#8-expires-directives) 10. [PHP Directives](#9-php-directives) 11. [Brute Force Protection](#10-brute-force-protection) 12. [CyberPanel Integration](#cyberpanel-integration) 13. [Real-World Examples](#real-world-examples) 14. [Troubleshooting](#troubleshooting) --- ## Getting Started ### What is This Module? The CyberPanel OpenLiteSpeed Module brings Apache .htaccess compatibility to OpenLiteSpeed servers. It allows you to use familiar Apache directives without switching web servers. ### Quick Start 1. **Module is pre-installed** on CyberPanel servers 2. **Create .htaccess** in your website's public_html directory 3. **Add directives** from this guide 4. **Test** using curl or browser ### Basic .htaccess Example ```apache # Security headers Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" # Enable brute force protection BruteForceProtection On ``` --- ## 1. Header Directives ### What Are HTTP Headers? HTTP headers are metadata sent with web responses. They control browser behavior, caching, security, and more. ### Supported Operations | Operation | Purpose | Syntax | |-----------|---------|--------| | **set** | Set header (replaces existing) | `Header set Name "Value"` | | **unset** | Remove header | `Header unset Name` | | **append** | Append to existing header | `Header append Name "Value"` | | **merge** | Add if not present | `Header merge Name "Value"` | | **add** | Always add (allows duplicates) | `Header add Name "Value"` | ### How to Use #### Basic Security Headers **What it does:** Protects against clickjacking, XSS, and MIME sniffing. ```apache # Prevent site from being embedded in iframe (clickjacking protection) Header set X-Frame-Options "SAMEORIGIN" # Prevent MIME type sniffing Header set X-Content-Type-Options "nosniff" # Enable XSS filter in browsers Header set X-XSS-Protection "1; mode=block" # Control referrer information Header set Referrer-Policy "strict-origin-when-cross-origin" # Restrict browser features Header set Permissions-Policy "geolocation=(), microphone=(), camera=()" ``` **Testing:** ```bash curl -I https://yourdomain.com | grep -E "X-Frame|X-Content|X-XSS" ``` #### Cache Control Headers **What it does:** Controls how browsers cache your content. ```apache # Cache for 1 year (static assets) Header set Cache-Control "max-age=31536000, public, immutable" # No caching (dynamic content) Header set Cache-Control "no-cache, no-store, must-revalidate" Header set Pragma "no-cache" Header set Expires "0" # Cache for 1 hour Header set Cache-Control "max-age=3600, public" ``` **Testing:** ```bash curl -I https://yourdomain.com/style.css | grep Cache-Control ``` #### CORS Headers **What it does:** Allows cross-origin requests (needed for APIs, fonts, n8n, etc.). ```apache # Allow all origins Header set Access-Control-Allow-Origin "*" # Allow specific origin Header set Access-Control-Allow-Origin "https://app.example.com" # Allow specific methods Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" # Allow specific headers Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-Requested-With" # Allow credentials Header set Access-Control-Allow-Credentials "true" # Preflight cache duration Header set Access-Control-Max-Age "86400" ``` **Testing:** ```bash curl -I -H "Origin: https://example.com" https://yourdomain.com/api ``` #### Remove Server Identification **What it does:** Hides server information from attackers. ```apache Header unset Server Header unset X-Powered-By Header unset X-LiteSpeed-Tag ``` **Testing:** ```bash curl -I https://yourdomain.com | grep -E "Server|X-Powered" # Should return nothing ``` ### CyberPanel Integration #### Via File Manager 1. Log into **CyberPanel** 2. Go to **File Manager** 3. Navigate to `/home/yourdomain.com/public_html` 4. Create or edit `.htaccess` 5. Add header directives 6. Save and test #### Via SSH ```bash # Navigate to website directory cd /home/yourdomain.com/public_html # Edit .htaccess nano .htaccess # Add your headers Header set X-Frame-Options "SAMEORIGIN" # Save (Ctrl+X, Y, Enter) # Test curl -I https://yourdomain.com | grep X-Frame ``` ### Common Use Cases #### WordPress Security Headers ```apache # WordPress-specific security Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" Header set X-XSS-Protection "1; mode=block" Header set Referrer-Policy "strict-origin-when-cross-origin" Header unset X-Powered-By # Disable XML-RPC header Header unset X-Pingback ``` #### n8n CORS Configuration ```apache # Allow n8n webhooks Header set Access-Control-Allow-Origin "https://your-n8n-instance.com" Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" Header set Access-Control-Allow-Headers "Content-Type, Authorization" Header set Access-Control-Allow-Credentials "true" ``` #### API Response Headers ```apache # JSON API headers Header set Content-Type "application/json; charset=utf-8" Header set X-Content-Type-Options "nosniff" Header set Access-Control-Allow-Origin "*" Header set Cache-Control "no-cache, no-store, must-revalidate" ``` --- ## 2. Request Header Directives ### What Are Request Headers? Request headers are sent FROM the client TO the server. This feature lets you modify or add headers before they reach your PHP application. ### How It Works Since OpenLiteSpeed's LSIAPI doesn't support direct request header modification, these are implemented as **environment variables** accessible in PHP via `$_SERVER`. ### Supported Operations | Operation | Syntax | Result | |-----------|--------|--------| | **set** | `RequestHeader set Name "Value"` | `$_SERVER['HTTP_NAME']` | | **unset** | `RequestHeader unset Name` | Header removed | ### How to Use #### SSL/HTTPS Detection (Behind Proxy) **What it does:** Tells your application the request came via HTTPS (when behind Cloudflare, nginx proxy, etc.). ```apache # Set HTTPS protocol headers RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-SSL "on" RequestHeader set X-Real-IP "%{REMOTE_ADDR}e" ``` **PHP Usage:** ```php ``` #### Application Environment Identification **What it does:** Tags requests with environment information. ```apache # Identify environment RequestHeader set X-Environment "production" RequestHeader set X-Server-Location "us-east-1" RequestHeader set X-Request-Start "%{REQUEST_TIME}e" ``` **PHP Usage:** ```php ``` #### Custom Backend Headers **What it does:** Passes custom information to your application. ```apache # Custom application headers RequestHeader set X-API-Version "v2" RequestHeader set X-Feature-Flags "new-ui,beta-features" RequestHeader set X-Client-Type "web" ``` **PHP Usage:** ```php ``` ### CyberPanel Integration #### For WordPress Behind Cloudflare ```apache # In /home/yourdomain.com/public_html/.htaccess RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-SSL "on" # WordPress will now correctly detect HTTPS ``` **Verify in WordPress:** ```php // Add to wp-config.php if needed if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } ``` ### Common Use Cases #### Cloudflare + WordPress ```apache RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-SSL "on" RequestHeader set X-Real-IP "%{REMOTE_ADDR}e" ``` #### Laravel Behind Load Balancer ```apache RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}e" ``` --- ## 3. Environment Variables ### What Are Environment Variables? Environment variables are key-value pairs accessible in your PHP application. They're useful for configuration, feature flags, and conditional logic. ### Supported Directives | Directive | Purpose | Syntax | |-----------|---------|--------| | **SetEnv** | Set static variable | `SetEnv NAME value` | | **SetEnvIf** | Conditional set (case-sensitive) | `SetEnvIf attribute regex VAR=value` | | **SetEnvIfNoCase** | Conditional set (case-insensitive) | `SetEnvIfNoCase attribute regex VAR=value` | | **BrowserMatch** | Detect browser | `BrowserMatch regex VAR=value` | ### How to Use #### Static Configuration Variables **What it does:** Sets application configuration accessible in PHP. ```apache # Application settings SetEnv APPLICATION_ENV production SetEnv DB_HOST localhost SetEnv DB_NAME myapp_db SetEnv API_ENDPOINT https://api.example.com SetEnv FEATURE_FLAG_NEW_UI enabled SetEnv DEBUG_MODE off ``` **PHP Usage:** ```php ``` #### Conditional Variables (SetEnvIf) **What it does:** Sets variables based on request properties. ##### Supported Conditions - `Request_URI` - URL path - `Request_Method` - HTTP method (GET, POST, etc.) - `User-Agent` - Browser/client identifier - `Host` - Domain name - `Referer` - Referrer URL - `Query_String` - URL parameters - `Remote_Addr` - Client IP address **Examples:** ```apache # Detect API requests SetEnvIf Request_URI "^/api/" IS_API_REQUEST=1 # Detect POST requests SetEnvIf Request_Method "POST" IS_POST_REQUEST=1 # Detect specific domain SetEnvIf Host "^beta\." IS_BETA_SITE=1 # Detect search queries SetEnvIf Query_String "search=" HAS_SEARCH=1 # Detect local development SetEnvIf Remote_Addr "^127\.0\.0\.1$" IS_LOCAL=1 ``` **PHP Usage:** ```php ``` #### Browser Detection **What it does:** Identifies the user's browser for compatibility handling. ```apache # Case-insensitive browser detection SetEnvIfNoCase User-Agent "mobile|android|iphone|ipad" IS_MOBILE=1 SetEnvIfNoCase User-Agent "bot|crawler|spider|scraper" IS_BOT=1 SetEnvIfNoCase User-Agent "MSIE|Trident" IS_IE=1 # Specific browser matching BrowserMatch "Chrome" IS_CHROME=1 BrowserMatch "Firefox" IS_FIREFOX=1 BrowserMatch "Safari" IS_SAFARI=1 BrowserMatch "Edge" IS_EDGE=1 ``` **PHP Usage:** ```php Please use a modern browser'; } ?> ``` ### CyberPanel Integration #### Environment-Specific Configuration ```apache # In /home/yourdomain.com/public_html/.htaccess # Production settings SetEnv APPLICATION_ENV production SetEnv DEBUG_MODE off SetEnv CACHE_ENABLED on # Database connection SetEnv DB_HOST localhost SetEnv DB_NAME wp_database # Feature flags SetEnv ENABLE_CDN on SetEnv ENABLE_CACHE on ``` **WordPress Usage (wp-config.php):** ```php ``` ### Common Use Cases #### Mobile Detection + Redirect ```apache # Detect mobile users SetEnvIfNoCase User-Agent "mobile|android|iphone" IS_MOBILE=1 # Redirect mobile to subdomain (using PHP) ``` **PHP redirect:** ```php ``` #### API Rate Limiting Preparation ```apache # Tag API requests SetEnvIf Request_URI "^/api/" IS_API=1 SetEnvIf Request_Method "POST" IS_POST=1 ``` **PHP rate limiting:** ```php ``` --- ## 4. Access Control ### What is Access Control? Access control restricts who can access your website based on IP addresses. Perfect for staging sites, admin panels, or development environments. ### Directives | Directive | Syntax | Description | |-----------|--------|-------------| | **Order** | `Order deny,allow` or `Order allow,deny` | Set evaluation order | | **Allow** | `Allow from IP/CIDR` | Allow specific IP | | **Deny** | `Deny from IP/CIDR` | Deny specific IP | ### Supported IP Formats - **Single IP:** `192.168.1.100` - **CIDR Range:** `192.168.1.0/24` (entire subnet) - **Large Ranges:** `10.0.0.0/8` (entire class) - **IPv6:** `2001:db8::/32` - **Wildcard:** `all` (everyone) ### How Order Works #### Order deny,allow 1. Check **Deny** list first 2. Then check **Allow** list 3. **Allow overrides Deny** 4. Default: **DENY** if not in either list ```apache Order deny,allow Deny from all Allow from 192.168.1.100 # Result: Only 192.168.1.100 can access ``` #### Order allow,deny 1. Check **Allow** list first 2. Then check **Deny** list 3. **Deny overrides Allow** 4. Default: **ALLOW** if not in either list ```apache Order allow,deny Allow from all Deny from 192.168.1.100 # Result: Everyone except 192.168.1.100 can access ``` ### How to Use #### Block All Except Specific IPs (Recommended for Staging) ```apache # Only allow office IP and VPN Order deny,allow Deny from all Allow from 203.0.113.50 # Office IP Allow from 192.168.1.0/24 # Office LAN Allow from 10.8.0.0/24 # VPN range ``` **Use case:** Development/staging sites, admin areas **Testing:** ```bash # From allowed IP curl https://staging.example.com # Should work # From other IP curl https://staging.example.com # Should get 403 Forbidden ``` #### Allow All Except Specific IPs ```apache # Block known attackers Order allow,deny Allow from all Deny from 198.51.100.50 # Banned IP Deny from 203.0.113.0/24 # Banned subnet ``` **Use case:** Blocking spam IPs, attack sources #### Protect Admin Directory ```apache # In /home/yourdomain.com/public_html/admin/.htaccess Order deny,allow Deny from all Allow from 192.168.1.0/24 # Office network Allow from 203.0.113.100 # Your home IP ``` **Use case:** WordPress wp-admin protection ### CyberPanel Integration #### Protect Staging Site 1. Create subdomain `staging.yourdomain.com` in CyberPanel 2. Navigate to `/home/staging.yourdomain.com/public_html` 3. Create `.htaccess`: ```apache # Staging site - Office only Order deny,allow Deny from all Allow from YOUR.OFFICE.IP.HERE Allow from YOUR.HOME.IP.HERE ``` 4. Test: ```bash # Get your IP curl ifconfig.me # Test access curl -I https://staging.yourdomain.com # Should see 403 if not allowed ``` #### Protect WordPress Admin ```apache # In /home/yourdomain.com/public_html/wp-admin/.htaccess Order deny,allow Deny from all Allow from 203.0.113.50 # Your IP ``` **Important:** This creates TWO layers of protection: 1. IP restriction (from .htaccess) 2. Login authentication (from WordPress) #### Protect CyberPanel Access ```apache # In /usr/local/CyberCP/public/.htaccess (if web accessible) Order deny,allow Deny from all Allow from 127.0.0.1 # localhost Allow from 192.168.1.0/24 # Your network ``` ### Common Use Cases #### Development Environment ```apache # Dev site - developers only Order deny,allow Deny from all Allow from 192.168.1.0/24 # Office LAN Allow from 10.8.0.0/24 # VPN Allow from 203.0.113.50 # Lead developer home ``` #### Geographic Restriction ```apache # Block specific countries (you need to maintain IP list) Order allow,deny Allow from all Deny from 198.51.100.0/24 # Country X subnet Deny from 203.0.113.0/24 # Country Y subnet ``` #### API Endpoint Protection ```apache # In /home/yourdomain.com/public_html/api/.htaccess Order deny,allow Deny from all Allow from 10.0.0.0/8 # Internal network Allow from 172.16.0.0/12 # Private network ``` ### Troubleshooting **Problem:** Getting 403 even from allowed IP **Solution:** 1. Check your actual IP: `curl ifconfig.me` 2. Verify CIDR: `192.168.1.0/24` covers `192.168.1.1` to `192.168.1.254` 3. Check logs: `tail -f /usr/local/lsws/logs/error.log` **Problem:** Access control not working **Solution:** 1. Verify module loaded: `ls -la /usr/local/lsws/modules/cyberpanel_ols.so` 2. Check .htaccess permissions: `chmod 644 .htaccess` 3. Restart OpenLiteSpeed: `/usr/local/lsws/bin/lswsctrl restart` --- ## 5. Redirect Directives ### What Are Redirects? Redirects tell browsers to go to a different URL. Essential for SEO, site migrations, and URL structure changes. ### Directives | Directive | Syntax | Use Case | |-----------|--------|----------| | **Redirect** | `Redirect [code] /old /new` | Simple path redirects | | **RedirectMatch** | `RedirectMatch [code] regex target` | Pattern-based redirects | ### Status Codes | Code | Name | When to Use | |------|------|-------------| | **301** | Permanent | SEO-friendly, URL has moved forever | | **302** | Temporary | URL temporarily moved, may change back | | **303** | See Other | Redirect after POST (form submission) | | **410** | Gone | Resource permanently deleted | ### How to Use #### Simple Redirects **What it does:** Redirects one path to another. ```apache # Old page to new page Redirect 301 /old-page.html /new-page.html # Old directory to new directory Redirect 301 /old-blog /blog # Use keywords instead of codes Redirect permanent /old-url /new-url Redirect temp /maintenance /coming-soon ``` **Testing:** ```bash curl -I https://yourdomain.com/old-page.html # Should show: HTTP/1.1 301 Moved Permanently # Location: https://yourdomain.com/new-page.html ``` #### Force HTTPS **What it does:** Redirects HTTP to HTTPS. ```apache # Redirect HTTP to HTTPS Redirect 301 / https://yourdomain.com/ ``` **Better Alternative (checks if already HTTPS):** ```apache SetEnvIf Request_URI ".*" IS_HTTP=1 # Use with PHP to avoid redirect loop ``` **PHP solution:** ```php ``` #### Force WWW or Non-WWW **What it does:** Standardizes domain format for SEO. ```apache # Force www Redirect 301 / https://www.yourdomain.com/ # Force non-www (use RedirectMatch) RedirectMatch 301 ^(.*)$ https://yourdomain.com$1 ``` #### Pattern-Based Redirects (RedirectMatch) **What it does:** Uses regex to match and redirect URLs. ```apache # Blog restructuring RedirectMatch 301 ^/blog/(.*)$ /news/$1 # /blog/post-1 → /news/post-1 # Product ID migration RedirectMatch 301 ^/product-([0-9]+)$ /item/$1 # /product-123 → /item/123 # Year/month/title to title RedirectMatch 301 ^/blog/([0-9]{4})/([0-9]{2})/(.*)$ /articles/$3 # /blog/2024/12/my-post → /articles/my-post # Category reorganization RedirectMatch 301 ^/category/(.*)$ /topics/$1 ``` **Testing:** ```bash curl -I https://yourdomain.com/blog/my-post # Should redirect to /news/my-post ``` ### CyberPanel Integration #### Site Migration (Old Domain to New) ```apache # In old site's .htaccess Redirect 301 / https://new-domain.com/ ``` **Steps:** 1. Keep old domain active in CyberPanel 2. Add redirect to `/home/old-domain.com/public_html/.htaccess` 3. Monitor traffic migration 4. After 6 months, can delete old domain #### WordPress Permalink Change **Scenario:** Changed permalinks from `/?p=123` to `/blog/post-title` ```apache # WordPress handles this automatically, but for custom: RedirectMatch 301 ^/\?p=([0-9]+)$ /blog/post-$1 ``` #### E-commerce URL Update ```apache # Old: /products/view/123 # New: /shop/product-123 RedirectMatch 301 ^/products/view/([0-9]+)$ /shop/product-$1 ``` ### Common Use Cases #### Complete Site Redesign ```apache # Redirect old structure to new RedirectMatch 301 ^/about-us$ /about RedirectMatch 301 ^/contact-us$ /contact RedirectMatch 301 ^/services/(.*)$ /solutions/$1 RedirectMatch 301 ^/blog/(.*)$ /news/$1 ``` #### Affiliate Link Management ```apache # Short URLs for affiliate links Redirect 302 /go/amazon https://amazon.com/your-affiliate-link Redirect 302 /go/product https://example.com/long-url-here ``` #### Seasonal Campaigns ```apache # Temporary campaign redirect Redirect 302 /sale /christmas-sale-2025 Redirect 302 /promo /black-friday ``` #### Remove .html Extensions (SEO) ```apache # Old: /page.html # New: /page RedirectMatch 301 ^/(.*)/index\.html$ /$1/ RedirectMatch 301 ^/(.*)[^/]\.html$ /$1 ``` ### Troubleshooting **Problem:** Redirect loop **Solution:** Check for conflicting rules: ```apache # BAD - Creates loop Redirect 301 / https://example.com/ Redirect 301 / https://www.example.com/ # GOOD - Use one or the other Redirect 301 / https://www.example.com/ ``` **Problem:** Redirect not working **Solution:** 1. Clear browser cache (redirects are cached!) 2. Test with curl: `curl -I https://yoursite.com/old-page` 3. Check .htaccess syntax 4. Restart OpenLiteSpeed --- ## 6. Error Documents ### What Are Error Documents? Custom error pages shown when errors occur (404 Not Found, 500 Internal Server Error, etc.). ### Supported Error Codes | Code | Error | When It Happens | |------|-------|-----------------| | **400** | Bad Request | Malformed request | | **401** | Unauthorized | Authentication required | | **403** | Forbidden | Access denied | | **404** | Not Found | Page doesn't exist | | **500** | Internal Server Error | Server-side error | | **502** | Bad Gateway | Proxy/backend error | | **503** | Service Unavailable | Server overloaded/maintenance | ### Syntax ```apache ErrorDocument ``` ### How to Use #### HTML Error Pages **What it does:** Shows custom-designed error pages. ```apache # Custom error pages ErrorDocument 404 /errors/404.html ErrorDocument 500 /errors/500.html ErrorDocument 403 /errors/403.html ErrorDocument 503 /errors/maintenance.html ``` **Create error pages:** ```bash mkdir -p /home/yourdomain.com/public_html/errors ``` **404.html example:** ```html Page Not Found

404 - Page Not Found

The page you're looking for doesn't exist.

Go to Homepage ``` **Testing:** ```bash curl https://yourdomain.com/nonexistent-page # Should show your custom 404 page ``` #### Inline Messages **What it does:** Shows simple text message. ```apache ErrorDocument 403 "Access Denied - Contact Administrator" ErrorDocument 404 "Page Not Found - Please check the URL" ``` #### WordPress-Friendly Error Pages **What it does:** Routes errors through WordPress. ```apache # Let WordPress handle 404s ErrorDocument 404 /index.php?error=404 ``` **WordPress theme (404.php):** ```php

Page Not Found

Sorry, this page doesn't exist.

``` ### CyberPanel Integration #### Setup Custom Error Pages **Step 1:** Create error directory ```bash cd /home/yourdomain.com/public_html mkdir errors cd errors ``` **Step 2:** Create error page files ```bash nano 404.html # Add custom HTML # Save (Ctrl+X, Y, Enter) nano 500.html # Add custom HTML # Save ``` **Step 3:** Configure .htaccess ```apache # In /home/yourdomain.com/public_html/.htaccess ErrorDocument 404 /errors/404.html ErrorDocument 500 /errors/500.html ErrorDocument 403 /errors/403.html ``` **Step 4:** Test ```bash curl https://yourdomain.com/test-404 ``` #### Maintenance Page ```apache # During maintenance ErrorDocument 503 /maintenance.html ``` **maintenance.html:** ```html Maintenance

We'll be right back!

Our site is undergoing maintenance.

Expected completion: 2 hours

``` **Trigger maintenance mode:** ```bash # Temporarily disable PHP mv index.php index.php.bak # Site will show 503 ``` ### Common Use Cases #### Professional 404 Page with Search **404.html:** ```html Page Not Found

404 - Page Not Found

Try searching:

Return to Homepage

``` #### Branded Error Pages ```apache ErrorDocument 400 /errors/400.html ErrorDocument 401 /errors/401.html ErrorDocument 403 /errors/403.html ErrorDocument 404 /errors/404.html ErrorDocument 500 /errors/500.html ErrorDocument 502 /errors/502.html ErrorDocument 503 /errors/503.html ``` Each page styled with your brand colors, logo, navigation. --- ## 7. FilesMatch Directives ### What is FilesMatch? FilesMatch applies directives only to files matching a regex pattern. Perfect for caching strategies, security headers per file type. ### Syntax ```apache # Directives here apply only to matching files Header set Name "Value" ``` ### Common File Patterns | Pattern | Matches | |---------|---------| | `\.(jpg\|png\|gif)$` | Images | | `\.(css\|js)$` | Stylesheets and JavaScript | | `\.(woff2?\|ttf\|eot)$` | Fonts | | `\.(pdf\|doc\|docx)$` | Documents | | `\.(html\|php)$` | Dynamic pages | | `\.json$` | JSON files | ### How to Use #### Cache Static Assets (Performance Boost) **What it does:** Tells browsers to cache images/fonts for a long time. ```apache # Images - Cache for 1 year Header set Cache-Control "max-age=31536000, public, immutable" Header unset ETag Header unset Last-Modified # Fonts - Cache for 1 year Header set Cache-Control "max-age=31536000, public, immutable" Header set Access-Control-Allow-Origin "*" # CSS/JS - Cache for 1 week (you update these more often) Header set Cache-Control "max-age=604800, public" ``` **Testing:** ```bash curl -I https://yourdomain.com/logo.png | grep Cache-Control # Should show: Cache-Control: max-age=31536000, public, immutable ``` **Performance Impact:** - First visit: Downloads all files - Return visits: Loads from browser cache (instant!) - Page load time: -50% to -80% #### Security Headers for HTML/PHP **What it does:** Applies security headers only to pages (not images). ```apache Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" Header set X-XSS-Protection "1; mode=block" Header set Referrer-Policy "strict-origin-when-cross-origin" ``` #### Prevent Caching of Dynamic Content **What it does:** Ensures dynamic pages are never cached. ```apache Header set Cache-Control "no-cache, no-store, must-revalidate" Header set Pragma "no-cache" Header set Expires "0" ``` #### CORS for Fonts (Fix Font Loading) **What it does:** Allows fonts to load from CDN or different domain. ```apache Header set Access-Control-Allow-Origin "*" ``` **Use case:** Fixes "Font from origin has been blocked by CORS policy" errors. #### Download Headers for Files **What it does:** Forces download instead of displaying in browser. ```apache Header set Content-Disposition "attachment" Header set X-Content-Type-Options "nosniff" ``` ### CyberPanel Integration #### WordPress Performance Optimization ```apache # In /home/yourdomain.com/public_html/.htaccess # Cache WordPress static assets Header set Cache-Control "max-age=31536000, public, immutable" # Cache CSS/JS (with version strings in WordPress) Header set Cache-Control "max-age=2592000, public" # Don't cache WordPress admin Header set Cache-Control "no-cache, no-store, must-revalidate" ``` **Result:** PageSpeed score +20-30 points #### WooCommerce Security ```apache # Protect sensitive files Order deny,allow Deny from all # JSON API security Header set X-Content-Type-Options "nosniff" Header set Content-Type "application/json; charset=utf-8" ``` ### Common Use Cases #### Complete Caching Strategy ```apache # Aggressive caching for static assets (1 year) Header set Cache-Control "max-age=31536000, public, immutable" Header unset ETag # Moderate caching for CSS/JS (1 month) Header set Cache-Control "max-age=2592000, public" # Short caching for HTML (1 hour) Header set Cache-Control "max-age=3600, public" # No caching for dynamic content Header set Cache-Control "no-cache, must-revalidate" ``` #### Media Library Protection ```apache # Prevent hotlinking (bandwidth theft) SetEnvIf Referer "^https://yourdomain\.com" local_ref SetEnvIf Referer "^$" local_ref Order deny,allow Deny from all Allow from env=local_ref ``` --- ## 8. Expires Directives ### What is mod_expires? Alternative syntax for setting cache expiration. More concise than Cache-Control headers. ### Directives ```apache ExpiresActive On ExpiresByType mime-type base+seconds ``` ### Time Bases - **A** = Access time (when user requests file) - **M** = Modification time (when file was last modified) ### Common Durations | Duration | Seconds | Example | |----------|---------|---------| | 1 minute | 60 | `A60` | | 1 hour | 3600 | `A3600` | | 1 day | 86400 | `A86400` | | 1 week | 604800 | `A604800` | | 1 month | 2592000 | `A2592000` | | 1 year | 31557600 | `A31557600` | ### How to Use #### Complete Expiration Strategy ```apache # Enable module ExpiresActive On # Images - 1 year ExpiresByType image/jpeg A31557600 ExpiresByType image/png A31557600 ExpiresByType image/gif A31557600 ExpiresByType image/webp A31557600 ExpiresByType image/svg+xml A31557600 ExpiresByType image/x-icon A31557600 # CSS and JavaScript - 1 month ExpiresByType text/css A2592000 ExpiresByType application/javascript A2592000 ExpiresByType application/x-javascript A2592000 ExpiresByType text/javascript A2592000 # Fonts - 1 year ExpiresByType font/ttf A31557600 ExpiresByType font/woff A31557600 ExpiresByType font/woff2 A31557600 ExpiresByType application/font-woff A31557600 ExpiresByType application/font-woff2 A31557600 # HTML - no cache ExpiresByType text/html A0 # PDF - 1 month ExpiresByType application/pdf A2592000 # JSON/XML - 1 hour ExpiresByType application/json A3600 ExpiresByType application/xml A3600 ``` **Testing:** ```bash curl -I https://yourdomain.com/image.jpg | grep -E "Expires|Cache-Control" ``` ### CyberPanel Integration #### WordPress Caching ```apache # In /home/yourdomain.com/public_html/.htaccess ExpiresActive On # WordPress uploads (images in wp-content/uploads) ExpiresByType image/jpeg A31557600 ExpiresByType image/png A31557600 ExpiresByType image/gif A31557600 # WordPress theme assets ExpiresByType text/css A2592000 ExpiresByType application/javascript A2592000 # WordPress HTML (dynamic, don't cache) ExpiresByType text/html A0 ``` ### FilesMatch vs Expires **Use FilesMatch when:** - Need multiple headers per file type - Need complex regex patterns - Want more control **Use Expires when:** - Only setting cache expiration - Want concise syntax - Working with MIME types **Both together:** ```apache ExpiresActive On ExpiresByType image/jpeg A31557600 Header set Cache-Control "public, immutable" Header unset ETag ``` --- ## 9. PHP Directives ### What Are PHP Directives? Change PHP configuration per-directory without editing php.ini. ### Directives | Directive | Syntax | Purpose | |-----------|--------|---------| | **php_value** | `php_value name value` | Set numeric/string values | | **php_flag** | `php_flag name on/off` | Set boolean (on/off) values | ### Requirements - Must use **LSPHP** (not PHP-FPM) - Must be **PHP_INI_ALL** or **PHP_INI_PERDIR** directive - CyberPanel uses LSPHP by default ✅ ### How to Use #### Memory and Execution Limits **What it does:** Allows scripts to use more memory/time. ```apache # Increase memory (default 128M) php_value memory_limit 256M # Increase execution time (default 30s) php_value max_execution_time 300 # Increase input time (default 60s) php_value max_input_time 300 # Increase max input variables (default 1000) php_value max_input_vars 5000 ``` **Use case:** WordPress imports, WooCommerce bulk operations, data processing. **Testing:** ```php ``` #### Upload Limits **What it does:** Allows larger file uploads. ```apache # Allow 100MB uploads (default 2M) php_value upload_max_filesize 100M php_value post_max_size 100M # Increase max file uploads (default 20) php_value max_file_uploads 50 ``` **Use case:** Media uploads, plugin/theme installation, backup uploads. **Testing:** ```php ``` #### Error Handling **What it does:** Controls error display and logging. ```apache # Production (hide errors) php_flag display_errors off php_flag log_errors on php_value error_log /home/yourdomain.com/logs/php_errors.log # Development (show errors) php_flag display_errors on php_value error_reporting 32767 ``` **Use case:** Debugging vs production security. #### Session Configuration **What it does:** Configures PHP sessions. ```apache # Session lifetime (1 hour) php_value session.gc_maxlifetime 3600 # Session cookie (close browser = logout) php_value session.cookie_lifetime 0 # Session security php_flag session.cookie_httponly on php_flag session.cookie_secure on php_value session.cookie_samesite Strict ``` **Use case:** Login session duration, security. #### Timezone **What it does:** Sets server timezone. ```apache php_value date.timezone "America/New_York" php_value date.timezone "Europe/London" php_value date.timezone "Asia/Tokyo" ``` **Use case:** Correct timestamps in logs, posts, events. **Testing:** ```php ``` ### CyberPanel Integration #### WordPress Performance Tuning ```apache # In /home/yourdomain.com/public_html/.htaccess # WordPress recommended settings php_value memory_limit 256M php_value max_execution_time 300 php_value max_input_time 300 php_value max_input_vars 5000 php_value upload_max_filesize 64M php_value post_max_size 64M # Production error handling php_flag display_errors off php_flag log_errors on php_value error_log /home/yourdomain.com/logs/php_errors.log # Session security php_flag session.cookie_httponly on php_flag session.cookie_secure on ``` #### WooCommerce Optimization ```apache # WooCommerce needs more resources php_value memory_limit 512M php_value max_execution_time 600 php_value max_input_vars 10000 php_value upload_max_filesize 128M php_value post_max_size 128M ``` #### Development vs Production **Development .htaccess:** ```apache php_flag display_errors on php_value error_reporting 32767 php_flag display_startup_errors on php_value memory_limit 512M ``` **Production .htaccess:** ```apache php_flag display_errors off php_flag log_errors on php_value error_log /home/yourdomain.com/logs/php_errors.log php_value memory_limit 256M ``` ### Common Use Cases #### Fix "Memory Exhausted" Error ```apache php_value memory_limit 512M ``` #### Fix "Maximum Execution Time Exceeded" ```apache php_value max_execution_time 300 ``` #### Fix "Upload Failed" (File Too Large) ```apache php_value upload_max_filesize 100M php_value post_max_size 100M ``` #### Fix "Maximum Input Vars Exceeded" (WordPress Theme Options) ```apache php_value max_input_vars 10000 ``` ### Supported Directives Most PHP ini settings can be changed: **✅ Supported:** - memory_limit - max_execution_time - max_input_time - max_input_vars - upload_max_filesize - post_max_size - display_errors - log_errors - error_log - error_reporting - session.* (all session directives) - date.timezone - default_charset - output_buffering **❌ Not Supported:** - enable_dl (PHP_INI_SYSTEM only) - safe_mode (deprecated) - open_basedir (security setting) --- ## 10. Brute Force Protection ### What is Brute Force Protection? Built-in WordPress login protection. Limits POST requests to wp-login.php and xmlrpc.php to stop password guessing attacks. ### Quick Start ```apache BruteForceProtection On ``` That's it! Default settings: 10 attempts per 5 minutes. ### How It Works 1. Tracks POST requests to `/wp-login.php` and `/xmlrpc.php` 2. Counts requests per IP address 3. Uses time-window quota system (e.g., 10 requests per 300 seconds) 4. When quota exhausted, applies action (block, log, or throttle) 5. Quota resets after time window expires ### Phase 1 Directives (Basic) | Directive | Values | Default | Description | |-----------|--------|---------|-------------| | **BruteForceProtection** | On/Off | Off | Enable protection | | **BruteForceAllowedAttempts** | 1-1000 | 10 | Max POST requests per window | | **BruteForceWindow** | 60-86400 | 300 | Time window (seconds) | | **BruteForceAction** | block/log/throttle | block | Action when limit exceeded | ### Phase 2 Directives (Advanced) | Directive | Values | Default | Description | |-----------|--------|---------|-------------| | **BruteForceXForwardedFor** | On/Off | Off | Use X-Forwarded-For for real IP | | **BruteForceWhitelist** | IP list | (empty) | Bypass protection for these IPs | | **BruteForceProtectPath** | path | (none) | Additional paths to protect | ### Actions Explained #### block (Recommended) **What it does:** Immediately returns 403 Forbidden. ```apache BruteForceAction block ``` **Response:** ``` HTTP/1.1 403 Forbidden Content-Type: text/html 403 Forbidden

Access Denied

Too many login attempts. Please try again later.

``` **Use case:** Production sites, maximum security. #### log (Monitoring) **What it does:** Allows request but logs to error.log. ```apache BruteForceAction log ``` **Use case:** Testing, monitoring before enabling blocking. **Check logs:** ```bash grep BruteForce /usr/local/lsws/logs/error.log ``` #### throttle (New in v2.2.0) **What it does:** Applies progressive delays before responding. ```apache BruteForceAction throttle ``` **Throttle levels:** | Over-Limit Attempts | Level | Delay | HTTP Response | |---------------------|-------|-------|---------------| | 1-2 | Soft | 2 seconds | 429 Too Many Requests | | 3-5 | Medium | 5 seconds | 429 Too Many Requests | | 6+ | Hard | 15 seconds | 429 Too Many Requests | **Response includes:** ``` HTTP/1.1 429 Too Many Requests Retry-After: 15 ``` **Use case:** Slows down attackers while allowing legitimate users who forgot password. ### How to Use #### Basic Protection (Small Site) ```apache # Simple protection BruteForceProtection On ``` **Result:** Default 10 attempts per 5 minutes, then block. #### Strict Protection (High Security) ```apache # Only 3 attempts per 15 minutes BruteForceProtection On BruteForceAllowedAttempts 3 BruteForceWindow 900 BruteForceAction block ``` **Result:** Very strict, good for high-value targets. #### Moderate Protection with Throttle (Recommended) ```apache # 5 attempts per 5 minutes, then progressive throttle BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle ``` **Result:** Legitimate users can still login (slowly), attackers waste time. #### Behind Cloudflare/Proxy **Problem:** All requests appear to come from proxy IP. **Solution:** Use X-Forwarded-For to get real client IP. ```apache BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle BruteForceXForwardedFor On ``` **Important:** Only enable if behind trusted proxy (Cloudflare, nginx). #### With IP Whitelist **What it does:** Allows unlimited attempts from trusted IPs. ```apache BruteForceProtection On BruteForceAllowedAttempts 3 BruteForceWindow 900 BruteForceAction block BruteForceWhitelist 203.0.113.50, 192.168.1.0/24, 10.0.0.0/8 ``` **Use case:** Whitelist office IP, admin home IP, VPN range. #### Protect Custom Login Pages ```apache # Protect custom endpoints BruteForceProtection On BruteForceProtectPath /admin/login BruteForceProtectPath /api/auth BruteForceProtectPath /members/signin ``` **Default protected:** `/wp-login.php` and `/xmlrpc.php` ### CyberPanel Integration #### WordPress Security Setup **Step 1:** Navigate to website .htaccess ```bash cd /home/yourdomain.com/public_html nano .htaccess ``` **Step 2:** Add protection ```apache # At top of .htaccess BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle ``` **Step 3:** Save and test ```bash # Try multiple wrong passwords # After 5 attempts, should get throttled ``` **Step 4:** Monitor logs ```bash tail -f /usr/local/lsws/logs/error.log | grep BruteForce ``` #### WooCommerce + WordPress ```apache # Protect both WordPress and WooCommerce login BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction block BruteForceProtectPath /my-account/ BruteForceProtectPath /checkout/ ``` #### Multi-Site WordPress ```apache # Apply to all subsites BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle BruteForceXForwardedFor On ``` ### Shared Memory Storage **Location:** `/dev/shm/ols/` ```bash ls -la /dev/shm/ols/ # BFProt.shm - Stores IP quota data # BFProt.lock - Synchronization lock ``` **Persistence:** Data survives OpenLiteSpeed restarts (stored in tmpfs). **Reset/Clear:** ```bash # Clear all quota data rm -f /dev/shm/ols/BFProt.* /usr/local/lsws/bin/lswsctrl restart ``` **Use case:** Accidentally locked out, need to reset. ### Monitoring and Logs #### View Brute Force Events ```bash grep BruteForce /usr/local/lsws/logs/error.log ``` **Sample log entries:** ``` [INFO] [BruteForce] Initialized: 10 attempts per 300s window, action: throttle [WARN] [BruteForce] Warning: 192.168.1.50 has 2 attempts remaining for /wp-login.php [NOTICE] [BruteForce] Blocked 192.168.1.50 - quota exhausted for /wp-login.php (10 attempts in 300s) [NOTICE] [BruteForce] Throttling 192.168.1.50 (medium level, 5000ms delay) for /wp-login.php ``` #### Real-Time Monitoring ```bash # Watch in real-time tail -f /usr/local/lsws/logs/error.log | grep BruteForce # Count blocked IPs today grep "BruteForce.*Blocked" /usr/local/lsws/logs/error.log | grep "$(date +%Y-%m-%d)" | wc -l ``` #### Check Specific IP ```bash grep "BruteForce.*192.168.1.50" /usr/local/lsws/logs/error.log ``` ### Testing Brute Force Protection #### Manual Test ```bash # Try multiple wrong passwords for i in {1..15}; do curl -X POST https://yourdomain.com/wp-login.php \ -d "log=admin&pwd=wrong$i&wp-submit=Log+In" \ -I | grep "HTTP" sleep 1 done # After BruteForceAllowedAttempts, should see: # HTTP/1.1 403 Forbidden (if action=block) # HTTP/1.1 429 Too Many Requests (if action=throttle) ``` #### Check Logs ```bash grep BruteForce /usr/local/lsws/logs/error.log | tail -20 ``` ### Common Use Cases #### Production WordPress ```apache BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction block ``` #### Behind Cloudflare ```apache BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle BruteForceXForwardedFor On ``` #### Enterprise with Whitelist ```apache BruteForceProtection On BruteForceAllowedAttempts 3 BruteForceWindow 900 BruteForceAction block BruteForceXForwardedFor On BruteForceWhitelist 10.0.0.0/8, 192.168.1.0/24, 203.0.113.100 BruteForceProtectPath /admin/ BruteForceProtectPath /api/login ``` ### Troubleshooting **Problem:** Legitimate users getting blocked **Solution:** ```apache # Increase allowed attempts BruteForceAllowedAttempts 10 # Or use throttle instead of block BruteForceAction throttle # Or whitelist their IP BruteForceWhitelist 203.0.113.50 ``` **Problem:** Protection not working **Solution:** ```bash # Check module loaded ls -la /usr/local/lsws/modules/cyberpanel_ols.so # Check .htaccess syntax cat /home/yourdomain.com/public_html/.htaccess | grep BruteForce # Check logs grep BruteForce /usr/local/lsws/logs/error.log # Restart OpenLiteSpeed /usr/local/lsws/bin/lswsctrl restart ``` **Problem:** Shared memory errors **Solution:** ```bash # Create directory if missing mkdir -p /dev/shm/ols # Set permissions chmod 755 /dev/shm/ols # Restart /usr/local/lsws/bin/lswsctrl restart ``` --- ## CyberPanel Integration ### Accessing Website Files #### Via CyberPanel File Manager 1. Log into **CyberPanel** (https://yourserver:8090) 2. Click **File Manager** 3. Navigate to `/home/yourdomain.com/public_html` 4. Create or edit `.htaccess` 5. Add directives from this guide 6. Click **Save** #### Via SSH ```bash # Log in via SSH ssh root@yourserver # Navigate to website cd /home/yourdomain.com/public_html # Edit .htaccess nano .htaccess # Add directives # Save: Ctrl+X, Y, Enter ``` #### Via FTP (FileZilla) 1. Connect via FTP 2. Navigate to `/home/yourdomain.com/public_html` 3. Download `.htaccess` 4. Edit locally 5. Upload back ### Creating New Website 1. **Create Website** in CyberPanel 2. **Navigate to directory:** ```bash cd /home/newsite.com/public_html ``` 3. **Create .htaccess:** ```bash nano .htaccess ``` 4. **Add base configuration:** ```apache # Security headers Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" # Brute force protection BruteForceProtection On # Cache static assets Header set Cache-Control "max-age=31536000, public" ``` ### WordPress on CyberPanel #### Complete WordPress .htaccess ```apache # Security Headers Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" Header set X-XSS-Protection "1; mode=block" Header unset X-Powered-By # Brute Force Protection BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle # Performance - Cache Static Assets Header set Cache-Control "max-age=31536000, public, immutable" Header set Cache-Control "max-age=2592000, public" # PHP Configuration php_value memory_limit 256M php_value upload_max_filesize 64M php_value post_max_size 64M php_value max_execution_time 300 php_flag display_errors off # WordPress Rewrite Rules (leave as-is) # BEGIN WordPress RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress ``` ### Staging Environment ```apache # Staging site - restrict access Order deny,allow Deny from all Allow from YOUR.OFFICE.IP Allow from YOUR.HOME.IP # No search engine indexing Header set X-Robots-Tag "noindex, nofollow" # Show errors (development) php_flag display_errors on php_value error_reporting 32767 ``` ### Testing After Configuration ```bash # Test headers curl -I https://yourdomain.com | grep -E "X-Frame|Cache-Control|X-Content" # Test specific file curl -I https://yourdomain.com/wp-content/uploads/2024/12/image.jpg | grep Cache # Test PHP settings echo '' > /home/yourdomain.com/public_html/info.php curl https://yourdomain.com/info.php | grep memory_limit # Clean up rm /home/yourdomain.com/public_html/info.php ``` --- ## Real-World Examples ### Example 1: High-Performance WordPress ```apache # Security Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" Header set X-XSS-Protection "1; mode=block" Header set Referrer-Policy "strict-origin-when-cross-origin" Header unset Server Header unset X-Powered-By # Brute Force Protection BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle BruteForceXForwardedFor On # Aggressive Caching Header set Cache-Control "max-age=31536000, public, immutable" Header unset ETag Header set Cache-Control "max-age=31536000, public, immutable" Header set Access-Control-Allow-Origin "*" Header set Cache-Control "max-age=2592000, public" # PHP Optimization php_value memory_limit 256M php_value max_execution_time 300 php_value upload_max_filesize 64M php_value post_max_size 64M php_flag display_errors off php_flag log_errors on ``` ### Example 2: WooCommerce E-commerce ```apache # Security Headers Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" Header set X-XSS-Protection "1; mode=block" # Strict Brute Force Protection BruteForceProtection On BruteForceAllowedAttempts 3 BruteForceWindow 900 BruteForceAction block BruteForceProtectPath /my-account/ BruteForceProtectPath /checkout/ # Product Image Caching Header set Cache-Control "max-age=31536000, public, immutable" # Don't Cache Checkout/Cart Header set Cache-Control "no-cache, no-store, must-revalidate" # PHP for WooCommerce php_value memory_limit 512M php_value max_execution_time 600 php_value max_input_vars 10000 php_value upload_max_filesize 128M php_value post_max_size 128M ``` ### Example 3: API Server ```apache # CORS for API Header set Access-Control-Allow-Origin "*" Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" Header set Access-Control-Allow-Headers "Content-Type, Authorization, X-API-Key" Header set Access-Control-Max-Age "86400" # JSON Response Headers Header set Content-Type "application/json; charset=utf-8" Header set X-Content-Type-Options "nosniff" Header set Cache-Control "no-cache, must-revalidate" # API Rate Limiting BruteForceProtection On BruteForceAllowedAttempts 100 BruteForceWindow 60 BruteForceAction throttle BruteForceProtectPath /api/ # Environment SetEnv API_VERSION v2 SetEnv API_ENVIRONMENT production ``` ### Example 4: Static Site with CDN ```apache # Aggressive Caching ExpiresActive On ExpiresByType image/jpeg A31557600 ExpiresByType image/png A31557600 ExpiresByType image/gif A31557600 ExpiresByType text/css A31557600 ExpiresByType application/javascript A31557600 ExpiresByType text/html A3600 # CORS for CDN Header set Access-Control-Allow-Origin "*" # Security Headers Header set X-Frame-Options "SAMEORIGIN" Header set X-Content-Type-Options "nosniff" Header set Content-Security-Policy "default-src 'self' https://cdn.example.com" # Remove Server Info Header unset Server Header unset X-Powered-By ``` ### Example 5: Multi-Environment Setup **Production (.htaccess):** ```apache SetEnv APPLICATION_ENV production php_flag display_errors off php_flag log_errors on BruteForceProtection On BruteForceAction block Header set X-Robots-Tag "index, follow" ``` **Staging (staging.example.com/.htaccess):** ```apache SetEnv APPLICATION_ENV staging php_flag display_errors on BruteForceProtection On BruteForceAction log Header set X-Robots-Tag "noindex, nofollow" # IP Restriction Order deny,allow Deny from all Allow from 203.0.113.50 ``` **Development (dev.example.com/.htaccess):** ```apache SetEnv APPLICATION_ENV development php_flag display_errors on php_value error_reporting 32767 BruteForceProtection Off Header set X-Robots-Tag "noindex, nofollow" ``` --- ## Troubleshooting ### Common Issues #### 1. Directives Not Working **Symptoms:** Headers not appearing, PHP settings not applied. **Solutions:** ```bash # Check module is installed ls -la /usr/local/lsws/modules/cyberpanel_ols.so # Should show 147KB file # Check module is loaded in config grep cyberpanel_ols /usr/local/lsws/conf/httpd_config.conf # Should show: module cyberpanel_ols { # Restart OpenLiteSpeed /usr/local/lsws/bin/lswsctrl restart # Check logs for errors tail -50 /usr/local/lsws/logs/error.log ``` #### 2. .htaccess File Permissions **Symptoms:** 500 Internal Server Error **Solutions:** ```bash # Set correct permissions chmod 644 /home/yourdomain.com/public_html/.htaccess # Set correct ownership chown nobody:nogroup /home/yourdomain.com/public_html/.htaccess # Verify ls -la /home/yourdomain.com/public_html/.htaccess # Should show: -rw-r--r-- nobody nogroup ``` #### 3. Headers Not Showing **Symptoms:** `curl -I` doesn't show custom headers **Solutions:** ```bash # Clear browser cache # Some headers are cached aggressively # Test with curl (bypasses cache) curl -I https://yourdomain.com # Test specific file curl -I https://yourdomain.com/test.jpg # Check if file exists ls -la /home/yourdomain.com/public_html/test.jpg # Verify .htaccess syntax cat /home/yourdomain.com/public_html/.htaccess ``` #### 4. PHP Directives Not Applied **Symptoms:** `phpinfo()` shows old values **Solutions:** ```bash # Verify using LSPHP (not PHP-FPM) # CyberPanel uses LSPHP by default # Check if directive is allowed # Some directives are PHP_INI_SYSTEM only # Create test file echo '' > /home/yourdomain.com/public_html/info.php # Check value curl https://yourdomain.com/info.php | grep memory_limit # Delete test file rm /home/yourdomain.com/public_html/info.php ``` #### 5. Brute Force Protection Not Triggering **Symptoms:** Can submit unlimited login attempts **Solutions:** ```bash # Check shared memory directory ls -la /dev/shm/ols/ # Should show BFProt.shm and BFProt.lock # Create if missing mkdir -p /dev/shm/ols chmod 755 /dev/shm/ols # Check .htaccess syntax grep BruteForce /home/yourdomain.com/public_html/.htaccess # Must be POST request to protected path curl -X POST https://yourdomain.com/wp-login.php -d "log=test&pwd=test" # Check logs grep BruteForce /usr/local/lsws/logs/error.log # Restart /usr/local/lsws/bin/lswsctrl restart ``` #### 6. Access Control Allowing All **Symptoms:** IP restrictions not working **Solutions:** ```bash # Verify your actual IP curl ifconfig.me # Check CIDR syntax # 192.168.1.0/24 = 192.168.1.1 to 192.168.1.254 # 10.0.0.0/8 = 10.0.0.0 to 10.255.255.255 # Check logs for access decisions grep "cyberpanel_access" /usr/local/lsws/logs/error.log # Test with curl from different IP curl -I https://yourdomain.com # Should get 403 if not allowed ``` #### 7. Redirect Loop **Symptoms:** ERR_TOO_MANY_REDIRECTS **Solutions:** ```bash # Check for conflicting redirects grep Redirect /home/yourdomain.com/public_html/.htaccess # Common mistake: # BAD: Both redirects active # Redirect 301 / https://example.com/ # Redirect 301 / https://www.example.com/ # GOOD: Only one Redirect 301 / https://www.example.com/ # Check WordPress settings # wp-admin > Settings > General # WordPress Address and Site Address must match ``` ### Getting Help #### Enable Debug Logging ```bash # Edit OpenLiteSpeed config nano /usr/local/lsws/conf/httpd_config.conf # Change Log Level to DEBUG # Restart /usr/local/lsws/bin/lswsctrl restart # Monitor logs tail -f /usr/local/lsws/logs/error.log ``` #### Collect Information ```bash # Module version ls -lh /usr/local/lsws/modules/cyberpanel_ols.so # OpenLiteSpeed version /usr/local/lsws/bin/openlitespeed -v # Check .htaccess cat /home/yourdomain.com/public_html/.htaccess # Recent logs tail -100 /usr/local/lsws/logs/error.log # Test headers curl -I https://yourdomain.com ``` #### Report Issue When reporting issues, include: 1. **What you're trying to do** (which feature) 2. **.htaccess content** (sanitized) 3. **Expected behavior** vs **actual behavior** 4. **Error logs** (last 50 lines) 5. **Test results** (curl output) 6. **Module version** and **OpenLiteSpeed version** --- ## Performance Optimization ### Best Practices 1. **Minimize .htaccess size** - Only include necessary directives 2. **Use FilesMatch carefully** - Each pattern adds regex overhead 3. **Prefer block over throttle** - Throttle holds connections longer 4. **Whitelist known IPs** - Skips brute force checks entirely 5. **Set long cache times** - Reduce server load ### Benchmarks | Metric | Value | |--------|-------| | Overhead per request | < 1ms | | Memory per cached .htaccess | ~2KB | | Memory per tracked IP (brute force) | ~64 bytes | | Cache invalidation | mtime-based (instant) | ### Optimization Examples **Before (Slow):** ```apache # Every request checks all patterns Header set X-Custom "Value" Header set X-Another "Value" Header set X-More "Value" Header set Cache-Control "max-age=3600" ``` **After (Fast):** ```apache # Only static assets checked Header set Cache-Control "max-age=31536000, public, immutable" ``` --- ## Appendix ### Quick Reference #### Headers ```apache Header set Name "Value" Header unset Name Header append Name "Value" ``` #### Access Control ```apache Order deny,allow Deny from all Allow from 192.168.1.0/24 ``` #### Redirects ```apache Redirect 301 /old /new RedirectMatch 301 ^/blog/(.*)$ /news/$1 ``` #### PHP ```apache php_value memory_limit 256M php_flag display_errors off ``` #### Brute Force ```apache BruteForceProtection On BruteForceAllowedAttempts 5 BruteForceWindow 300 BruteForceAction throttle ``` ### Common MIME Types ``` image/jpeg, image/png, image/gif, image/webp, image/svg+xml text/css, text/html, text/javascript, text/plain application/javascript, application/json, application/xml, application/pdf font/ttf, font/woff, font/woff2 ``` ### Time Duration Reference ``` 1 minute = 60 5 minutes = 300 15 minutes = 900 1 hour = 3600 1 day = 86400 1 week = 604800 1 month = 2592000 1 year = 31557600 ``` ### IP CIDR Cheat Sheet ``` /32 = 1 IP (255.255.255.255) /24 = 256 IPs (255.255.255.0) /16 = 65,536 IPs (255.255.0.0) /8 = 16,777,216 IPs (255.0.0.0) ``` --- ## Support - **GitHub:** [github.com/usmannasir/cyberpanel_ols](https://github.com/usmannasir/cyberpanel_ols) - **Community:** [community.cyberpanel.net](https://community.cyberpanel.net) --- **Document Version:** 1.0 **Module Version:** 2.2.0 **Last Updated:** December 28, 2025 --- *Thank you for using the CyberPanel OpenLiteSpeed Module!*