针对前端同学的 Nginx 入门

130 阅读8分钟

Nginx 是什么?

NGINX 为世界上最繁忙的网站加速内容和应用的交付过程,并提高安全性、可用性和可扩展性。NGINX是用于 Web 服务、负载均衡、反向代理、内容缓存、媒体流传输等场景的开源软件,且F5 NGINX 提供云原生的、Kubernetes 友好的开源和商业解决方案,如今已成为全世界最流行的 web 服务器!

这是 Nginx 站点上的 description,可以了解到:

  1. Nginx 是一个 web 服务器
  2. Nginx 提供了负载均衡、反向代理、内容缓存、媒体流传输等场景

为什么要学习 Nginx

对于前端同学来说

前端项目最终打包完后生成的是 index.html 和一些相关的资源。这些资源没法直接用于访问,于是我们需要一个服务器来提供服务,Nginx 就是一个 web 服务器

对于后端同学来说

后端的算力是寸土寸金的,我们期望更多的能力用来处理业务,Nginx 是一个可以实现动静分离的服务器。

动静分离是将网站静态资源(html,javascript,css,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问

Nginx 的优点

  1. 一种轻量级的web服务器
  2. 设计思想是事件驱动的异步非阻塞处理(类node.js)
  3. 占用内存少、启动速度快、并发能力强
  4. 扩展性好,第三方插件非常多
  5. 在互联网项目中广泛应用

Nginx 的概念

反向代理

正向代理和反向代理

正向代理

正向代理一般用于用户无法直接访问目标服务器,需要一个代理服务器来访问。这种情况下代理服务器在作用上等于一个用户,由他发起真正的请求,获取真正的响应,然后将结果告诉用户。(是站在用户这边的)

反向代理

反向代理一般是用于保护真实服务器的,反向代理隐藏了真实服务器的地址,用户只与代理服务器交互,一定程度上保护了真实服务器

配置反向代理

server {  
  listen       8080;        
  server_name  localhost;

  location / {
    root   html; # Nginx默认值
    index  index.html index.htm;
  }

  proxy_pass http://localhost:8000; # 反向代理配置,请求会被转发到8000端口
}

负载均衡

负载均衡场景

当公司的业务增长到一定量时,就会需要多台服务器(服务器集群)来支持请求。但是用户不会去记多个服务器的地址,用户只期望有一个入口。这种场景就需要负载均衡来处理。

在服务器集群中,请求不是绝对平均的访问到每一台服务器,而是相对平均或者更具权重来处理。

负载均衡内容

  1. 分摊了请求压力
  2. 保证用户访问的稳定性
  3. Nginx 带有健康检查,会定期的轮训各个服务器,避免出现请求打到异常服务器的情况
# 负载均衡:设置domain
upstream domain {
    server localhost:8000;
    server localhost:8001;
}
server {  
        listen       8080;        
        server_name  localhost;

        location / {
            # root   html; # Nginx默认值
            # index  index.html index.htm;
            
            proxy_pass http://domain; # 负载均衡配置,请求会被平均分配到8000和8001端口
            proxy_set_header Host $host:$server_port;
        }
}

Nginx 命令

Nginx 常用命令

  1. nginx:启动服务
  2. nginx -s stop:关闭服务
  3. nginx -s reload:重启
  4. pkill -9 nginx:强制重启

Nginx 配置


#进程, 可更具cpu数量调整
worker_processes  1;

events {
    #连接数
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    #连接超时时间,服务器会在这个时间过后关闭连接。
    keepalive_timeout  10;

    # gizp压缩
    gzip  on;

    # 直接请求nginx也是会报跨域错误的这里设置允许跨域
    # 如果代理地址已经允许跨域则不需要这些, 否则报错(虽然这样nginx跨域就没意义了)
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Headers X-Requested-With;
    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;

    # srever模块配置是http模块中的一个子模块,用来定义一个虚拟访问主机
    server {
        listen       80;
        server_name  localhost;
        
        # 根路径指到index.html
        location / {
            root   html;
            index  index.html index.htm;
        }

        # localhost/api 的请求会被转发到192.168.0.103:8080
        location /api {
            rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/api前缀, 否则会出现404
            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://192.168.0.103:8080; # 转发地址
        }
        
        # 重定向错误页面到/50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

    }

}

进程配置

worker_processes 8; # Nginx 进程数,建议按照CPU数目来指定,一般为它的倍数 (如:2个四核的CPU计为8)

worker_rlimit_nofile 65535; #一个Nginx 进程打开的最多文件描述符数目

worker_connections 65535;#每个进程允许的最多连接数

http配置

http {
    sendfile  on                  # 高效传输文件的模式 一定要开启
    keepalive_timeout   65        # 客户端服务端请求超时时间

    # 直接请求nginx也是会报跨域错误,这里设置允许跨域
    # 如果代理地址已经允许跨域则不需要这些, 否则报错(虽然这样nginx跨域就没意义了)
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Headers X-Requested-With;
    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
}

server 配置

server {
   listen       80; # 监听端口
   server_name  dev1-cd.hongsong.club; # 域名 Host
	 # path
   location / {
       proxy_pass http://127.0.0.1:10086/; # 代理配置
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header REMOTE-HOST $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }
}

一些常见配置

反向代理

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend_server:8080;  # 后端 Java 服务
        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;
    }
}

