2026-03-23 01:15:59 +03:00
## Apache mod_rewrite Compatibility Module for Nginx
This module provides Apache's `mod_rewrite` compatibility for Nginx, enabling `.htaccess` file support and standard rewrite rules.
---
# Configuration Directives
The following directives are available in this module:
### 1. RewriteEngine
**Purpose:** Enable or disable the rewrite engine.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `main` , `server` , `location` | ✓ All three levels supported |
**Syntax:**
```nginx
RewriteEngine on|off
```
**Possible Values:**
- `on` - Enable rewrite engine
- `off` - Disable rewrite engine (default)
**Example in nginx.conf:**
```nginx
http {
server {
RewriteEngine on;
location /blog/ {
# Rules apply here
}
location /static/ {
RewriteEngine off; # Disable for this location
}
}
}
```
---
### 2. RewriteRule
**Purpose:** Define a rewrite rule that matches a URL pattern and substitutes it with a new value.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `server` , `location` | ✓ Server and Location level |
| `.htaccess` | ✓ Supported in .htaccess files |
**Syntax:**
```nginx
RewriteRule pattern substitution [flags]
```
**Parameters:**
- **pattern** - Regular expression to match the URL (supports backreferences $1, $2, etc.)
- Pattern can be prefixed with `!` for negation
- `-` as substitution means "no substitution" (only match for conditions)
- **substitution** - Target URL or file path to rewrite to
- Can be a relative path (`/new/path` ) or absolute redirect (`http://example.com/new` )
**Flags:** `[flag1,flag2,...]` (optional):
| Flag | Abbreviation | Description |
|------|--------------|-------------|
| `B` | - | Escape backreferences in output (prevent URL encoding issues) |
| `C` | Chain | Chain this rule with the next one (requires previous match) |
| `D` | DPI | Discard path info after substitution |
| `E` | Env=var:val | Set an environment variable for later use (FastCGI integration) |
| `F` | Forbidden | Return HTTP 403 Forbidden status |
| `G` | Gone | Return HTTP 410 Gone status |
| `L` | Last | Stop processing rules after this one |
| `N` | Next=limit | Loop (retry) up to N times for infinite rewriting prevention |
| `P` | Proxy | Proxy the request internally (Phase 2) |
| `Q` | QSA | Append original query string to substitution URL |
| `Q` | QSD | Discard original query string |
| `Q` | QSL | Set "query string last" marker |
| `R` | Redirect=code| Perform external redirect with status code (301, 302, 307) or: Permanent, Temp, SeeOther |
| `S` | Skip=N | Skip N subsequent rules after this one |
| `T` | Type=mime | Force specific MIME type for the response |
| `NC` | - | Case-insensitive matching |
| `NOESCAPE` | - | Do not escape special characters in output |
| `END` | - | Stop all rewriting and pass to content phase |
**Example:**
```nginx
# Redirect /old-path/ to /new-path/ (permanent redirect)
RewriteRule ^old-path/(.*)$ /new-path/$1 [R=301,L]
# Condition-based rewrite (chain)
2026-03-23 15:11:12 +03:00
RewriteCond %{REQUEST_URI} !^/admin/
2026-03-23 01:15:59 +03:00
RewriteRule ^admin/(.*)$ /login.php?user=$1 [NC,E,END]
# In .htaccess:
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [OR]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
```
---
### 3. RewriteCond
**Purpose:** Define conditions that must be met before a `RewriteRule` is applied. Multiple conditions are ANDed together; OR flag can change this behavior.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `server` , `location` | ✓ Server and Location level |
| `.htaccess` | ✓ Supported in .htaccess files |
**Syntax:**
```nginx
RewriteCond input_string pattern [flags]
```
**Parameters:**
- **input_string** - Variable or string to test (e.g., `%REQUEST_URI` , `%HTTP_HOST` , `%REQUEST_FILENAME` )
- Common variables: `REQUEST_URI` , `HTTP_HOST` , `REQUEST_METHOD` , `REQUEST_FILENAME`
- **pattern** - Test pattern for the condition:
- **File tests:** `-f` (file exists), `-d` (directory exists), `-x` (executable), `-s` (non-zero size)
- **Link tests:** `-h` or `-l` (hard/soft link), `-L` (link target exists)
- **Integer comparisons:** `-lt` , `-le` , `-eq` , `-gt` , `-ge` , `-ne`
- **String comparisons:** `=` , `>` , `<` , `>=` , `<=`
- **Regular expressions:** Any regex pattern
- **flags** (optional):
- `NC` - Case-insensitive matching
- `OR` / `ornext` - OR logic between conditions (instead of AND)
**Examples:**
```nginx
# Condition: file exists
2026-03-23 15:11:12 +03:00
RewriteCond %{REQUEST_FILENAME} -f
2026-03-23 01:15:59 +03:00
# Condition: not a directory
2026-03-23 15:11:12 +03:00
RewriteCond %{REQUEST_FILENAME} !-d
2026-03-23 01:15:59 +03:00
# Condition: string comparison
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
# Multiple conditions with OR logic
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [OR]
RewriteCond %{HTTPS} off
# Regular expression pattern
RewriteCond %{REQUEST_URI} ^/old/(.*)$
```
---
### 4. RewriteBase
**Purpose:** Set the base URL path for relative substitutions in rewrite rules.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `location` | ✓ Location level only |
| `.htaccess` | ✓ Supported in .htaccess files |
**Syntax:**
```nginx
RewriteBase /path/
```
**Parameters:**
- Must start with `/` and end with `/` (trailing slash required)
**Example:**
```nginx
# Inside a specific location
location /blog/ {
RewriteBase /blog/
# Relative substitution resolves to: /blog/news.html
RewriteRule ^news\.html$ news.php [L]
}
# In .htaccess:
RewriteEngine on
RewriteBase /subdir/
RewriteRule ^index\.html$ home.php [L]
```
---
### 5. RewriteOptions
**Purpose:** Configure rewrite behavior options that affect rule inheritance and processing order.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `main` , `server` , `location` | ✓ All three levels supported |
**Syntax:**
```nginx
RewriteOptions option1 [option2 ...]
```
**Possible Options:**
| Option | Description |
|-----------------|-------------|
| `Inherit` | Inherit rules from parent locations/servers (default behavior) |
| `InheritBefore` | Process parent rules before child rules |
**Example:**
```nginx
http {
server {
RewriteOptions Inherit
location /parent/ {
RewriteRule ^parent/(.*)$ /new/$1 [L]
}
location /child/ {
# Inherits rules from parent by default with 'Inherit' option
RewriteBase /child/
}
}
}
```
---
### 6. RewriteMap
**Purpose:** Define name-value mappings for lookup tables in rewrite expressions.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `server` | ✓ Server level only |
| `.htaccess` | ✗ Not supported in .htaccess |
**Syntax:**
```nginx
RewriteMap name type:source
```
**Parameters:**
- **name** - Map identifier (used as variable like `%MAPNAME:value` )
- **type** - Type of map:
- `int` - Internal function (supported: `tolower` , `toupper` , `escape` , `unescape` )
- `txt` - Text file lookup (not supported yet)
- `rnd` - Random lookup (not supported yet)
- `prg` - Program lookup (not supported yet)
**Example:**
```nginx
server {
# Map to lowercase version of hostname
RewriteMap lc int:tolower
server_name example.com;
location / {
# Use mapped value in rule
RewriteRule ^lc/([^/]+)$ /redirect/$1 [L]
}
}
# Usage in rules:
RewriteRule ^(.*)$ /%lc:$1 [L]
```
---
### 7. HtaccessEnable
**Purpose:** Enable or disable `.htaccess` file parsing for the server/location.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `main` , `server` | ✓ Main and Server level only |
| `.htaccess` | ✗ Not supported in .htaccess |
**Syntax:**
```nginx
HtaccessEnable on|off
```
**Parameters:**
- `on` - Enable `.htaccess` parsing
- `off` - Disable `.htaccess` parsing (default)
**Example:**
```nginx
http {
server {
HtaccessEnable on
# .htaccess files will be searched upward from the request path
location /subdir/ {
root /var/www/html;
}
}
}
# In nginx.conf, you can also enable at http level:
http {
HtaccessEnable on;
server {
# Inherits setting from http level
}
}
```
---
### 8. HtaccessName
**Purpose:** Specify an alternative filename for `.htaccess` files.
| Context | Available Levels |
|----------------|---------------------------------------------|
| `main` , `server` | ✓ Main and Server level only |
| `.htaccess` | ✗ Not supported in .htaccess |
**Syntax:**
```nginx
HtaccessName filename
```
**Parameters:**
- Any string (default is `.htaccess` )
**Example:**
```nginx
server {
HtaccessName .webconfig
# Will look for .webconfig files instead of .htaccess
location / {
root /var/www/html;
}
}
# In .htaccess:
HtaccessEnable on
HtaccessName .custom_htac
```
---
### 9. RewriteFallBack
**Purpose:** Specify an alternative fallback path when the rewritten file doesn't exist (instead of default `/index.php` ). This directive can only be used in `.htaccess` files and is read by `ngx_htaccess_parse_file_from_ha()` . The fallback path is cached per request and retrieved in `ngx_http_apache_rewrite_url_register_hook_with_fallback()` .
| Context | Available Levels |
|----------------|---------------------------------------------|
| `.htaccess` | ✓ Supported only in .htaccess files |
**Syntax:**
```apache
RewriteFallBack /path/to/fallback.php
```
**Parameters:**
- Path must start with `/` (required)
- Default fallback is `/index.php` if not specified
**Example in .htaccess:**
```apache
# Use custom fallback when file not found
RewriteFallBack /custom/app.php
# Fallback will redirect to /custom/app.php?query_string instead of /index.php
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
```
**Example with query string:**
```apache
RewriteFallBack /handler.php?lang=ru
# When file doesn't exist, request is redirected to the fallback path
# preserving the original query string if present
```
---
## Configuration Levels Summary
| Directive | http/main | server | location | .htaccess |
|-----------------|-----------|--------|----------|-----------|
| RewriteEngine | ✓ | ✓ | ✓ | ✓ |
| RewriteRule | - | ✓ | ✓ | ✓ |
| RewriteCond | - | ✓ | ✓ | ✓ |
| RewriteBase | - | - | ✓ | ✓ |
| RewriteOptions | ✓ | ✓ | ✓ | - |
| RewriteMap | - | ✓ | - | - |
| HtaccessEnable | ✓ | ✓ | - | - |
| HtaccessName | ✓ | ✓ | - | - |
| RewriteFallBack | ✗ | ✗ | - | ✓ |
---
## .htaccess File Format
`.htaccess` files follow the Apache format:
```apache
# Comments start with #
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/old/(.*)$
RewriteRule ^old/(.*)$ /new/$1 [R=301,L]
# Multiple conditions (AND logic by default)
RewriteCond %{HTTP_HOST} www\.example\.com$
RewriteCond %{HTTPS} off
RewriteRule (.*) https://www.example.com/$1 [R=301,L]
RewriteBase /subdir/
RewriteFallBack /custom/fallback.php
RewriteCond !-f
RewriteCond !-d
RewriteRule ^(.*)$ index.php?route=$1 [QSA,L]
```
When a file doesn't exist after URL rewriting, the module falls back to:
1. `RewriteFallBack` path if specified in `.htaccess` , or
2. `/index.php` as default fallback
---
## Module Features
### FastCGI Integration
The module automatically passes environment variables (set via `[E=VAR:VAL]` flags) to FastCGI applications without manual configuration.
### Environment Variables
Environment variables persist across request phases and are available for downstream modules.
### .htaccess Caching
`.htaccess` files are cached by modification time in the request pool to improve performance on repeated requests. The `RewriteFallBack` directive is also stored in the cache entry and retrieved when needed.
### RewriteFallBack Directive
The `RewriteFallBack` directive allows customizing the fallback path used when a rewritten file doesn't exist:
1. **Caching: ** The fallback path from `.htaccess` is cached per request to avoid repeated parsing
2. **Fallback Logic: ** When `try_files` fails, the module redirects to the configured fallback instead of `/index.php`
3. **Query String Preservation: ** Original query string is preserved and appended to fallback path
---
## Notes
- Rewrite rules are processed in order as defined in configuration or `.htaccess` files
- The `[L]` flag stops processing at the current rule
- The `[N]` flag enables looping for infinite redirects prevention (max 10,000 rounds)
- Location-level rules override server-level rules unless `Inherit` option is set