Nginx mod_rewrite Module: .htaccess Support for CMS
Nginx does not support Apache's .htaccess, which creates challenges when migrating websites to popular CMS platforms like WordPress, Drupal, or Grav. These systems rely on mod_rewrite for SEO-friendly URLs, directory protection, and error handling. Without .htaccess, CMSs either return 404 errors or require Nginx + Apache setups, adding overhead.
A module called nginx-mod-rewrite has been developed to emulate mod_rewrite. It parses .htaccess on the fly, applying rewrite rules, including internal redirects and fallback to index.php. The module operates at server, location, and .htaccess levels, minimizing file reads through request pool caching.
Solution Approaches in Control Panels
Control panels like HestiaCP address the issue in two ways:
try_files $uri $uri/ index.php?$args— covers 50–80% of cases but not all mod_rewrite rules.- ngx_http_rewrite_module templates — a full .htaccess equivalent for specific CMSs, but tightly bind the config to the platform.
The nginx-mod-rewrite module eliminates these limitations: it supports RewriteMap (minimally), RewriteOptions, requires no templates, and allows editing .htaccess without server admin privileges.
Building and Installing the Module
Building is possible on the host or in Docker. For Almalinux 9:
- Install Docker.
- Clone the repository.
- Run
bash package_preparer.sh prepare "almalinux:9".
The result is RPM packages in tmpbuild/:
tmpbuild/nginx-mod-rewrite-0.1-1.el9.src.rpm
tmpbuild/nginx-mod-rewrite-0.1-1.el9.x86_64.rpm
tmpbuild/nginx-mod-rewrite-debuginfo-0.1-1.el9.x86_64.rpm
tmpbuild/nginx-mod-rewrite-debugsource-0.1-1.el9.x86_64.rpm
Similarly for Debian — DEB packages.
Server Configuration
Example server block for a CMS site:
server {
listen 127.0.0.1:80;
server_name test.my.brp www.test.my.brp;
root /home/test/web/test.my.brp/public_html;
index index.php index.html index.htm;
HtaccessEnable on;
location ~ /\.(?!well-known\/) {
deny all;
return 404;
}
location ~* ^.+\.(jpeg|jpg|png|webp|gif|bmp|ico|svg|css|js|txt)$ {
expires max;
fastcgi_hide_header "Set-Cookie";
}
location / {
RewriteEngine On;
location ~ [^/]\.php(/|$) {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php74-fpm.sock;
}
}
}
HtaccessEnable on activates .htaccess parsing. Static files are excluded from rewrite processing for performance.
Performance Benchmarks
Tests on Drupal (wrk, 30 seconds):
| Scenario | Nginx + php-fpm | Nginx + mod_rewrite | Nginx + Apache + php-fpm |
|---------------------------|-----------------|--------------------|---------------------------|
| / (fallback index.php) | 129.74 req/s | 125.94 req/s | 121.31 req/s |
| /robots.txt (static) | 7384.25 req/s | 4591.31 req/s | 2007.70 req/s |
| /user/login (rewrite) | 126.48 req/s | 128.58 req/s | 117.78 req/s |
The module is close to pure Nginx in speed and outperforms the Apache combination. Static content slows due to .htaccess parsing but is optimized with location exclusions.
Key Points
- The module fully emulates mod_rewrite, including internal redirects and .htaccess caching.
- CMS support without templates: WordPress, Drupal, Grav work with native .htaccess.
- Performance: 90–100% of pure Nginx, without Apache overhead.
- Builds into RPM/DEB for RHEL/Debian, with Docker support.
- Limitations: minimal RewriteMap, simplified RewriteOptions (sufficient for CMS).
— Editorial Team
No comments yet.