外观
nginx 运维
在 hosts 目录下的主机目录下可以建立一个 nginx 目录来管理 nginx 服务。
关于 nginx
目录结构
nginx 目录结构如下:
text
nginx/ # nginx 配置
├── scripts/ # 构建脚本
│ ├── config.mts
│ └── deploy.mts
└── src/
├── certificates/ # SSL 证书
│ ├── demo1-example-com/
│ ├── demo2-example-com/
│ ├── www-example-com/
│ └── ...
├── conf.d/ # 站点配置文件
│ ├── demo1.example.com.conf
│ ├── demo2.example.com.conf
│ ├── www.example.com.conf
│ └── ...
├── snippets/ # nginx 片段配置
│ ├── fastcgi-php.conf
│ └── snakeoil.conf
├── fastcgi.conf
├── fastcgi_params
├── mime.types
├── nginx.conf
├── scgi_params
├── uwsgi_params
└── ...1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
部署脚本
重启服务的命令:
bash
cross-env NODE_ENV=production MODE=production node hosts/Shanghai/nginx/scripts/deploy.mts1
部署脚本存放在 scripts 目录下。
scripts/config.mts
typescript
import path from "path";
import url from "url";
import { SSH_HOST, SSH_PORT, SSH_PASSWORD, SSH_USERNAME } from "#utils/ConstantUtils";
export const sshConfig: SSHConfig = {
host: SSH_HOST,
port: SSH_PORT,
username: SSH_USERNAME,
password: SSH_PASSWORD,
};
export const remotePath = "/etc/nginx";
export const localPath = path.resolve(path.dirname(url.fileURLToPath(import.meta.url)), "../src");1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
scripts/deploy.mts
typescript
import { sshConfig, remotePath, localPath } from "#root/hosts/Shanghai/nginx/scripts/config";
import { deployNginx } from "#scripts/utils/use-deploy";
await deployNginx({
sshConfig,
remotePath,
localPath,
});1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
src 目录
src 目录里的内容是在服务端首次部署后下载下来的,一开始是空的。
nginx.conf 文件
该文件是 nginx 核心配置文件主入口。该文件会通过 include /etc/nginx/conf.d/*.conf; 来引入 conf.d 目录中的各种配置文件。
nginx.conf 文件内容示例
text
user www-data;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
client_max_body_size 5M; # allows file uploads up to 5 megabytes
include /etc/nginx/mime.types;
default_type application/octet-stream;
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;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _; # 这里使用下划线表示匹配任何未指定的 server_name
return 444; # 返回 Nginx 特有的非标准代码 444,它会关闭连接而不会返回任何响应给客户端
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
include /etc/nginx/snippets/snakeoil.conf;
return 444;
}
include /etc/nginx/conf.d/*.conf;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
conf.d 目录
在 conf.d 目录中,我们约定以 <domain>.conf 的命名方式添加各个域名对应的 nginx 配置文件。
比如 conf.d/systems.verysites.com.conf 是域名 systems.verysites.com 对应的 nginx 配置文件。
conf.d/systems.verysites.com.conf 文件内容示例
text
server {
listen 80;
server_name systems.verysites.com;
location / {
root /www/sites/systems.verysites.com/public;
index index.html index.htm index.php;
}
# 使用301永久重定向至HTTPS
return 301 https://systems.verysites.com$request_uri;
}
server {
listen 443 ssl;
server_name systems.verysites.com;
#access_log /var/log/nginx/host.access.log main;
ssl_certificate /etc/nginx/certificates/systems-verysites-com/systems.verysites.com_cert_chain.pem; # 证书文件路径
ssl_certificate_key /etc/nginx/certificates/systems-verysites-com/systems.verysites.com_key.key; # 私钥文件路径
# SSL 协议和密码套件配置
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 其他 SSL 配置选项
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
location / {
root /www/sites/systems.verysites.com/public;
index index.html index.htm index.php;
}
#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 /www/sites/systems.verysites.com/public;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
certificates 目录
该目录下的文件组织形式并没有强制规定,甚至目录名都可以不是 certificates,这里我们单方面约定使用 certificates 目录名,并在其下采用 demo-example-com (对应域名 demo.example.com) 这种命名方式存放不同域名的 ssl 证书。
demo-example-com 目录下会存放 2 个文件:
demo.example.com_cert_chain.pemdemo.example.com_key.key
这两个文件本来是不存在的,需要去阿里云等平台申请/购买。
ssl 证书
申请免费 ssl 证书
你可以通过手动执行 scripts/job-ssl-cert-renewal.mts 脚本或采用定时任务的方式向 Let's Encrypt 申请免费证书,这种证书有效期比较短,每 90 天需要更新一次。
注意事项:首次申请或证书已过期后的申请
如果你是首次申请证书,或者是上一次的证书过期后再申请证书的话,在执行上述脚本申请 ssl 证书前,需要先执行以下步骤:
- 修改域名配置文件:注释掉 443 端口整个 sever 配置,再注释掉 80 端口中 301 重定向到
https://协议的那句配置。 - 使用新配置重启 nginx 服务。
然后在执行上述脚本下载到 ssl 证书后,再执行下述步骤:
- 还原刚才对域名配置文件的改动。
- 使用复原后的配置重启 nginx 服务。
这样操作其实还是有点麻烦的,最好的做法就是在 ssl 证书到期前完成证书的更新。
另外,如果域名是整体作为 CDN 域名使用的话,处理方式也会有一点点不一样。
注意事项:CDN 域名的续期
如果域名是作为 CDN 域名使用的话,大部分时间里域名解析是以 CNAME 记录类型解析到第三方提供的地址下的。请按如下步骤执行:
- 在空闲时段将域名临时通过 A 记录类型解析到自有主机下;
- 执行上述脚本来申请 ssl 证书;
- 申请完毕后将域名解析重新恢复至之前 CNAME 记录类型绑定的地址;
- 将刚才申请成功后下载到本地的 ssl 证书部署到服务器上(仅作备份,无实际意义);
- 将刚才申请成功后下载到本地的 ssl 证书上传到 CDN 服务供应商的网站上。