天天看点

nginx Location 配置及常用配置

作者:零一间
nginx Location 配置及常用配置

nginx Location语法规则

在 Nginx 中,Location 块是用来匹配请求 URL 并处理相应请求的常见配置指令之一。以下是 Location 块的语法规则:

语法

每个 Location 块都需要一个匹配规则,一般采用正则表达式的形式,后面跟着一组配置指令。例如:

location ~* \.(jpg|jpeg|png|gif|ico)$ {
    # 配置指令
}
           

Location 匹配规则

Nginx 中的 Location 匹配规则有以下几种:

  1. 前缀匹配:匹配 URI 的前缀,也就是以指定字符串开头的 URI。

举例:

location /static/ {
    # ...
}
           

以上配置将匹配所有以 “/static/” 开头的 URI,例如 /static/css/main.css、/static/images/logo.png 等。

  1. 正则表达式匹配:使用正则表达式来匹配 URI。

举例:

location ~ ^/user/\d+ {
    # ...
}
           

以上配置将匹配所有以 “/user/” 开头,后跟数字的 URI,例如 /user/123、/user/456 等。

  1. 精确匹配:匹配完整的 URI。

举例:

location = /about {
    # ...
}
           

以上配置将仅匹配 URI 为 “/about” 的请求。

  1. 最长前缀匹配:匹配与 URI 前缀相匹配的最长的 Location。

举例:

location / {
    # ...
}
location /test/ {
    # ...
}
           

对于 URI “/test/index.html”,将匹配 /test/ 对应的 Location,而非 / 对应的 Location。

需要注意的是,当用于匹配 URI 的 Location 配置块出现重叠时,实际匹配使用最长的前缀匹配规则。例如:

location / {
    # ...
}
location /test/ {
    # ...
}
location /test/test/ {
    # ...
}
           

对于 URI “/test/test/index.html”,将匹配到 /test/test/ 对应的 Location。因此,在处理重叠的 URI 匹配时,需要确保 Location 配置各自独立且不重复,以避免匹配错误。

nginx Location 配置及常用配置

优先级

Nginx 块的优先级,从高到低分别是 “=”,”^~”,”~”和”~*”,因此在匹配规则时应该注意处理顺序。

块内配置指令

在 Location 块内部,可以配置多个 Nginx 指令来对请求进行处理。这些指令包括:proxy_pass、root、alias、rewrite等。这些指令可以根据请求的具体情况进行不同的处理。

块嵌套

在 Location 块中可以嵌套其他的 Location 块,这种嵌套方式非常灵活。例如:

location /product {
    # 配置指令
    location /product/detail {
        # 配置指令
    }
}
           

在上面的示例中,/product 是外层 Location 块,/product/detail 是内部 Location 块,内部 Location 块的配置将继承上层 Location 块的配置。

以下是一个完整的基于 Location 块的 Nginx 配置示例:

server {
    listen 80;
    server_name example.com;

    # 匹配请求 "/" 的 Location 配置块
    location / {
        root /var/www/html;
        index index.html;
    }

    # 匹配请求 "/blog" 的 Location 配置块
    location /blog {
        alias /var/www/blog;
        index index.html;
    }

    # 匹配所有以 .php 结尾的请求的 Location 配置块
    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
    }
}
           

在上面的示例中,我们定义了三个 Location 块。分别匹配了请求 “/”,”/blog” 和以 “.php” 结尾的请求。Nginx 将请求地址与这个 “location” 块中的 URI 进行比较,匹配成功则执行相应的操作。

第一个 Location 块匹配请求 “/”,并将请求转发到 /var/www/html 目录下,同时设置为默认访问首页为 index.html。

第二个Location块匹配以”/blog”开头的请求,并映射到服务器上的 /var/www/blog 目录下。

第三个 Location 块使用“~”符号匹配以 “.php” 结尾的请求,将请求转发到 FastCGI 进程(如 PHP-FPM)的 IP 和端口号上。在这个示例中,我们将请求映射到本机上的 9000 端口(也可设置为 UNIX 套接字),并使用 fastcgi_params 将所有必要的协议参数传递给 FastCGI 进程。我们还使用 fastcgi_param 将 SCRIPT_FILENAME 提供给 FastCGI 进程,让它知道应该在哪里查找 PHP 文件。

通过组合不同的 Location 块和 Nginx 指令,我们可以实现各种不同的功能,如静态文件服务、反向代理、负载均衡、安全认证等。

nginx Location 配置及常用配置

配置示例:

根据文件类型加载配置

location / {  
    root /var/www/html;  
    index index.html;  
}  

