After examining dozens of production Nginx configurations and community examples, I've noticed significant inconsistency in quoting practices. The core issue stems from how Nginx's parser handles special characters versus plain text.
1. Special characters in values:
add_header X-Frame-Options "SAMEORIGIN";
The quotes ensure the semicolon isn't interpreted as a statement terminator.
2. Spaces in directive names or values:
map $http_user_agent $is_mobile {
default 0;
"~*android|iphone" 1;
}
For simple alphanumeric strings without special characters:
add_header Cache-Control no-cache;
Works identically to:
add_header Cache-Control "no-cache";
The wildcard character (*) demonstrates an interesting edge case:
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Origin '*';
Both work because Nginx treats * as a literal when unquoted in this context.
Based on the Nginx source code analysis:
- Always quote regular expressions
- Quote values containing { } [ ] ( ) | * & ~ ! =
- Consider quoting as defensive programming
- Be consistent within each config file
Properly quoted complex directive:
location ~* "\.(jpg|jpeg|png|gif|ico|css|js)$" {
expires 30d;
add_header Pragma public;
}
Minimal quoting for readability:
server {
listen 80;
server_name example.com;
root /var/www/html;
}
After examining hundreds of Nginx configuration files across open-source projects, I've noticed significant inconsistency in quote usage. The core question isn't whether quotes work, but when they're required by Nginx's parsing rules.
Nginx's configuration parser follows these fundamental rules:
- Tokens without spaces/special characters don't require quotes
- Values containing spaces, semicolons, or curly braces must be quoted
Here are cases where quotes are mandatory:
# Special characters require quotes
add_header X-Custom-Header "value;with;semicolons";
# Spaces in values
set $my_var "string with spaces";
# Complex regex patterns
location ~* "\\.(jpg|jpeg|png)$" { ... }
Cases where quotes are optional but commonly used:
# Both work identically
add_header Cache-Control "public";
add_header Cache-Control public;
# Star (*) character works both ways
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Origin '*';
The wildcard character (*) in headers like CORS demonstrates an interesting edge case. While both quoted and unquoted versions work:
# Functionally equivalent
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Origin '*';
I recommend quoting asterisks in production configurations because:
- Improves consistency with other quoted values
- Prevents potential misinterpretation by reverse proxies
- Makes the config more maintainable for teams
Based on managing large-scale Nginx deployments, here's my quote strategy:
# Always quote:
# 1. Paths with spaces
root "/var/www/my site";
# 2. Regex patterns
location ~* "\.(js|css)$" { ... }
# 3. Headers with multiple values
add_header Content-Security-Policy "default-src 'self'";
# Optional but recommended:
# 1. All header values
add_header X-Frame-Options "SAMEORIGIN";
# 2. Variables containing user input
set $safe_input "$arg_user_input";
Watch out for these quote-related mistakes:
# WRONG: Unquoted space-containing value
set $var string with spaces;
# WRONG: Mismatched quotes
add_header X-Header "value';
# WRONG: Escaping inside quotes (Nginx doesn't need this)
set $var "this is \"wrong\"";