nginx 简介

Nginx(发音同“engine X”)是异步框架的网页服务器,也可以用作反向代理、负载平衡器和 HTTP 缓存。该软件由 伊戈尔·赛索耶夫 创建并于 2004 年首次公开发布。2011 年成立同名公司以提供支持。2019 年 3 月 11 日,Nginx 公司被 F5 Networks 以 6.7 亿美元收购。

主要功能

  • HTTP 服务器
  • FastCGI 动态内容网站
  • 反向代理
    • 缓存
    • 负载均衡

安装配置

Linux 平台下的安装

软件包安装

按照 文档 上的说明,根据不同的发行版本,执行命令即可。
下面摘抄两个常用发行版的安装命令。

RHEL/CentOS

sudo yum install yum-utils
cat | sudo tee /etc/yum.repos.d/nginx.repo <<TEXT
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/\$releasever/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
TEXT
sudo yum install nginx # 按 y 确定安装

Ubuntu

sudo apt install curl gnupg2 ca-certificates apt-transport-https lsb-release
echo "deb https://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" | sudo tee /etc/apt/preferences.d/99nginx
curl -o /tmp/nginx_signing.key https://nginx.org/keys/nginx_signing.key
# 省略验证签名,但生产环境必须验证
sudo mv /tmp/nginx_signing.key /etc/apt/trusted.gpg.d/nginx_signing.asc
sudo apt update
sudo apt install nginx # 回车确认安装

源码安装

下载页面

1.18.0 稳定版

(以安装 nginx-1.18.0 为例)

mkdir nginx-build && cd nginx-build
sudo apt install gcc make # CentOS 上用 sudo yum install gcc make
wget https://ftp.pcre.org/pub/pcre/pcre-8.43.tar.gz
tar -zxvf pcre-8.43.tar.gz
wget http://zlib.net/zlib-1.2.11.tar.gz
tar -zxvf zlib-1.2.11.tar.gz
wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz
tar -zxvf openssl-1.1.1k.tar.gz
wget https://nginx.org/download/nginx-1.18.0.tar.gz
tar -zxvf nginx-1.18.0.tar.gz
cd nginx-1.18.0
# 这里启用一些常用模块,详情请查看文档
# 默认安装位置在 /usr/local/nginx
./configure \
  --with-pcre=../pcre-8.43 \
  --with-zlib=../zlib-1.2.11 \
  --with-openssl=../openssl-1.1.1k \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_realip_module \
  --with-http_addition_module \
  --with-http_gunzip_module \
  --with-http_gzip_static_module \
  --with-http_auth_request_module \
  --with-http_random_index_module \
  --with-http_slice_module
make
sudo make install

# 查看安装成功的版本
/usr/local/nginx/sbin/nginx -v

# 可选,将 nginx 执行文件链接到系统
sudo ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx

Windows 平台下的安装

对于 Windows 平台,nginx 官网提供了下载地址,可以直接从官网下载。

下载页面

1.18.0 稳定版

下载完成后解压到任意目录即可使用。

启动、停止、重启

对于 Windows 或源码安装的版本,只能通过发送信号的方式控制 nginx,命令如下:

sudo nginx           # 启动
sudo nginx -s stop   # 停止(关闭所有连接)
sudo nginx -s quit   # 退出(等待连接断开)
sudo nginx -s reload # 重新加载配置
sudo nginx -t        # 测试配置文件

对于使用发行版软件包安装的版本,可以使用 systemd 管理 nginx 服务。

sudo systemctl enable nginx.service  # 让 nginx 开机自启
sudo systemctl disable nginx.service # 取消开机自启
sudo systemclt start nginx.service   # 立即启动 nginx
sudo systemclt restart nginx.service # 重启 nginx
sudo systemclt stop nginx.service    # 停止 nginx
sudo systemclt reload nginx.service  # 重新加载配置文件

搭建基础 HTTP 服务器

一个 HTTP 服务器最基础的功能就是提供静态内容浏览,如果你的项目使用 webpack 打包成静态文件,那么直接把打包后的输出丢进 nginx 就部署完成了。

在安装好 nginx 后,nginx 已经为我们创建好了一个 HTTP 服务器的例子,启动后在浏览器输入服务器地址即可看到 nginx 的欢迎页面。

那么我们来看一下 nginx 的默认配置文件为我们做了什么。

/etc/nginx/nginx.conf 文件内容:

user  nginx; # 启动用户,nginx 的 workers 将以该用户的身份运行
worker_processes  1; # worker 进程的数量,建议为 CPU 核心数

error_log  /var/log/nginx/error.log warn; # 错误日志文件存放位置
pid        /var/run/nginx.pid; # master 进程的 pid 保存地址(控制 nginx 需要向进程发送信号)


events {
    worker_connections  1024;
}