location ~ \.php$ {  
    fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;  
    fastcgi_index index.php;  
    include fastcgi_params;  
}  

location ~ \.js$ {  
    expires 30d;  
    add_header Cache-Control "public";  
}  

location ~ \.css$ {  
    expires 30d;  
    add_header Cache-Control "public";  
}
           

根据请求头中的 User-Agent 加载配置

if ($http_user_agent ~* "Android") {  
    set $show_android_qr_code "yes";  
}  

if ($show_android_qr_code = "yes") {  
    # 显示 Android 二维码的配置  
} else {  
    # 不显示 Android 二维码的配置  
}
           

静态文件服务

server {
    listen 80;
    server_name example.com;

    location / {
        root /var/www/html;
        index index.html;
    }

    location /static/ {
        root /var/www/;
        index index.html;
    }
}
           

第一个 location 块匹配 URI 为 “/” 的请求,并使用 root 指令将请求转发到 /var/www/html 目录下。

第二个 location 块匹配以 “/static/” 开头的请求,并使用 root 指令将这些请求指向服务器上的 /var/www 目录下。如果用户请求的资源存在,Nginx 会尝试返回这些资源。此外,我们还指定了 index.html 作为默认页面。

反向代理

server {
    listen 80;
    server_name example.com;

    location /api/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://127.0.0.1:8080/;
    }
}
           

在上面的示例中,我们创建了一个 name-based server,监听 on port 80,接受所有 coming to example.com requests。 重点是下面的 location 块:

location /api/ {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://127.0.0.1:8080/;
}
           

location /api/ 匹配在 URI 中包含 /api/ 的所有请求。

proxy_pass 指令将请求转发到 http://127.0.0.1:8080/,并将 HTTP 头信息中的 Host 和 X-Real-IP 添加到代理请求中。由于没有指定URI上下文,因此 Nginx 不会更改代理请求的 URI。

需要注意的是,为了实现反向代理,我们需要安装后端服务器(如 Apache、Node.js 等),并在代理服务器中将请求转发到后端服务器上。

通常情况下,后端服务器运行在 localhost 上的某个端口号上,代理服务器则使用反向代理技术将请求转发到后端服务器。

负载均衡

Nginx 可以通过使用 upstream 模块实现负载均衡。

upstream 模块允许我们定义一个或多个后端服务器,并通过设置不同的负载均衡算法来实现用户请求的分发。

