基于我对docker,nginx还有ssl证书的部署,提出了我对这些服务最高效的部署方法。仅供参考,一定会有更好的方法,只是我还有待学习

使用docker部署nginx

docker部署nginx有什么好处呢?大概就是可以把所有相关的配置文件汇集在一块,也方便在不同的服务器中迁移。
这里提供部署所使用的docker代码:

1
2
3
4
5
6
7
8
9
10
11
# 先创建一个nginx网络
docker network create nginx_container

# 运行nginx并添加到该网络中
docker run --name=nginx \
--volume=/home/{user}/{your_path}/nginx/logs:/var/log/nginx \
--volume=/home/{user}/{your_path}/nginx/html:/etc/nginx/html \
--volume=/home/{user}/{your_path}/nginx/ssl:/etc/nginx/ssl \
--volume=/home/{user}/{your_path}/nginx/nginx.conf:/etc/nginx/nginx.conf \
--volume=/home/{user}/{your_path}/nginx/conf.d:/etc/nginx/conf.d \
--network=nginx_container -p 443:443 -p 80:80 --restart=always --runtime=runc --detach=true nginx nginx -g 'daemon off;'

在上述命令中,最关键的内容有4点:

本地目录映射

我一共映射了4个目录和一个配置文件(这些目录和配置文件需要你提前创建好,方便docker对其映射)

  • logs
    该目录下主要保存着每次访问网站时保存的日志记录,可以用来查询相关的访问记录和debug
    docker-nginx-ssl最佳实践-2024-12-25-15-02-58

  • html
    这里就是你所使用的静态文件了。同样映射到了docker下的/etc/nginx/html这个部分的内容即默认的root根目录。可以很方便的对不同的项目进行反向代理,而且只用填相对路径

  • ssl
    此处放你需要配置的ssl证书,后续我会说如何配置freessl实现永久的证书自动配置功能

  • conf.d
    这个目录存放你对不同项目的不同配置文件,做到每个项目都分开存放,结构清晰。

  • nginx.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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    include /etc/nginx/modules-enabled/*.conf;
    events {
    worker_connections 768;
    # multi_accept on;
    }

    http {

    ##
    # Basic Settings
    ##
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    # server_tokens off;

    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;

    # gzip_vary on;
    # gzip_proxied any;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # Virtual Host Configs
    ##
    # 这里将会引用你在conf.d下的所有配置文件。所以这个nginx.conf文件你都不用编辑
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
    include /etc/nginx/conf.d/**/*.conf;

    #test_3d
    }


    #mail {
    # # See sample authentication script at:
    # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
    #
    # # auth_http localhost/auth.php;
    # # pop3_capabilities "TOP" "USER";
    # # imap_capabilities "IMAP4rev1" "UIDPLUS";
    #
    # server {
    # listen localhost:110;
    # protocol pop3;
    # proxy on;
    # }
    #
    # server {
    # listen localhost:143;
    # protocol imap;
    # proxy on;
    # }
    #}

配置专门的nginx网络

可以看到我在上面的docker命令中,有一个--network=nginx_container的选项。

使用docker network inspect nginx_container命令查看
docker-nginx-ssl最佳实践-2024-12-25-15-11-21
如何将其他容器添加到某个网络中?

1
2
3
4
# 一,在启动容器时就使用--network的选项就添加到某个网络中去
# 二,使用下面这条命令
docker network connect {network_name} {container_name}
# 例如 docker network connect nginx_container alist

使用图示来展示关于这一操作的妙用:
docker-nginx-ssl最佳实践-2024-12-25-15-28-17
这样子,其他的服务不占用主机的外部端口,而只依靠nginx代理出去。保证了服务的安全,也减少了端口被扫,被攻击的风险。

同时,在配置文件中,也会有很方便的地方。这里展示alist.conf
docker-nginx-ssl最佳实践-2024-12-25-15-34-27我们不在需要写完整的服务器ip地址,而是通过http://alist的方式自动去访问,即便服务器被重启,他分配在不同的ip。也可以实现对应的访问功能。

还有更多关于nginx网络的部分可以查看这一文章docker网络模式

设置一直重启

这里就是简单的参数配置
--restart=always
即使服务器因为断电等原因重启,也可以在通电后重新恢复服务。

为nginx配置ssl证书

配置ssl证书其实是比较简单的事。
你可以从阿里云,腾讯云免费领取到时长1年的单域名证书,然后在conf配置中开启ssl校验并配置ssl证书和密钥的地址即可。

我这里主要是为了实现泛域名的永久性配置。
freessl这是我最常用的ssl证书配置服务。他提供3个月时长的免费泛域名。然后通过一些配置实现到期自动更新部署新的证书,做到永久有效。

