mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-01-14 03:22:04 +01:00
- Added new model `CatchAllEmail` to store catch-all email configurations per domain. - Implemented views for fetching, saving, and deleting catch-all email configurations, enhancing email management capabilities. - Updated URL routing to include endpoints for catch-all email operations. - Enhanced error handling and permission checks for email forwarding actions. These changes improve the flexibility and user experience of email management within CyberPanel.
2792 lines
60 KiB
Markdown
2792 lines
60 KiB
Markdown
# 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
|
|
<?php
|
|
// Detect HTTPS
|
|
$proto = $_SERVER['HTTP_X_FORWARDED_PROTO'] ?? 'http';
|
|
$isHttps = ($proto === 'https');
|
|
|
|
// Get real IP
|
|
$realIp = $_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'];
|
|
|
|
// Force HTTPS redirect
|
|
if (!$isHttps && $_SERVER['REQUEST_METHOD'] !== 'OPTIONS') {
|
|
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
|
|
exit;
|
|
}
|
|
?>
|
|
```
|
|
|
|
#### 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
|
|
<?php
|
|
$env = $_SERVER['HTTP_X_ENVIRONMENT'] ?? 'development';
|
|
$location = $_SERVER['HTTP_X_SERVER_LOCATION'] ?? 'unknown';
|
|
|
|
if ($env === 'production') {
|
|
ini_set('display_errors', 0);
|
|
error_reporting(E_ALL & ~E_DEPRECATED);
|
|
}
|
|
?>
|
|
```
|
|
|
|
#### 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
|
|
<?php
|
|
$apiVersion = $_SERVER['HTTP_X_API_VERSION'] ?? 'v1';
|
|
$features = explode(',', $_SERVER['HTTP_X_FEATURE_FLAGS'] ?? '');
|
|
$clientType = $_SERVER['HTTP_X_CLIENT_TYPE'] ?? 'unknown';
|
|
|
|
if (in_array('beta-features', $features)) {
|
|
// Enable beta features
|
|
}
|
|
?>
|
|
```
|
|
|
|
### 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
|
|
<?php
|
|
$env = $_SERVER['APPLICATION_ENV'] ?? 'development';
|
|
$dbHost = $_SERVER['DB_HOST'] ?? 'localhost';
|
|
$apiEndpoint = $_SERVER['API_ENDPOINT'] ?? '';
|
|
$newUiEnabled = ($_SERVER['FEATURE_FLAG_NEW_UI'] ?? 'off') === 'enabled';
|
|
|
|
if ($newUiEnabled) {
|
|
require 'templates/new-ui.php';
|
|
} else {
|
|
require 'templates/old-ui.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
|
|
<?php
|
|
if (!empty($_SERVER['IS_API_REQUEST'])) {
|
|
header('Content-Type: application/json');
|
|
$output = json_encode($data);
|
|
} else {
|
|
header('Content-Type: text/html');
|
|
$output = render_html($data);
|
|
}
|
|
|
|
if (!empty($_SERVER['IS_BETA_SITE'])) {
|
|
// Enable experimental features
|
|
define('BETA_FEATURES', true);
|
|
}
|
|
?>
|
|
```
|
|
|
|
#### 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
|
|
<?php
|
|
if (!empty($_SERVER['IS_MOBILE'])) {
|
|
require 'mobile-layout.php';
|
|
} else {
|
|
require 'desktop-layout.php';
|
|
}
|
|
|
|
if (!empty($_SERVER['IS_BOT'])) {
|
|
// Serve cached version to bots
|
|
serve_cached_page();
|
|
exit;
|
|
}
|
|
|
|
if (!empty($_SERVER['IS_IE'])) {
|
|
echo '<div class="browser-warning">Please use a modern browser</div>';
|
|
}
|
|
?>
|
|
```
|
|
|
|
### 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
|
|
<?php
|
|
// Use environment variables
|
|
define('WP_ENV', $_SERVER['APPLICATION_ENV'] ?? 'production');
|
|
define('WP_DEBUG', ($_SERVER['DEBUG_MODE'] ?? 'off') === 'on');
|
|
|
|
if (WP_DEBUG) {
|
|
define('WP_DEBUG_LOG', true);
|
|
define('WP_DEBUG_DISPLAY', true);
|
|
}
|
|
?>
|
|
```
|
|
|
|
### 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
|
|
<?php
|
|
if (!empty($_SERVER['IS_MOBILE']) && strpos($_SERVER['HTTP_HOST'], 'm.') !== 0) {
|
|
header('Location: https://m.example.com' . $_SERVER['REQUEST_URI']);
|
|
exit;
|
|
}
|
|
?>
|
|
```
|
|
|
|
#### 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
|
|
<?php
|
|
if (!empty($_SERVER['IS_API'])) {
|
|
// Apply API rate limiting
|
|
check_api_rate_limit($_SERVER['REMOTE_ADDR']);
|
|
}
|
|
?>
|
|
```
|
|
|
|
---
|
|
|
|
## 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
|
|
<?php
|
|
if ($_SERVER['REQUEST_SCHEME'] !== 'https') {
|
|
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], true, 301);
|
|
exit;
|
|
}
|
|
?>
|
|
```
|
|
|
|
#### 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 <code> <document>
|
|
```
|
|
|
|
### 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
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Page Not Found</title>
|
|
<style>
|
|
body { font-family: Arial; text-align: center; padding: 50px; }
|
|
h1 { color: #e74c3c; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>404 - Page Not Found</h1>
|
|
<p>The page you're looking for doesn't exist.</p>
|
|
<a href="/">Go to Homepage</a>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
**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
|
|
<?php
|
|
// Custom 404 page design
|
|
get_header();
|
|
?>
|
|
<h1>Page Not Found</h1>
|
|
<p>Sorry, this page doesn't exist.</p>
|
|
<?php
|
|
get_footer();
|
|
?>
|
|
```
|
|
|
|
### 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
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Maintenance</title>
|
|
<meta http-equiv="refresh" content="30">
|
|
<style>
|
|
body { font-family: Arial; text-align: center; padding: 100px; }
|
|
h1 { color: #3498db; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>We'll be right back!</h1>
|
|
<p>Our site is undergoing maintenance.</p>
|
|
<p>Expected completion: 2 hours</p>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
**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
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Page Not Found</title>
|
|
</head>
|
|
<body>
|
|
<h1>404 - Page Not Found</h1>
|
|
<p>Try searching:</p>
|
|
<form action="/search" method="get">
|
|
<input type="text" name="q" placeholder="Search...">
|
|
<button>Search</button>
|
|
</form>
|
|
<p><a href="/">Return to Homepage</a></p>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
#### 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
|
|
<FilesMatch "regex">
|
|
# Directives here apply only to matching files
|
|
Header set Name "Value"
|
|
</FilesMatch>
|
|
```
|
|
|
|
### 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
|
|
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
Header unset ETag
|
|
Header unset Last-Modified
|
|
</FilesMatch>
|
|
|
|
# Fonts - Cache for 1 year
|
|
<FilesMatch "\.(woff2?|ttf|eot|otf)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
Header set Access-Control-Allow-Origin "*"
|
|
</FilesMatch>
|
|
|
|
# CSS/JS - Cache for 1 week (you update these more often)
|
|
<FilesMatch "\.(css|js)$">
|
|
Header set Cache-Control "max-age=604800, public"
|
|
</FilesMatch>
|
|
```
|
|
|
|
**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
|
|
<FilesMatch "\.(html|htm|php)$">
|
|
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"
|
|
</FilesMatch>
|
|
```
|
|
|
|
#### Prevent Caching of Dynamic Content
|
|
|
|
**What it does:** Ensures dynamic pages are never cached.
|
|
|
|
```apache
|
|
<FilesMatch "\.(html|php|json|xml)$">
|
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
|
Header set Pragma "no-cache"
|
|
Header set Expires "0"
|
|
</FilesMatch>
|
|
```
|
|
|
|
#### CORS for Fonts (Fix Font Loading)
|
|
|
|
**What it does:** Allows fonts to load from CDN or different domain.
|
|
|
|
```apache
|
|
<FilesMatch "\.(woff2?|ttf|eot|otf)$">
|
|
Header set Access-Control-Allow-Origin "*"
|
|
</FilesMatch>
|
|
```
|
|
|
|
**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
|
|
<FilesMatch "\.(pdf|zip|tar|gz|doc|docx|xls|xlsx)$">
|
|
Header set Content-Disposition "attachment"
|
|
Header set X-Content-Type-Options "nosniff"
|
|
</FilesMatch>
|
|
```
|
|
|
|
### CyberPanel Integration
|
|
|
|
#### WordPress Performance Optimization
|
|
|
|
```apache
|
|
# In /home/yourdomain.com/public_html/.htaccess
|
|
|
|
# Cache WordPress static assets
|
|
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
</FilesMatch>
|
|
|
|
# Cache CSS/JS (with version strings in WordPress)
|
|
<FilesMatch "\.(css|js)$">
|
|
Header set Cache-Control "max-age=2592000, public"
|
|
</FilesMatch>
|
|
|
|
# Don't cache WordPress admin
|
|
<FilesMatch "(wp-login|wp-admin|wp-cron)\.php$">
|
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
|
</FilesMatch>
|
|
```
|
|
|
|
**Result:** PageSpeed score +20-30 points
|
|
|
|
#### WooCommerce Security
|
|
|
|
```apache
|
|
# Protect sensitive files
|
|
<FilesMatch "(\.log|\.sql|\.md|readme\.txt|license\.txt)$">
|
|
Order deny,allow
|
|
Deny from all
|
|
</FilesMatch>
|
|
|
|
# JSON API security
|
|
<FilesMatch "\.json$">
|
|
Header set X-Content-Type-Options "nosniff"
|
|
Header set Content-Type "application/json; charset=utf-8"
|
|
</FilesMatch>
|
|
```
|
|
|
|
### Common Use Cases
|
|
|
|
#### Complete Caching Strategy
|
|
|
|
```apache
|
|
# Aggressive caching for static assets (1 year)
|
|
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico|woff2?|ttf|eot|otf)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
Header unset ETag
|
|
</FilesMatch>
|
|
|
|
# Moderate caching for CSS/JS (1 month)
|
|
<FilesMatch "\.(css|js)$">
|
|
Header set Cache-Control "max-age=2592000, public"
|
|
</FilesMatch>
|
|
|
|
# Short caching for HTML (1 hour)
|
|
<FilesMatch "\.html$">
|
|
Header set Cache-Control "max-age=3600, public"
|
|
</FilesMatch>
|
|
|
|
# No caching for dynamic content
|
|
<FilesMatch "\.(php|json)$">
|
|
Header set Cache-Control "no-cache, must-revalidate"
|
|
</FilesMatch>
|
|
```
|
|
|
|
#### Media Library Protection
|
|
|
|
```apache
|
|
# Prevent hotlinking (bandwidth theft)
|
|
<FilesMatch "\.(jpg|jpeg|png|gif)$">
|
|
SetEnvIf Referer "^https://yourdomain\.com" local_ref
|
|
SetEnvIf Referer "^$" local_ref
|
|
Order deny,allow
|
|
Deny from all
|
|
Allow from env=local_ref
|
|
</FilesMatch>
|
|
```
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
<FilesMatch "\.(jpg|png|gif)$">
|
|
ExpiresByType image/jpeg A31557600
|
|
Header set Cache-Control "public, immutable"
|
|
Header unset ETag
|
|
</FilesMatch>
|
|
```
|
|
|
|
---
|
|
|
|
## 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
|
|
<?php
|
|
echo 'Memory Limit: ' . ini_get('memory_limit') . "\n";
|
|
echo 'Max Execution Time: ' . ini_get('max_execution_time') . "\n";
|
|
?>
|
|
```
|
|
|
|
#### 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
|
|
<?php
|
|
phpinfo();
|
|
// Search for upload_max_filesize and post_max_size
|
|
?>
|
|
```
|
|
|
|
#### 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
|
|
<?php
|
|
echo date_default_timezone_get();
|
|
?>
|
|
```
|
|
|
|
### 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
|
|
|
|
<html>
|
|
<head><title>403 Forbidden</title></head>
|
|
<body>
|
|
<h1>Access Denied</h1>
|
|
<p>Too many login attempts. Please try again later.</p>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
**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
|
|
<FilesMatch "\.(jpg|png|gif|css|js)$">
|
|
Header set Cache-Control "max-age=31536000, public"
|
|
</FilesMatch>
|
|
```
|
|
|
|
### 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
|
|
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
</FilesMatch>
|
|
|
|
<FilesMatch "\.(css|js)$">
|
|
Header set Cache-Control "max-age=2592000, public"
|
|
</FilesMatch>
|
|
|
|
# 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
|
|
<IfModule mod_rewrite.c>
|
|
RewriteEngine On
|
|
RewriteBase /
|
|
RewriteRule ^index\.php$ - [L]
|
|
RewriteCond %{REQUEST_FILENAME} !-f
|
|
RewriteCond %{REQUEST_FILENAME} !-d
|
|
RewriteRule . /index.php [L]
|
|
</IfModule>
|
|
# 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 '<?php phpinfo(); ?>' > /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
|
|
<FilesMatch "\.(jpg|jpeg|png|gif|webp|svg|ico)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
Header unset ETag
|
|
</FilesMatch>
|
|
|
|
<FilesMatch "\.(woff2?|ttf|eot)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
Header set Access-Control-Allow-Origin "*"
|
|
</FilesMatch>
|
|
|
|
<FilesMatch "\.(css|js)$">
|
|
Header set Cache-Control "max-age=2592000, public"
|
|
</FilesMatch>
|
|
|
|
# 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
|
|
<FilesMatch "\.(jpg|jpeg|png|webp)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
</FilesMatch>
|
|
|
|
# Don't Cache Checkout/Cart
|
|
<FilesMatch "(cart|checkout|my-account)">
|
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
|
</FilesMatch>
|
|
|
|
# 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
|
|
<FilesMatch "\.json$">
|
|
Header set Content-Type "application/json; charset=utf-8"
|
|
Header set X-Content-Type-Options "nosniff"
|
|
Header set Cache-Control "no-cache, must-revalidate"
|
|
</FilesMatch>
|
|
|
|
# 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 '<?php phpinfo(); ?>' > /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"
|
|
|
|
<FilesMatch ".*">
|
|
Header set Cache-Control "max-age=3600"
|
|
</FilesMatch>
|
|
```
|
|
|
|
**After (Fast):**
|
|
```apache
|
|
# Only static assets checked
|
|
<FilesMatch "\.(jpg|png|css|js)$">
|
|
Header set Cache-Control "max-age=31536000, public, immutable"
|
|
</FilesMatch>
|
|
```
|
|
|
|
---
|
|
|
|
## 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!*
|