upstream backend {
    server 192.168.1.101:80 weight=3;
    server 192.168.1.102:80 weight=2;
    server 192.168.1.103:80 weight=3;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
           

在上面的示例中,我们先定义了一个 upstream 块,指定了三个后端服务器的地址和端口。前两个服务器的 weight 分别设置为 3 和 2,最后一个服务器的 weight 设置为 3,这意味着第一个服务器将处理更多的请求。然后,我们在 server 块中使用了 location 块,定义了根上下文 URI,并将请求转发到 upstream 中定义的服务器组。proxy_pass 指令指定了实际的后端服务器地址,proxy_set_header 指令设置了代理服务器的 HTTP 头信息。这些信息将通过代理服务器传递到后端服务器。

当请求到达代理服务器时,Nginx 会自动选择一个合适的后端服务器处理请求,以实现负载均衡。Nginx 支持的负载均衡算法包括 round-robin(默认)、IP hash、least connected 等。可以通过设置 upstream 块中不同的负载均衡算法来实现不同的负载均衡策略。

安全认证

Nginx 可以通过 location 块的认证功能,实现基于 HTTP 基本认证的访问控制机制。

server {
    listen 80;
    server_name example.com;

    location /secure/ {
        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/.htpasswd;

        proxy_pass http://backend/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
           

在上面的示例中,我们创建了一个 server 块,监听 80 端口,并将请求转发到后端服务器。我们使用了 location 块和认证指令来配置了访问控制机制。我们指定了URI上下文为 “/secure/”,并开启了 HTTP 基本认证。”Restricted Area” 是认证提示信息,它会在用户需要认证时显示出来。auth_basic_user_file 指令配置了用户名和密码的数据文件。Nginx 并不负责实现密码验证,而是通过代理服务器从数据文件中读取用户名和密码。代理服务器使用的密码格式是类 Apache 的 htpasswd 格式。

需要使用 htpasswd 工具创建用户名和密码数据文件,例如:

htpasswd -c /etc/nginx/.htpasswd john
           

执行上面的命令将会创建 /etc/nginx/.htpasswd 文件,并要求你输入密码。如果你想为另一个用户添加密码,请省略 -c 选项。

本示例中的认证指令将限制 “/secure/” URI 上下文的访问,只有经过认证的用户才能访问。上面提到的基于 HTTP 基本认证并不安全,并且只应作为一种控制简单的访问权限的解决方案。

nginx Location 配置及常用配置

限制访问

Nginx 可以通过限制 location 块来限制访问,从而确保只有授权用户可以访问资源。

server {
    listen 80;
    server_name example.com;

    location /private/ {
        deny all;

        location /private/secret.html {
            allow 192.168.1.0/24;
            deny all;
        }

        location /private/important.html {
            allow 192.168.1.100;
            allow 192.168.1.101;
            deny all;
        }

        proxy_pass http://backend/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
           

在上面的示例中,我们创建了一个 server 块,并使用了 location 块来限制访问。我们使用了 deny 指令,以防止未经授权的用户访问 URI 上下文 “/private/”。

此处使用了嵌套的 location 块,以进一步限制访问 “/private/” URI 上下文中的具体文件。

对于 /private/secret.html,我们允许 IP 在 192.168.1.0/24 子网的主机,同时拒绝所有其他主机。对于 /private/important.html,我们只允许 IP 为 192.168.1.100 或 192.168.1.101 的主机,同时拒绝所有其他主机。要注意的是,拒绝指令会优先于允许指令。

最后,我们将请求转发到后端服务器上,使用了 proxy_pass、proxy_set_header 指令。

通过以上的配置,我们限制了访问 “/private/” URI 上下文,同时对该上下文下的具体文件也进行了授权限制,只有特定的 IP 主机才能访问。需要注意的是,此方案还存在安全风险,比如 IP 地址欺骗攻击、代理服务器绕过、Cookie 劫持等。

禁止目录遍历

目录遍历是指攻击者尝试以任意方式访问站点中的目录或文件。攻击者可能尝试使用 “..” 之类的符号直接访问父目录或使用其他技术,例如暴力破解会话 ID,从而获取站点中的敏感信息。

server {
    listen 80;
    server_name example.com;

    location / {
        try_files $uri $uri/ /index.html;

        location ~* \.(php|jsp|cgi|asp|aspx|py|sh|pl)$ {
            return 404;
        }
    }
}
           

在上面的示例中,我们将请求转发到默认的首页 index.html。当尝试访问非 index.html 文件时,我们使用 try_files 指令来查找对应的文件,如果找不到文件,则继续查找该路径下的子目录。使用 try_files 可以防止攻击者尝试获取站点中的信息。我们还使用了正则表达式匹配文件扩展名,通过拒绝访问具有风险的文件,例如 php、jsp、cgi 等,可以保护站点免受攻击。

需要注意的是,禁止目录遍历并不能完全保证站点的安全。攻击者仍然可能利用其他漏洞和技术攻击站点,因此建议在实现安全配置的同时,始终保持最新的安全补丁和最佳实践。

安全TLS支持

确保 Nginx 安全支持 TLS 协议,通常需要考虑以下几个方面:

  1. 版本和密码套件:根据安全最佳实践,应启用 TLS 1.2 或更高版本,并且只使用安全的密码套件。可以使用 Nginx 的 ssl_protocols 和 ssl_ciphers 指令配置版本和密码套件。
  2. SSL 证书安全性:建议使用由受信任的证书颁发机构(CA)签名的 SSL 证书,以确保证书的可靠性和安全性。可以使用 ssl_certificate 和 ssl_certificate_key 指令配置 SSL 证书和私钥位置。
  3. 劫持保护:开启 HTTP Strict Transport Security(HSTS)可以保护站点免受证书劫持等攻击。可以使用 add_header 指令配置 HSTS 头。
  4. 防止 BEAST 攻击:建议开启 TLS 块加密模式以防止 BEAST(BREACH)攻击,可以使用 ssl_prefer_server_ciphers 指令配置。

下面是一个使用 location 块启用安全 TLS 支持的 Nginx 配置示例:

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/certificate;
    ssl_certificate_key /path/to/key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers on;

    add_header Strict-Transport-Security "max-age=31536000";

    location / {
        proxy_pass http://backend/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

}
           

在上面的示例中,我们开启了 TLSv1.2 和 TLSv1.3 版本,只使用了安全的密码套件,开启了服务器密码套件优先模式,并配置了 HSTS 头。我们也配置了 SSL 证书和私钥路径,并使用了 location 块将请求转发到后端服务器。

需要注意的是,安全证书配置是 Web 应用程序安全的重要方面之一,可以有效地阻止中间人攻击和数据泄漏。

继续阅读