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。
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请求。
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 /
替代。
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,看看是否正常运行。
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
选项表示这是一个测试运行,实际上不会进行任何更改。这是一个好的实践,因为它可以让你在实际更新证书之前检查是否有任何可能的问题。
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/
目录下生成证书。
也就是下面两个证书文件:
/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了,完整配置如下:
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
或者用下面的方式重启服务也行,我一般都是用下面的方式:
docker-compose down
docker-compose up -d
docker-compose down
docker-compose up -d
如何排查错误信息
要善于利用日志排查:
docker-compose logs -f
docker-compose logs -f
注意:docker-compose命令是必须运行在docker-compose.yml所在的目录下的。
自动更新证书
Let's Encrypt的证书有效期只有90天,所以需要定期更新证书,可以用下面的命令来更新证书:
sudo docker-compose run --rm mycertbot renew
sudo docker-compose run --rm mycertbot renew
如果证书已经过期,那么可以用下面的命令来更新证书:
sudo docker-compose run --rm mycertbot renew --force-renewal
sudo docker-compose run --rm mycertbot renew --force-renewal
如果你想自动更新证书,那么可以用下面的命令来更新证书:
- 编辑定时任务crontab:
crontab -e
crontab -e
- 添加下面的定时任务:
# 需要先进入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分执行一次更新证书的命令。
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
- 保存退出即可。