Nginx

Nginx

location syntax

  1. Directives with the "=" prefix that match the query exactly. If found, searching stops.
  2. All remaining directives with conventional strings. If this match used the "^~" prefix, searching stops.
  3. Regular expressions, in the order they are defined in the configuration file.
  4. If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.
location  = / {
  # matches the query / only.
  [ configuration A ] 
}
location  / {
  # matches any query, since all queries begin with /, but regular
  # expressions and any longer conventional blocks will be
  # matched first.
  [ configuration B ] 
}
location /documents/ {
  # matches any query beginning with /documents/ and continues searching,
  # so regular expressions will be checked. This will be matched only if
  # regular expressions don't find a match.
  [ configuration C ] 
}
location ^~ /images/ {
  # matches any query beginning with /images/ and halts searching,
  # so regular expressions will not be checked.
  [ configuration D ] 
}
location ~* \.(gif|jpg|jpeg)$ {
  # matches any request ending in gif, jpg, or jpeg. However, all
  # requests to the /images/ directory will be handled by
  # Configuration D.   
  [ configuration E ] 
}

Can nginx location blocks match a URL query string?

Short answer: No.

Long answer: There is a workaround if we have only a handful of such location blocks.

Here's a sample workaround for 3 location blocks that need to match specific query strings:

server {
  #... common definitions such as server, root

  location / {
    error_page 418 = @queryone;
    error_page 419 = @querytwo;
    error_page 420 = @querythree;

    if ( $query_string = "service=git-receive-pack" ) { return 418; }
    if ( $args ~ "service=git-upload-pack" ) { return 419; }
    if ( $arg_somerandomfield = "somerandomvaluetomatch" ) { return 420; }

    # do the remaining stuff
    # ex: try_files $uri =404;

  }

  location @queryone {
    # do stuff when queryone matches
  }

  location @querytwo {
    # do stuff when querytwo matches
  }

  location @querythree {
    # do stuff when querythree matches
  }
}

You may use $query_string, $args or $arg_fieldname. All will do the job. You may know more about error_page in the official docs.

Warning: Please be sure not to use the standard HTTP codes.

反向代理

假设源站 IP 1.2.3.4,同样监听 80 / 443 端口。

server {
    server_name example.com;
    charset utf-8;

    listen 0.0.0.0:80;

    location / {
        proxy_pass ​http://1.2.3.4;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X_FORWARDED_PROTO https;
    }
}


server {
    server_name example.com;

    listen 0.0.0.0:443 ssl spdy;

    client_max_body_size 100m;

    ssl on;
    ssl_certificate /root/example.com/fullchain.pem;
    ssl_certificate_key /root/example.com/privkey.pem;
    ssl_dhparam /root/example.com/dhparam.pem;
    ssl_ciphers 'AES256+EECDH:AES256+EDH:!aNULL';
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_cache shared:SSL:10m;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_prefer_server_ciphers   on;

    location / {
        proxy_pass https://1.2.3.4;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_cache_bypass $http_upgrade;
    }
}

保护源站

可以在源站主机上设置 iptables 规则,禁止非反向代理访问。

# 假设 1.2.3.45.6.7.8 分别是源站和反向代理主机 IP
iptables -I INPUT 1 -p tcp --dport 80 -d 1.2.3.4 ! -s 5.6.7.8 -j DROP
iptables -I INPUT 1 -p tcp --dport 443 -d 1.2.3.4 ! -s 5.6.7.8 -j DROP

字符串替换 sub_filter

http://nginx.org/en/docs/http/ngx_http_sub_module.html

默认仅替换 text/html

# 配合反向代理使用时,禁止后端 App gzip压缩,否则无法替换字符串。
#proxy_set_header Accept-Encoding "";

sub_filter '</head>' '<script src="https://example.com/test.js"></script></head>';
sub_filter_once on;

Docker 反向代理

jwilder/nginx-proxy

https://github.com/jwilder/nginx-proxy

docker run --name nginx -p 80:80 -p 443:443 -d \
#  -v /root/data/nginx-config/proxy.conf:/etc/nginx/proxy.conf \
#  -v /root/data/nginx-config/vhost.d:/etc/nginx/vhost.d \
#  -v /root/data/certs:/etc/nginx/certs \
  -v /var/run/docker.sock:/tmp/docker.sock:ro \
  jwilder/nginx-proxy

Direct set http response body

location = /test_url {
  types { } default_type "application/json; charset=utf-8";
  add_header Set-Cookie "token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT" always;
  return 200 '{}';
}

Last update: 2019-10-23 06:53:19 UTC