负载均衡

http {
    upstream backend {
        least_conn;  # 每次选择当前连接数最少的服务器
        server backend1.example.com weight=6;
        server backend2.example.com weight=3;
        server backend3.example.com weight=2;
    }

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
        }
    }
}

动静态分离

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://app_server:8000;
    }

    location /static/ {
        alias /var/www/static_content/;
    }
}

缓存代理

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_cache my_cache;
            proxy_pass http://backend_server:8080;
            add_header X-Cache-Status $upstream_cache_status;
            proxy_cache_valid 200 302 10m;
            proxy_cache_valid 404 1m;
        }
    }
}

限制IP访问

server {
    listen 80;
    server_name example.com;

    location / {
        allow 192.168.1.0/24;  # 允许内部网段
        deny all;              # 拒绝其他地址
        proxy_pass http://backend_server:8080;
    }
}

Http 认证

server {
    listen 80;
    server_name example.com;

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

WS 代理

server {
    listen 80;
    server_name example.com;

    location /ws/ {
        proxy_pass http://websocket_server:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
}

请求限制

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;  # 每秒最多1个请求

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req zone=mylimit burst=5;  # 突发请求最多5个
            proxy_pass http://backend_server:8080;
        }
    }
}

请求重定向

server {
    listen 80;
    server_name example.com;

    location /old-page {
        return 301 https://example.com/new-page;  # 301 永久重定向
    }
}

HTTPS

