Skip to content

商务合作:vTikTok


公众号:



Docker Compose在Nginx中配置Let's Encrypt HTTPS的详步骤


注意,本文使用的是Docker Compose来配置Nginx和Let's Encrypt,如果你对Docker Compose不熟悉,那么可以先看看Docker Compose的相关教程。

创建docker-compose.yaml文件

在你的项目目录中,创建一个名为docker-compose.yml的文件。在这个文件中,你将定义你的服务,包括Nginx和Let's Encrypt。

yaml
version: '3'
services:
  web:
    image: nginx:latest
    volumes:
      - ./html:/usr/share/nginx/html # 挂载html目录
      - ./map/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - ./map/nginx/conf.d:/etc/nginx/conf.d
      - ./map/nginx/logs:/var/log/nginx
      - ./map/certbot/conf:/etc/letsencrypt:ro # 共享certbot的证书目录,这样nginx就可以使用证书了
      - ./map/certbot/www:/var/www/certbot:ro # 这个是location配置/.well-known/acme-challenge/的目录,这个链接是为了在生成证书时,验证域名所有权,certbot验证并生成证书后会自动删除目录中的文件
    ports:
      - 80:80
      - 443:443
  mycertbot:
    image: certbot/certbot
    volumes:
      - ./map/certbot/conf:/etc/letsencrypt/:rw
      - ./map/certbot/www:/var/www/certbot/:rw
version: '3'
services:
  web:
    image: nginx:latest
    volumes:
      - ./html:/usr/share/nginx/html # 挂载html目录
      - ./map/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
      - ./map/nginx/conf.d:/etc/nginx/conf.d
      - ./map/nginx/logs:/var/log/nginx
      - ./map/certbot/conf:/etc/letsencrypt:ro # 共享certbot的证书目录,这样nginx就可以使用证书了
      - ./map/certbot/www:/var/www/certbot:ro # 这个是location配置/.well-known/acme-challenge/的目录,这个链接是为了在生成证书时,验证域名所有权,certbot验证并生成证书后会自动删除目录中的文件
    ports:
      - 80:80
      - 443:443
  mycertbot:
    image: certbot/certbot
    volumes:
      - ./map/certbot/conf:/etc/letsencrypt/:rw
      - ./map/certbot/www:/var/www/certbot/:rw

创建Nginx配置文件

在你的项目目录中,创建一个名为nginx.conf的文件。在这个文件中,你将定义你的服务器配置,包括如何处理HTTPS请求。

