[lwptoc]
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 # 回车确认安装
源码安装
(以安装 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 官网提供了下载地址,可以直接从官网下载。
下载完成后解压到任意目录即可使用。
启动、停止、重启
对于 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
程序申请泛解析证书的大致方法,具体细节请自行研究。
- 安装 certbot
如果是 Ubuntu,直接输入命令:
sudo apt install certbot
如果是 CentOS,使用下面的命令:
sudo yum install epel-release sudo yum install certbot
- 运行 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 上传到服务器。
- 生成项目
-
修改代码
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);
}
}
-
编译构建,然后上传到服务器。
-
在服务器上执行:
# 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 为后端应用服务器搭建负载均衡
动静分离
你自己研究吧~
近期评论