http { # http 节点,所有的虚拟服务器都要在这个节点里配置
    include       /etc/nginx/mime.types; # MIME 类型定义
    default_type  application/octet-stream; # 如果没有识别,默认的 MIME 类型

    # 日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main; # 请求日志地址

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on; # 是否启用 gzip 静态压缩

    include /etc/nginx/conf.d/*.conf; # 引入该目录下的所有 .conf 文件
}

查看 /etc/nginx/conf.d/,发现默认有个 default.conf

/etc/nginx/conf.d/default.conf 文件内容:

server {
    listen       80; # 端口号
    server_name  localhost; # 绑定域名

    #charset koi8-r; # 默认编码
    #access_log  /var/log/nginx/host.access.log  main; # 单独配置日志

    location / {
        root   /usr/share/nginx/html; # 内容根,访问服务器地址,就相当于访问这个目录
        index  index.html index.htm; # 欢迎页的文件名。即访问某个目录,如果不加文件名,默认显示的页面
    }

    # 将服务器错误页面重定向至静态的 /50x.html 页面
    error_page   500 502 503 504  /50x.html;

    # 这个地方的内容根和上面一样,可以去掉
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # 也可以用这个配置默认 404 页面
    # error_page 404 /404.html;
}

可见默认的配置将 /usr/share/nginx/html 设置成了服务器的“内容根” (document root),即当我们访问服务器地址时,服务器会从这个目录查找页面发送给我们,相当于服务器网站的根目录,所以也叫“网站根” (www root)。

在同一个服务器上搭建多个网站

观察刚才的配置文件结构,我们可以发现,http 节点下应该可以有多个 server,即虚拟主机。

由于默认的配置会包含 /etc/nginx/conf.d/ 下的所有 .conf 文件,所以我们只要创建一个新的配置文件即可。

/etc/nginx/conf.d/test.conf 文件内容:

server {
    listen       80; # 端口号
    server_name  gardel.top; # 绑定域名(测试时可以将域名加到 /etc/hosts 中)

    location / {
        root   /usr/share/nginx/test;
        index  index.html index.htm;
    }
}

gardel.top 解析到服务器上,或者设置 hosts。

创建 /usr/share/nginx/test/index.html,然后重启 nginx。

访问 http://gardel.top,即可看到静态网页。

这样我们就在同一个服务器上的 80 端口搭建了两个网站,当然了,需要不同的域名。另外不同的端口也是可以的。

配置 https

众所周知,http 是明文传输协议,在网络中极易受到攻击,因此 https 正在逐渐替代 http,成为网站的标配。

要想在 nginx 中启用 https,首先要在编译时启用 ssl 模块,我们在安装时已经带上了。要检查当前安装的 nginx 是否支持 ssl,可以通过输入 nginx -V 查看编译参数,如果包含 --with-http_ssl_module 参数,则已支持 https。

https 使用非对称加密交换对称加密用的密码,客户端需要验证服务端的公钥,然后生成用公钥加密的随机数发给服务端,服务端用私钥解密,生成密码后用于传输。

服务端的公钥是服务器证书的一部分,证书用于表示服务器的身份,防止中间人攻击。因此,要让客户端信任服务器的证书,就必须使用客户端系统信任的权威证书机构颁发的证书。


互联网上的权威证书机构通常不会免费提供证书。在此情况下公益组织 Let’s Encrypt 为了推进 https 普及,宣布免费提供 tls 证书,可用于 https。另外,国内也有一些免费的证书颁发机构。

下面给出使用 certbot 程序申请泛解析证书的大致方法,具体细节请自行研究。

  1. 安装 certbot

    如果是 Ubuntu,直接输入命令:

    sudo apt install certbot
    

    如果是 CentOS,使用下面的命令:

    sudo yum install epel-release
    sudo yum install certbot
    
  2. 运行 certbot
    sudo certbot certonly -d "gardel.top,*.gardel.top" --manual --preferred-challenges dns
    

    程序会要求用户为域名设置 dns txt 记录以用于验证所有权,验证成功后会颁发证书,提示证书保存路径。


nginx 支持 pem/crt 格式的证书,假设我们已经创建好了证书,路径如下:

  • 证书公钥:/etc/nginx/certs/gardel.top.crt
  • 证书密钥:/etc/nginx/certs/gardel.top.key

修改配置文件 /etc/nginx/conf.d/test.conf

server {
    listen       443 ssl; # 端口号
    server_name  gardel.top; # 绑定域名(测试时可以将域名加到 /etc/hosts 中)

    ssl_certificate /etc/nginx/certs/gardel.top.crt;
    ssl_certificate_key /etc/nginx/certs/gardel.top.key;
    # 下面的都是推荐参数,照着配置即可
    #ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256::!MD5";
    ssl_prefer_server_ciphers on;

    location / {
        root   /usr/share/nginx/test;
        index  index.html index.htm;
    }
}

# 将 http 协议跳转到 https
server {
    listen       80;
    server_name  gardel.top;
    rewrite ^(.*)$  https://$host$1 permanent;
}

配置完成后重启 nginx,访问 http://gardel.top,会跳转到 https 协议,并且地址栏出现加密安全图标。

兼容单页面应用

这里说的单页面应用,就是只有一个 index.html 文件,所有路径的页面都是通过 javascript 动态创建的,比如用 react、vue 框架搭建的应用。

由于其只有一个 index.html 文件,所有其他的页面,都必须在内部指向 index.html。

修改 server 节点下面的 location / 如下:

location / {
    root   /path/to/vue-project/dist;
    try_files $uri $uri/ /index.html?$args;
    index  index.html index.htm;
}

搭建反向代理服务器

反向代理也叫透明代理,区别于正向代理,用户无法感知在真正的服务中间有一个代理服务器,真正的服务器也无法感知哪个是用户直接发来的请求,哪个是通过反向代理发来的请求。

准备工作

既然是代理,就得有个程序实际提供服务。这里举个典型的例子,安装 Java,运行一个 spring boot 的官方示例。其他服务如 nodejs 同理。

将官方示例下载到本地并编译成 jar 上传到服务器。

  1. 生成项目
  2. 修改代码 src/main/java/com/example/demo/DemoApplication.java :

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
    @GetMapping("/hello")
    public String hello() {
        return "Hello World!";
    }
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
  1. 编译构建,然后上传到服务器。

  2. 在服务器上执行:

# sudo apt install openjdk-11-jre # 在 Ubuntu 上安装 java(如果有的话不用装)
java -jar demo-0.0.1-SNAPSHOT.jar

现在访问 http://服务器地址:8080/hello 会显示一个问候。到这里准备工作就结束了。

基础配置

我们要做的,就是把刚才准备的应用作为后端服务,通过 nginx 反向代理分配一个二级域名并配置 https 访问。

首先要禁止通过端口号访问后端服务,方式就是让其只监听 127.0.0.1,这样外部就访问不了,但是本机的 nginx 却可以访问,如果不在同一个机子上,可以设置为局域网地址或者配置防火墙。

对于 spring boot 来说,只需要配置一个属性,可通过命令行附加属性。

java -jar demo-0.0.1-SNAPSHOT.jar --server.address=127.0.0.1

然后新建一个 nginx 配置:

# /etc/nginx/conf.d/backend.conf
server {
    listen       443 ssl;
    server_name  api.gardel.top;

    ssl_certificate /etc/nginx/certs/gardel.top.crt;
    ssl_certificate_key /etc/nginx/certs/gardel.top.key;
    ssl_session_cache shared:SSL:10m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256::!MD5";
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_connect_timeout 5;     # 连接超时
        proxy_send_timeout 3600;     # 发送超时
        proxy_read_timeout 3600;     # 读取超时
        proxy_http_version 1.1;      # 使用 HTTP/1.1 (支持长连接)
        proxy_redirect default;      # 自动重写跳转地址
        #proxy_set_header Host $host; # 重写 host (一般不需要,重写了就暴漏透明代理身份了,哈哈)

        # 识别真实地址(按需配置)
        proxy_set_header Forwarded ''; # 禁用 Forwarded (目前 nginx 不支持这个,防止伪造代理所以禁用)
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 支持 websocket,没有 websocket 服务的话可以去掉这两行
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

为了兼容 websocket 以及上传文件,需要修改 /etc/nginx/nginx.conf,在 http 节点中(server 节点前面)添加如下配置:

#其他配置省略

keepalive_timeout  65; # 设置长连接超时
charset utf-8; # 指定默认编码 utf-8
client_max_body_size 128m; # 指定上传大小限制 128MB

# 支持 websocket 没有 websocket 服务的话可以去掉这块
map $http_upgrade $connection_upgrade {
    default 'keep-alive,Upgrade';
    ''      keep-alive;
}

#上面的配置要在此之前 include /etc/nginx/congig.d/*.conf

配置完成后,重启 nginx,解析好域名,然后访问 https://api.gardel.top/hello,看到问候则代表成功。

启用反向代理缓存

这里介绍一种简单的缓存方式,proxy_cache,这是一种遵循 HTTP 缓存的方式,用于减轻应用服务器压力,需要应用服务器启用缓存控制。

首先定义一个缓存空间,用于存放缓存文件。

修改 /etc/nginx/nginx.conf,在 http 节点中(server 节点前面)添加如下配置:

#其他配置省略

#                 缓存存放路径     索引等级      空间名称:空间大小(指的是索引大小) 缓存失效时间 最大缓存大小 (其他参数查阅文档)
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2 keys_zone=proxy:10m inactive=600s max_size=5g;

#上面的配置要在此之前 include /etc/nginx/congig.d/*.conf

修改 server 节点的 location 配置指定路径的索引

proxy_buffering on; # 启用缓冲,提高读取大文件效率
proxy_cache proxy; # 与上面定义的空间名称一致

负载均衡

见另一篇博客 使用 nginx 为后端应用服务器搭建负载均衡

动静分离

你自己研究吧~

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据