Case-insensitive Nginx
by Kuligaposten December 12 2024
Here’s the complete NGINX server block configuration to make the filenames case-insensitive. This example uses the Lua module for NGINX to convert the requested URI to lowercase. You need to have the Lua module installed in your NGINX setup for this solution.
Here’s the complete NGINX server block configuration to make the filenames case-insensitive. This example uses the Lua module for NGINX to convert the requested URI to lowercase. You need to have the Lua module installed in your NGINX setup for this solution.
server {
listen 80;
server_name example.com; # Replace with your domain
# Replace with your actual document root
root /path/to/your/document/root;
index index.html;
# Rule: Redirect requests for any `.html` file
# to the same URL without `.html`
rewrite ^/(.*)\.html$ /$1 permanent;
# Lua module for case-insensitive file handling
location / {
# Set the requested URI to lowercase
set_by_lua_block $lower_uri {
return ngx.var.uri:lower()
}
# Try to serve the file with the lowercase URI
try_files $lower_uri $lower_uri.html $uri $uri.html $uri/ =404;
}
# Error handling
error_page 404 /404.html;
# Optional logging
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
Explanation of the Configuration:
rootDirective: Specifies the root directory for your website files.Case Conversion:
- The
set_by_lua_blockdirective converts the requested URI to lowercase using the Lua module. $lower_uriholds the lowercase version of the URI.
- The
try_filesDirective:- Attempts to locate files based on the converted lowercase URI.
- Tries these paths in order:
$lower_uri(lowercase version of the URI)$lower_uri.html(lowercase URI with.htmlextension)$uri(original case-sensitive URI)$uri.html(original case-sensitive URI with.html)$uri/(directory path)
- Returns a
404if none of the above exist.
rewriteRule: Redirects URLs with.htmlto their equivalents without the.htmlextension for cleaner URLs.Error Pages: Specifies a custom 404 error page.
Logging: Enables access and error logs for debugging.
Prerequisite:
You need the ngx_http_lua_module for this configuration. If it’s not installed, you can either install OpenResty (which includes Lua support) or recompile NGINX with the Lua module.
To check if your NGINX installation has the Lua module enabled, you can follow these steps:
1. Check the NGINX Version and Modules
Run the following command in your terminal:
nginx -V
This will output a lot of information, including the compile-time options and modules. Look for the following modules in the output:
--add-module=/path/to/lua-nginx-module--add-dynamic-module=/path/to/lua-nginx-module
If you see the Lua module included, then your NGINX installation supports Lua.
2. Check if Lua is Installed
If the module is included, you can verify Lua itself by checking its version:
lua -v
If Lua is installed, this will show the version, like:
Lua 5.1.5
If Lua is not installed, you'll need to install it (see the instructions below).
3. Test Lua in NGINX
You can also test if Lua works in NGINX by creating a simple Lua block in your NGINX configuration:
Add the Following to Your nginx.conf:
server {
listen 8080;
server_name localhost;
location /lua_test {
content_by_lua_block {
ngx.say("Lua is working!")
}
}
}
Reload NGINX:
sudo nginx -s reload
Test in Your Browser or Curl:
Visit http://localhost:8080/lua_test or run:
curl http://localhost:8080/lua_test
If Lua is enabled, you'll see:
Lua is working!
4. Install Lua (If Not Installed)
If Lua is not installed, you can install it along with the NGINX Lua module:
Using OpenResty:
The easiest way to get Lua with NGINX is to install OpenResty, a distribution of NGINX that includes Lua out of the box.
sudo apt-get update
sudo apt-get install -y openresty
sudo systemctl start openresty
sudo systemctl enable openresty
Install Lua with Dynamic Module Support:
Alternatively, you can install Lua and compile NGINX with the Lua module:
sudo apt-get install lua5.1 liblua5.1-0-dev
sudo apt-get install luarocks # For Lua package management
Then recompile NGINX with the Lua module.
If you cannot use Lua
If you cannot use Lua, the alternative is to use a combination of try_files and an application-level handler, such as PHP or a custom script, to resolve case-insensitivity. Here's an example configuration that uses PHP to handle case-insensitivity:
NGINX Configuration (Without Lua)
server {
listen 80;
server_name example.com;
root /path/to/your/document/root;
index index.php index.html;
# Redirect URLs with `.html` to clean URLs
rewrite ^/(.*)\.html$ /$1 permanent;
# Try to serve the file directly; if not found, pass to PHP for case-insensitive lookup
location / {
try_files $uri $uri/ /case_insensitive_handler.php;
}
# PHP configuration
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php7.4-fpm.sock; # Adjust as per your PHP-FPM setup
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Error handling
error_page 404 /404.html;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
case_insensitive_handler.php
This PHP script will handle case-insensitive file lookups:
<?php
// Get the requested URI
$uri = $_SERVER['REQUEST_URI'];
// Remove query parameters
$path = parse_url($uri, PHP_URL_PATH);
// Normalize the path to lowercase
$lowercasePath = strtolower($path);
// Get the document root
$documentRoot = $_SERVER['DOCUMENT_ROOT'];
// Attempt to find the file in a case-insensitive manner
$realPath = null;
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($documentRoot)) as $file) {
if (strtolower($file->getFilename()) === ltrim($lowercasePath, '/')) {
$realPath = $file->getRealPath();
break;
}
}
// Serve the file if found
if ($realPath && file_exists($realPath)) {
header("Content-Type: " . mime_content_type($realPath));
readfile($realPath);
exit;
}
// Return a 404 error if the file doesn't exist
http_response_code(404);
include '404.html';
exit;
?>
Explanation
try_filesin NGINX:- NGINX first tries to serve the requested file directly.
- If the file isn't found, it passes the request to
case_insensitive_handler.php.
case_insensitive_handler.php:- Converts the requested path to lowercase.
- Iterates over the document root to find a matching file in a case-insensitive manner.
- Serves the file if found.
- Returns a 404 error if the file doesn’t exist.
Error Handling:
- Includes a
404.htmlpage for graceful error messages.
- Includes a
PHP-FPM:
- The
fastcgi_passdirective connects NGINX to PHP-FPM to process the PHP script.
- The
Notes:
- This approach offloads case-insensitivity logic to PHP, which is less efficient than NGINX handling it directly but works reliably.
- Ensure that the
case_insensitive_handler.phpscript is properly secured and doesn't allow access to unauthorized files. - The PHP script iterates through the entire document root, which might impact performance on large file systems. Consider optimizing it by narrowing the search to relevant directories.