server {
    listen 443 ssl;
    server_name secure.example.com;

    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

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

ssl_certificate和 ssl_certificate_key :定义SSL证书和私钥文件路径。

ssl_protocols和 ssl_ciphers :配置支持的SSL协议和加密套件,确保连接的安全性。

基本前端服务(qiankun子应用)

server {
        listen       8000;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;  # 尝试文件,如果没有找到则返回 index.html
            add_header Access-Control-Allow-Origin *; 
        }

        # location ~* .(css|js|html)$ {
        #     root   html;
        #     index index.html;
        #     add_header Access-Control-Allow-Origin *; 
        # }

        location ~* .(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ {
            rewrite ^/APC_WEBWATCH/(.*)$ /$1 last;
            add_header Access-Control-Allow-Origin *; 
        }

        # 匹配 .html 文件,保持原样请求
        location ~* .html$ {
            # 不需要任何额外的配置,只是确保这个 location 块存在
            add_header Access-Control-Allow-Origin *; 
        }
        
        location /APC_WEBWATCH/inter-api {
            proxy_pass http://10.30.71.205:10676/inter-api;  # 替换为后端服务器的地址和端口
            proxy_set_header Host $host;  # 保持主机头
            proxy_set_header X-Real-IP $remote_addr;  # 真实的客户端 IP
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 转发的IP
            proxy_set_header X-Forwarded-Proto $scheme;  # 转发的协议
        }
        
        location /inter-api {
            proxy_pass http://10.30.71.205:10676;  # 替换为后端服务器的地址和端口
            proxy_set_header Host $host;  # 保持主机头
            proxy_set_header X-Real-IP $remote_addr;  # 真实的客户端 IP
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 转发的IP
            proxy_set_header X-Forwarded-Proto $scheme;  # 转发的协议
        }
        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

详细配置

# 启动进程,通常设置成和cpu的数量相等
worker_processes  1;

# 全局错误日志定义类型,[debug | info | notice | warn | error | crit]
error_log  logs/error.log;
error_log  logs/error.log  notice;
error_log  logs/error.log  info;

# 进程pid文件
pid        /var/run/nginx.pid;

# 工作模式及连接数上限
events {
    # 仅用于linux2.6以上内核,可以大大提高nginx的性能
    use   epoll;

    # 单个后台worker process进程的最大并发链接数
    worker_connections  1024;

    # 客户端请求头部的缓冲区大小
    client_header_buffer_size 4k;

    # keepalive 超时时间
    keepalive_timeout 60;

    # 告诉nginx收到一个新连接通知后接受尽可能多的连接
    # multi_accept on;
}

# 设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
    # 文件扩展名与文件类型映射表义
    include       /etc/nginx/mime.types;

    # 默认文件类型
    default_type  application/octet-stream;

    # 默认编码
    charset utf-8;

    # 服务器名字的hash表大小
    server_names_hash_bucket_size 128;

    # 客户端请求头部的缓冲区大小
    client_header_buffer_size 32k;

    # 客户请求头缓冲大小
    large_client_header_buffers 4 64k;

    # 设定通过nginx上传文件的大小
    client_max_body_size 8m;

    # 开启目录列表访问,合适下载服务器,默认关闭。
    autoindex on;

    # sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于普通应用,
    # 必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度
    sendfile        on;

    # 此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
    #tcp_nopush     on;

    # 连接超时时间(单秒为秒)
    keepalive_timeout  65;


    # gzip模块设置
    gzip on;               #开启gzip压缩输出
    gzip_min_length 1k;    #最小压缩文件大小
    gzip_buffers 4 16k;    #压缩缓冲区
    gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
    gzip_comp_level 2;     #压缩等级
    gzip_types text/plain application/x-javascript text/css application/xml;
    gzip_vary on;

    # 开启限制IP连接数的时候需要使用
    #limit_zone crawler $binary_remote_addr 10m;

    # 指定虚拟主机的配置文件,方便管理
    include /etc/nginx/conf.d/*.conf;


    # 负载均衡配置
    upstream aaa {
        # 请见上文中的五种配置
    }


   # 虚拟主机的配置
    server {

        # 监听端口
        listen 80;

        # 域名可以有多个,用空格隔开
        server_name www.aaa.com aaa.com;

        # 默认入口文件名称
        index index.html index.htm index.php;
        root /data/www/sk;

        # 图片缓存时间设置
        location ~ .*.(gif|jpg|jpeg|png|bmp|swf)${
            expires 10d;
        }

        #JS和CSS缓存时间设置
        location ~ .*.(js|css)?${
            expires 1h;
        }

        # 日志格式设定
        #$remote_addr与 $http_x_forwarded_for用以记录客户端的ip地址;
        #$remote_user:用来记录客户端用户名称;
        #$time_local:用来记录访问时间与时区;
        #$request:用来记录请求的url与http协议;
        #$status:用来记录请求状态;成功是200,
        #$body_bytes_sent :记录发送给客户端文件主体内容大小;
        #$http_referer:用来记录从那个页面链接访问过来的;
        log_format access '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" $http_x_forwarded_for';

        # 定义本虚拟主机的访问日志
        access_log  /usr/local/nginx/logs/host.access.log  main;
        access_log  /usr/local/nginx/logs/host.access.404.log  log404;

        # 对具体路由进行反向代理
        location /connect-controller {

            proxy_pass http://127.0.0.1:88;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;

            # 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;

            # 允许客户端请求的最大单文件字节数
            client_max_body_size 10m;

            # 缓冲区代理缓冲用户端请求的最大字节数,
            client_body_buffer_size 128k;

            # 表示使nginx阻止HTTP应答代码为400或者更高的应答。
            proxy_intercept_errors on;

            # nginx跟后端服务器连接超时时间(代理连接超时)
            proxy_connect_timeout 90;

            # 后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据
            proxy_send_timeout 90;

            # 连接成功后,后端服务器响应的超时时间
            proxy_read_timeout 90;

            # 设置代理服务器(nginx)保存用户头信息的缓冲区大小
            proxy_buffer_size 4k;

            # 设置用于读取应答的缓冲区数目和大小,默认情况也为分页大小,根据操作系统的不同可能是4k或者8k
            proxy_buffers 4 32k;

            # 高负荷下缓冲大小(proxy_buffers*2)
            proxy_busy_buffers_size 64k;

            # 设置在写入proxy_temp_path时数据的大小,预防一个工作进程在传递文件时阻塞太长
            # 设定缓存文件夹大小,大于这个值,将从upstream服务器传
            proxy_temp_file_write_size 64k;
        }

        # 动静分离反向代理配置(多路由指向不同的服务端或界面)
        location ~ .(jsp|jspx|do)?$ {
            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://127.0.0.1:8080;
        }
    }
}

gzip 压缩

    # gzip模块设置
    gzip on;               #开启gzip压缩输出
    gzip_min_length 1k;    #最小压缩文件大小
    gzip_buffers 4 16k;    #压缩缓冲区
    gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
    gzip_comp_level 2;     #压缩等级
    
    # 设置什么类型的文件需要压缩
    gzip_types text/plain application/x-javascript text/css application/xml;
    
    # 用于设置使用Gzip进行压缩发送是否携带“Vary:Accept-Encoding”头域的响应头部
    # 主要是告诉接收方,所发送的数据经过了Gzip压缩处理
    gzip_vary on;

基本配置

worker_processes auto;     // 处理进程
worker_connections 65535;     // 最大并发链接数
keepalive_timeout 75s;     // 连接超时时间
gzip on;     // 是否开启压缩传输
gzip_min_length 1kb;     // 最小压缩文件
gzip_comp_level 2;     // 压缩率
client_max_body_size 50mb;     // 最大上传文件
server_names_hash_bucket_size 512;     // 服务器名字的hash表大小
client_header_buffer_size 32kb;     // 客户端请求头buffer大小
client_body_buffer_size 512kb;     // 请求主体缓冲区

一些常见的正则匹配式

静态资源

location ~* .(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ {
    rewrite ^/xpt-supgpt-unmanned-factory/(.*)$ /$1 last; 
    root /usr/share/nginx/html;
}

请求代理

location ^~ /api/ {
    proxy_pass http://backend_service;
}

HTML 文件

location ~* .html$ {
    root /var/www/html;
}

特定路径(例如/about和/contact)

location ~ ^/(about|contact)$ {
    # 处理关于和联系方式请求
}

缓存相关

强缓存

强缓存是在请求和响应的生命周期内,直接从浏览器的缓存中获取数据,而不需要向服务器发送请求。主要涉及以下两种HTTP头:

  • Cache-Control:指示浏览器如何缓存资源。
    • max-age:定义资源在缓存中可以保留的时间(秒),如Cache-Control: max-age=3600表示资源可以缓存一小时。
    • public / privatepublic允许任何缓存,private只允许用户的浏览器缓存。
  • Expires:过期时间,表示资源的有效期,较早的缓存机制,现在大多用于兼容性。
location /images/ {
    expires 30d;  # 设置强缓存过期时间为30天
    add_header Cache-Control "public, max-age=2592000";  # 最大缓存时间为30天
}

协商缓存

协商缓存是一种动态的缓存机制,当强缓存过期后,浏览器会向服务器发送请求,询问资源是否被修改。主要是通过以下两个HTTP头实现:

location /api/ {
    add_header Last-Modified $date_gmt;  # 添加Last-Modified头
    add_header ETag "$request_time";      # 添加ETag头
    expires epoch;                        # 禁用强缓存
}

文件缓存

http {
    open_file_cache max=1000 inactive=20s;  # 最大缓存1000个文件,20秒无访问后淘汰
    open_file_cache_valid 30s;               # 30秒内不会重新打开文件
}

重定向

return

server {
    listen 80;
    server_name example.com www.example.com;

    return 301 https://example.com$request_uri;
}

rewrite

server {
    listen 80;
    server_name example.com;

    location / {
        rewrite ^/old-path(.*)$ /new-path$1 permanent;
    }
}

结合条件重定向

server {
    listen 80;
    server_name example.com;

    if ($http_user_agent ~* "iPhone") {
        rewrite ^/(.*)$ /mobile/$1 redirect;
    }
}