nginx
nginx
listen vs server_name
| The listen directive can be set to:
- An IP address/port combo.
- A lone IP address which will then listen on the default port 80.
- A lone port which will listen to every interface on that port.
- The path to a Unix socket.
location
location optional_modifier location_match {
. . .
}
- (none): If no modifiers are present, the location is interpreted as a prefix match. This means that the location given will be matched against the beginning of the request URI to determine a match.
- =: If an equal sign is used, this block will be considered a match if the request URI exactly matches the location given.
- ~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regular expression match.
- ~*: If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match.
- ~: If a carat and tilde modifier is present, and if this block is selected as the best non-regular expression match, regular expression matching will not take place
Optimizing nginx for high traffic loads
worker_processes 4; # 2 * Number of CPUs
events {
worker_connections 19000; # It's the key to high performance - have a lot of connections available
}
worker_rlimit_nofile 20000; # Each connection needs a filehandle (or 2 if you are proxying)
# Total amount of users you can serve = worker_processes * worker_connections
location
location / {
root /var/www/html; # request file path
index index.php index.html index.htm; # default filename
expires 7d; # static file expire time
try_files $uri $uri/=404; # try_files
}
location /temp {
return 302 http://www.example.com; # 兼容旧版本
}
location /chat {
try_files $uri @chatapp; # redirect to other app
}
location @chatapp {
proxy_pass http://chat.app.com;
}
location /status {
stub_status on; # open nginx status page, default off; # depends on nginx_http_stub_status_module, installation requred
allow 192.168.0.176; # allowed list
deny all; # default deny all
}
location /download {
alias /var/www/download; # assets path, #NOTICE: index attribute not allowed
autoindex on; # turn on inventory index
autoindex_exact_size off; # default on, display exact file size(bytes), OFF display (kB, MB)
autoindex_localtime on; # default off, show GMT time, ON show server time
}
location ~* /story(/|$) {
auth_basic "Login Required";
auth_basic_user_file /etc/nginx/.htpasswd;
root /usr/share/nginx/html;
}
nginx auth
# ubuntu
sudo apt update && sudo apt install apache2-utils -y
# debian
sudo yum install httpd-tools -y
# -c:创建新文件;路径建议放在 Nginx 配置目录(非 web 根)
sudo htpasswd -c /etc/nginx/.htpasswd admin
# 按提示输入并确认密码(密码加密存储)
# add more users
sudo htpasswd /etc/nginx/.htpasswd user1
# 用更安全的 bcrypt 加密(推荐)
sudo htpasswd -B /etc/nginx/.htpasswd admin
# nginx all site enable auth
server {
listen 80;
server_name yourdomain.com;
# 启用 Basic Auth,提示文字可自定义
auth_basic "Restricted Access";
# 指定密码文件路径(必须绝对路径)
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
upstream
# default: round-robin
upstream shop {
server 10.24.0.1:8000;
server 10.24.0.1:8001;
server 10.24.0.2:8000;
}
# weighted
upstream shop {
server 10.24.0.1:8000 weight=1;
server 10.24.0.1:8001 weight=2;
server 10.24.0.2:8000 weight=3;
}
# ip_hash
upstream shop {
ip_hash;
server 10.24.0.1:8000;
server 10.24.0.1:8001;
server 10.24.0.2:8000;
}
# least_conn
# cookie
# route
# lean
# ntlm
# least_time
# queue
# stick
# fair
# url_hash
nginx variable
| name | description |
|---|---|
| $remote_add | |
| $remote_user | |
| $time_local | |
| $request | url + method |
| $status | |
| $body_bytes_sent | |
| $http_referer | |
| $http_user_agent | |
| $request_uri | has search string |
| $uri | no search string |
| $http_x_forwarded_for | |
| $http_x_real_ip | |
| $args | $query_string |
| $host | |
| $scheme | http, https |
| $document_uri | |
| $document_root |
GeoIP
# 1. install dynamic module
sudo apt install libnginx-mod-http-geoip2
# confirm module loaded
nginx -V 2>&1 | grep geoip2
# 2. edit conf files
# 3. place mmdb files
sudo mkdir -p /etc/nginx
sudo cp GeoIP2-City.mmdb /etc/nginx/
sudo chmod 644 /etc/nginx/GeoIP2-City.mmdb
# 4. reload nginx
sudo nginx -t
sudo systemctl restart nginx
# 5. test from remote
curl http://your.domain.com/geo
http {
geoip2 /etc/nginx/GeoIP2-City.mmdb {
auto_reload 5m;
$geoip2_city city names zh-CN;
$geoip2_region subdivisions 0 iso_code;
$geoip2_latitude location latitude;
$geoip2_longitude location longitude;
}
geoip2 /etc/nginx/GeoIP2-Country.mmdb {
$geoip2_country_code default=CN country iso_code;
$geoip2_country_name country names zh-CN;
}
map $geoip2_country_code $allowed_country {
default 0; # Block all by default
CN 1; # only specified countries are allowed
}
server {
listen 80;
location = /geo { # for testing purpose
default_type application/json;
#add_header Content-Type application/json;
return 200 '{
"ip":"$remote_addr",
"lat":"$geoip2_latitude",
"lng":"$geoip2_longitude",
"city":"$geoip2_city",
"country":"$geoip2_country_code",
"region":"$geoip2_region"
}';
}
location / {
proxy_pass http://localhost:13030;
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 $scheme;
proxy_connect_timeout 3600;
proxy_send_timeout 3600;
proxy_read_timeout 3600;
proxy_set_header X-Country-Code $geoip2_country_code;
proxy_set_header X-Country-Name $geoip2_country_name;
proxy_set_header X-City $geoip2_city;
proxy_set_header X-Region $geoip2_region;
proxy_set_header X-Latitude $geoip2_latitude;
proxy_set_header X-Longitude $geoip2_longitude;
}
}
}
API Gateway
http {
# 定义后端服务集群(可选,用于负载均衡)
upstream user_service {
server 192.168.1.10:8080; # 用户服务实例1
server 192.168.1.11:8080; # 用户服务实例2
least_conn; # 优先转发到连接数最少的实例
}
upstream order_service {
server 192.168.1.20:8080; # 订单服务实例
}
server {
listen 80;
server_name api.example.com; # API 网关域名
# 转发 /api/v1/user 到用户服务
location /api/v1/user {
# 传递真实客户端 IP 和 Host 到后端
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_pass http://user_service; # 转发到 upstream 定义的集群
}
# 转发 /api/v1/order 到订单服务
location /api/v1/order {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://order_service;
}
# URL 重写示例:将 /v2/xxx 转发到新服务,并修改路径
location /v2 {
# 重写路径:/v2/user/123 → /user/123
rewrite ^/v2/(.*)$ /$1 break;
proxy_pass http://new_service;
}
}
}
QPS limit
http {
# 定义限流规则:基于客户端 IP,共享 10MB 内存,限制 10r/s(每秒 10 个请求)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
listen 80;
server_name api.example.com;
location /api {
# 应用限流规则:允许突发 20 个请求,超过的直接拒绝(nodelay)
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend_service;
}
}
}
JWT auth, based on OpenResty + Lua
# 需安装 OpenResty(集成 ngx_lua 和 lua-resty-jwt 库)
http {
lua_package_path "/usr/local/openresty/lualib/?.lua;;"; # 指定 Lua 库路径
server {
listen 80;
server_name api.example.com;
location /api {
# 在请求处理前验证 JWT
access_by_lua_block {
local jwt = require "resty.jwt"
local auth_header = ngx.req.get_headers()["Authorization"]
# 检查 Authorization 头是否存在且格式为 "Bearer <token>"
if not auth_header or not string.find(auth_header, "Bearer ") then
ngx.status = 401
ngx.say('{"error": "Missing or invalid Authorization header"}')
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
# 提取 JWT 令牌(去掉 "Bearer " 前缀)
local token = string.sub(auth_header, 8)
# 验证 JWT(使用签名密钥,需与签发方一致)
local jwt_obj = jwt:verify("your-jwt-secret-key", token)
if not jwt_obj.valid then
ngx.status = 401
ngx.say('{"error": "Invalid JWT token: ' .. jwt_obj.reason .. '"}')
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
}
proxy_pass http://backend_service;
}
}
}
CORS
server {
listen 80;
server_name api.example.com;
location /api {
# 允许的来源(* 表示所有,生产环境建议指定具体域名)
add_header 'Access-Control-Allow-Origin' '*';
# 允许的请求方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
# 允许的请求头
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
# 预检请求(OPTIONS)直接返回 204(无内容)
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://backend_service;
}
}
Page Source