When using Nginx as a reverse proxy, the server_name, location, and proxy_pass directives are almost always required. However, each of them has several variations in how they can be written, and the subtle differences between these variations can easily lead to pitfalls. I am documenting these details here.


What are the different ways to write server_name

1. Exact Domain Matching

server_name example.com www.example.com;

The most common way is to write the domain directly. You can write multiple domains, separated by spaces.

2. Wildcard Matching (Prefix or Suffix)

server_name *.example.com;          # 匹配所有子域名,如 www.example.com, mail.example.com
server_name example.*;              # 匹配所有后缀,如 example.com, example.org
server_name *.example.*;            # 匹配子域名和后缀,如 www.example.com, mail.example.org

Wildcards can only appear at the beginning or the end; they cannot be placed in the middle. For example, www.*.com is not allowed.

3. Regular Expression Matching

server_name ~^www\d+\.example\.com$;    # 匹配 www1.example.com, www2.example.com 等
server_name ~^(.*)\.example\.com$;      # 匹配所有 example.com 的子域名

Regex patterns start with ~, and Nginx will match them using regular expressions. However, regex matching has lower priority than exact matching and wildcard matching, and it is also slightly less performant. Use wildcards whenever possible instead of regex.

4. Null Value (Default Host)

server_name "";
# 或
server_name _;

"" indicates a request without a Host header. _ is not actually any special syntax; it is simply a domain name that can never truly be matched, typically used as a fallback default server.

5. IP Address

server_name 192.168.1.1;

Accessing directly via IP will match this server block.

6. Variables

server_name $hostname;  # 使用服务器的主机名

$hostname automatically retrieves the server's hostname, although this notation is less commonly used.

7. Combined Usage

server_name example.com *.example.com ~^www\d+\.example\.com$;

Multiple syntaxes can be used together. Nginx's matching priority is: exact match > prefix wildcard > suffix wildcard > regular expression.


What is the difference between location /, location /image, and location /image/?

These three look similar, but their matching behavior differs.

Impact of Trailing Slashes

  • location /image matches /image and /image/, and even /imageabc will match (because it is a prefix match).
  • location /image/ only matches paths that start with /image/, such as /image/photo.jpg, but it will not match /image (the case without a trailing slash).

If a client requests /image, location /image will handle it, while location /image/ will not match. The request may then fall back to location /.

Priority When Multiple Locations Exist

Nginx selects the longest matching prefix. For example, for a request to /image/photo.jpg:

  • If location /image/ exists, it takes priority.
  • If only location /image exists, it matches that.
  • If neither exists, it matches location /.

location / is the shortest prefix, so it acts as a fallback, matching any path.


The Difference of Whether or Not to Include a Trailing Slash in proxy_pass

This is the part of Nginx that I think is most prone to causing issues: whether or not you include a / after proxy_pass results in completely different forwarded paths.

Assume our location block looks like this:

location /api/ {
    proxy_pass ...;
}

1. proxy_pass http://backend (without path)

location /api/ {
    proxy_pass http://backend;
}

Request http://example.com/api/users, forwarding it to http://backend/api/users.

The original URI /api/users is fully preserved and directly appended to the backend.

2. proxy_pass http://backend/ (with a slash)

location /api/ {
    proxy_pass http://backend/;
}

A request to http://example.com/api/users is forwarded to http://backend/users.

Note that /api/ is stripped here, leaving only /users appended to http://backend/. This happens because proxy_pass includes a path (even if it is just /), causing Nginx to replace the matched location prefix.

For another example, a request to http://example.com/api/ is forwarded to http://backend/.

3. proxy_pass http://backend/image (with a specific path)

location /api/ {
    proxy_pass http://backend/image;
}

Request http://example.com/api/users, forwarded to http://backend/imageusers.

The pattern becomes clear here: Nginx strips the /api/ part matched by the location and directly appends the remaining users to http://backend/image, resulting in /imageusers—which is usually not the desired outcome.

If you want to forward to /image/users, it should be written as:

location /api/ {
    proxy_pass http://backend/image/;
}

Summary of Patterns

In short:

  • proxy_pass has no path component (e.g., http://backend): The original URI is forwarded unchanged.
  • proxy_pass has a path component (e.g., http://backend/ or http://backend/xxx): The prefix matched by the location block is replaced with the path component specified in proxy_pass.

This difference in the / may seem minor, but mixing it up can cause requests to be routed to the wrong path, which can be quite difficult to troubleshoot.