Nginx Location Block: Understanding the Tilde (~) Operator in Regex Pattern Matching


12 views

In Nginx configuration files, the tilde (~) symbol before a URI pattern in a location block indicates that the following pattern should be treated as a case-sensitive regular expression. This is one of several pattern matching modifiers available in Nginx location directives.

location ~ ^/download/(.*)$ {
  alias /home/website/files/$1;
}

The presence or absence of the tilde significantly changes how Nginx processes the location match:

Modifier Behavior Example
location /pattern Prefix matching (no regex) Matches "/pattern" and "/pattern/sub"
location = /pattern Exact matching Only matches "/pattern" exactly
location ~ pattern Case-sensitive regex Regex pattern matching (case matters)
location ~* pattern Case-insensitive regex Regex pattern matching (case ignored)

Here are some common use cases for the tilde operator:

1. Dynamic File Routing

location ~ ^/images/([a-z0-9]+)\.(jpg|png|gif)$ {
  root /data/images/$1;
  try_files $uri /default.jpg;
}

2. API Version Handling

location ~ ^/api/v([0-9]+)/(.*)$ {
  proxy_pass http://backend_$1/$2;
}

3. File Extension Based Rules

location ~ \.(php|phar)$ {
  fastcgi_pass unix:/run/php-fpm.sock;
}

While regex location blocks are powerful, they have some performance implications:

  • Regex matches are evaluated in order until the first match is found
  • Complex regex patterns can impact performance
  • For simple prefix matches, non-regex locations are faster

Here's a more optimized version of our first example:

location /download/ {
  try_files $uri @dynamic_download;
}

location @dynamic_download {
  rewrite ^/download/(.*)$ /$1 break;
  alias /home/website/files;
}

When working with regex location blocks:

  • Forgetting that regex is greedy by default
  • Not escaping special characters properly
  • Overlooking case sensitivity requirements
  • Creating regex patterns that are too broad

Here's an example of problematic regex matching:

# Potentially too broad - will match "/admin/login" and "/random/admin/text"
location ~ /admin {
  deny all;
}

Better alternative:

# More precise matching
location ~ ^/admin(/|$) {
  deny all;
}

The tilde operator enables powerful capture group functionality. Captured values can be used in directives like alias, proxy_pass, and rewrite:

location ~ ^/user/([^/]+)/avatar/(small|medium|large)$ {
  set $username $1;
  set $size $2;
  alias /var/www/avatars/$username/$size.jpg;
}

This configuration would map:
/user/john/avatar/small/var/www/avatars/john/small.jpg


In Nginx configuration, the tilde (~) operator in a location block indicates that the following pattern should be treated as a case-sensitive regular expression. This is one of several pattern matching modifiers available in Nginx's location directive.

# Case-sensitive regex example
location ~ ^/download/(.*)$ {
  alias /home/website/files/$1;
}

Nginx offers several approaches to location matching:

# Prefix matching (no modifier)
location /download/ {
  # matches any URI starting with /download/
}

# Case-sensitive regex (tilde)
location ~ ^/download/(.*)$ {
  # regex match (case matters)
}

# Case-insensitive regex (tilde asterisk)
location ~* \.(jpg|jpeg|png)$ {
  # matches image extensions regardless of case
}

The ~ modifier is particularly useful when you need:

# Exact path matching with regex
location ~ ^/users/([0-9]+)/profile$ {
  # Only matches numeric user IDs
}

# Complex pattern matching
location ~ /blog/(20[0-9]{2})/([a-z0-9-]+)/?$ {
  # Matches blog posts with year and slug pattern
}

While regex locations are powerful, they have performance implications:

  • Regular expression locations are checked in order of appearance
  • Nginx will process the first matching regex it finds
  • Simple prefix matches are faster than regex evaluations

When using tilde operators:

# Use start (^) and end ($) anchors for precise matching
location ~ ^/api/v[1-3]/resources$ {
  # Matches only specific API versions
}

# Use non-capturing groups when possible
location ~ ^/category/(?:books|music|movies)$ {
  # More efficient than capturing groups
}