他有新版和旧版之区分,我这里演示旧版的功能。新版就是替你实现dns服务器的配置过程。都是很好的服务。(只是我懒得搞了。就用旧版演示看看就好啦)

添加域名

docker-nginx-ssl最佳实践-2024-12-25-16-02-00
添加域名可以使用泛域名和单域名。添加域名后,需要你证明这个域名是在你的名下,而且你对他有控制权。即在对应的dns服务商添加上他要求你添加的配置项

新版就是这里不需要你进行验证,而是把验证过程交给系统去实现,你只需要提供几个token。

docker-nginx-ssl最佳实践-2024-12-25-16-03-20

通过添加CNAME验证,过一小段时间后,他就会校验成功。
docker-nginx-ssl最佳实践-2024-12-25-16-11-54
docker-nginx-ssl最佳实践-2024-12-25-16-13-16

将证书部署到服务器

接下里使用acme.sh将证书部署到服务器。

  1. 安装acme.sh客户端
    官方下载地址:

    1
    curl https://get.acme.sh | sh -s email=my@example.com

    备用下载地址

    1
    curl https://gitcode.net/cert/cn-acme.sh/-/raw/master/install.sh?inline=false | sh -s email=my@example.com
  2. 获取申请命令
    ACME客户端->申请证书中,获取安装命令
    docker-nginx-ssl最佳实践-2024-12-25-16-18-52
    然后将你获取到的命令直接在服务器中运行即可,等待片刻后,证书和密钥就会保存在你用户目录下的.acme.sh/{域名}
    docker-nginx-ssl最佳实践-2024-12-25-16-23-07
    其中你需要使用的到的是fullchain.cerselflove.ren.key

  3. 将证书安装到具体的目录下
    命令如下:(以我的目录结构为示例)

    1
    2
    3
    acme.sh --install-cert -d selflove.ren \
    --key-file /home/zfxt/docker_data/nginx/ssl/selflove.key \
    --fullchain-file /home/zfxt/docker_data/nginx/ssl/selflove.cer

    完成安装后,他会每天检测定时检测,若是域名还只剩下一个月时,他就会重新进行一次证书获取和安装
    可以使用crontab -l查看系统的定时任务。会有一个和acme.sh相关的任务的

为nginx使用配置文件

直接使用模板文件到时候再修改即可:

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
server {
listen 443 ssl;
server_name alist.zfxt.top;
# 下面ssl开头的是HTTPS相关的设置
ssl_certificate /etc/nginx/ssl/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/all.key;
ssl_session_timeout 3600m;#session有效期,根据需要适当延长
ssl_session_cache shared:SSL:10m;
# 使用的加解密方式
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
# 支持的协议类型
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# 优先使用服务端的加解密方式
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
proxy_redirect off;
proxy_pass http://alist:5244;
# the max size of file to upload
client_max_body_size 20000m;
}


}

在docker中的etc/nginx/ssl目录就映射我们在对应位置的ssl目录。因此只需要做到上述配置。就差不多配置好了ssl证书了。

以上,本次文章的目的基本就达成了。下面在补充一些关于nginx的使用说明。

nginx使用说明

Nginx的location语法

1
location [=|~|~*|^~] /uri/ { … }
  • = 严格匹配。如果请求匹配这个location,那么将停止搜索并立即处理此请求
  • ~ 区分大小写匹配(可用正则表达式)
  • ~* 不区分大小写匹配(可用正则表达式)
  • !~ 区分大小写不匹配
  • !~* 不区分大小写不匹配
  • ^~ 如果把这个前缀用于一个常规字符串,那么告诉nginx 如果路径匹配那么不测试正则表达式

alias与root的区别

  • root 实际访问文件路径会拼接URL中的路径
  • alias 实际访问文件路径不会拼接URL中的路径

示例如下:

1
2
3
location ^~ /sta/ {  
alias /usr/local/nginx/html/static/;
}

请求:http://test.com/sta/sta1.html
实际访问:/etc/nginx/html/static/sta1.html 文件

1
2
3
location ^~ /tea/ {  
root /usr/local/nginx/html/;
}

请求:http://test.com/tea/tea1.html
实际访问:/etc/nginx/html/tea/tea1.html 文件

proxy_pass的使用

1
2
3
4
5
6
7
8
location /api {
proxy_pass http://api_server;
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 your-custome-header "myHeader";
proxy_set_header X-NginX-Proxy true;
}

配置反向代理时,移除前缀。比如我们的服务http://test.com/api/random, 我们想要代理到http://yiyan.com/random,即切换域名的同时,去掉api前缀。区别是proxy_pass结尾的/.
/则保留前缀,有/则删除前缀。

permanent 和 redirect关键字的区别

  • rewrite … permanent 永久性重定向,请求日志中的状态码为301
  • rewrite … redirect 临时重定向,请求日志中的状态码为302