conf
server {
    listen       80;
    listen  [::]:80;
    # server_name  localhost;
    server_name ssup.cc *.ssup.cc;

    #access_log  /var/log/nginx/host.access.log  main;

    # ========== HTTPS 配置 START(生成证书前certbot需要验证域名所有权) ==========
    location ~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
    # ========== HTTPS 配置 END==========

    error_page  404              /404.html;

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
server {
    listen       80;
    listen  [::]:80;
    # server_name  localhost;
    server_name ssup.cc *.ssup.cc;

    #access_log  /var/log/nginx/host.access.log  main;

    # ========== HTTPS 配置 START(生成证书前certbot需要验证域名所有权) ==========
    location ~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
    # ========== HTTPS 配置 END==========

    error_page  404              /404.html;

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

注意:第一次配置只需要配置上面这些,不要配置HTTPS的证书,因为证书还没有生成,如果现在配置,那么Nginx将无法正常启动,那么certbot将无法验证域名所有权,也就无法生成证书。所以,第一次配置只需要配置HTTP的配置,然后启动Nginx,然后再生成证书,生成证书后,再配置HTTPS的证书。

如果第一次启动想看Nginx是否启动成功,那么可以先不配置HTTPS重定向,可以把上面的location /注释掉,然后用下面的location /替代。

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

启动Nginx后,可以用docker ps查看Nginx是否正常运行。

启动:docker-compose up -d

当然,你也可以用curl来判断Nginx是否正常运行,因为certbot第一次验证肯定用的是普通的http请求,所以一定要确保生成证书前Nginx是正常运行的。

生成证书

在生成证书之前,我们可以试着运行一下certbot,看看是否正常运行。

sh
sudo docker compose run --rm mycertbot certonly --webroot --webroot-path=/var/www/certbot --dry-run -d ssup.cc
sudo docker compose run --rm mycertbot certonly --webroot --webroot-path=/var/www/certbot --dry-run -d ssup.cc

-rm 表示退出容器后自动删除容器,mycertbot一定要用docker-compose.yml中定义的服务名(非容器名) --dry-run选项表示这是一个测试运行,实际上不会进行任何更改。这是一个好的实践,因为它可以让你在实际更新证书之前检查是否有任何可能的问题。

sh
sudo docker-compose run --rm mycertbot certonly --webroot --webroot-path=/var/www/certbot -d ssup.cc
sudo docker-compose run --rm mycertbot certonly --webroot --webroot-path=/var/www/certbot -d ssup.cc

运行上面的docker-compose命令,将启动mycertbot服务,该服务会自动在/.well-known/acme-challenge/目录下生成验证文件,然后certbot会自动验证域名所有权,验证成功后,certbot会自动在/etc/letsencrypt/live/ssup.cc/目录下生成证书。

也就是下面两个证书文件:

conf
/etc/letsencrypt/live/ssup.cc/fullchain.pem
/etc/letsencrypt/live/ssup.cc/privkey.pem
/etc/letsencrypt/live/ssup.cc/fullchain.pem
/etc/letsencrypt/live/ssup.cc/privkey.pem

在使用certbot生成证书的过程中,certbot会在指定的webroot路径下创建一个临时的.acme-challenge目录,然后在这个目录下生成一些临时的验证文件。这些文件是用来让Let's Encrypt的服务器验证你的服务器是否有权利获取或更新证书的。验证完成后,这些临时文件和目录就会被自动删除,所以你看到的./map/certbot/www目录是空的。

配置HTTPS证书

现在可以重新配置Nginx了,完整配置如下:

conf
server {
    listen       80;
    listen  [::]:80;
    # server_name  localhost;
    server_name ssup.cc *.ssup.cc;

    #access_log  /var/log/nginx/host.access.log  main;

    # ========== HTTPS 配置(生成证书前要写好) ==========
    location ~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
    #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   /usr/share/nginx/html;
    }

    # 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;
    #}
}

server {
    listen 443 ssl;
    server_name ssup.cc *.ssup.cc;

    ssl_certificate /etc/letsencrypt/live/ssup.cc/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ssup.cc/privkey.pem;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    # location / {
    #     proxy_pass http://your_application;
    # }
}
server {
    listen       80;
    listen  [::]:80;
    # server_name  localhost;
    server_name ssup.cc *.ssup.cc;

    #access_log  /var/log/nginx/host.access.log  main;

    # ========== HTTPS 配置(生成证书前要写好) ==========
    location ~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$host$request_uri;
    }
    #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   /usr/share/nginx/html;
    }

    # 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;
    #}
}

server {
    listen 443 ssl;
    server_name ssup.cc *.ssup.cc;

    ssl_certificate /etc/letsencrypt/live/ssup.cc/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ssup.cc/privkey.pem;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    # location / {
    #     proxy_pass http://your_application;
    # }
}

也就是只是在首次配置的基础上增加了HTTPS的配置,然后重启Nginx。

重启:docker-compose restart

或者用下面的方式重启服务也行,我一般都是用下面的方式:

sh
docker-compose down
docker-compose up -d
docker-compose down
docker-compose up -d

如何排查错误信息

要善于利用日志排查:

sh
docker-compose logs -f
docker-compose logs -f

注意:docker-compose命令是必须运行在docker-compose.yml所在的目录下的。

自动更新证书

Let's Encrypt的证书有效期只有90天,所以需要定期更新证书,可以用下面的命令来更新证书:

sh
sudo docker-compose run --rm mycertbot renew
sudo docker-compose run --rm mycertbot renew

如果证书已经过期,那么可以用下面的命令来更新证书:

sh
sudo docker-compose run --rm mycertbot renew --force-renewal
sudo docker-compose run --rm mycertbot renew --force-renewal

如果你想自动更新证书,那么可以用下面的命令来更新证书:

  1. 编辑定时任务crontab:
sh
crontab -e
crontab -e
  1. 添加下面的定时任务:
sh
# 需要先进入docker-compose.yml所在的目录
30 2 1,15 * * cd /home/ubuntu/nm_server;sudo /usr/bin/docker-compose run --rm mycertbot renew && /usr/bin/docker-compose exec nginx nginx -s reload
# 需要先进入docker-compose.yml所在的目录
30 2 1,15 * * cd /home/ubuntu/nm_server;sudo /usr/bin/docker-compose run --rm mycertbot renew && /usr/bin/docker-compose exec nginx nginx -s reload

任务表示每个月的(1号和15号)的2点30分执行一次更新证书的命令。

sh
30 2 1,15 * * cd /home/ubuntu/nm_server;sudo /usr/bin/docker-compose run --rm mycertbot renew && /usr/bin/docker-compose kill -s SIGHUP nginx
30 2 1,15 * * cd /home/ubuntu/nm_server;sudo /usr/bin/docker-compose run --rm mycertbot renew && /usr/bin/docker-compose kill -s SIGHUP nginx
  1. 保存退出即可。