突发奇想要搞一个ssl的服务器,然后我就打起了docker的主意,想着能不能搞一个基于Docker的服务器,这样维护起来也方便一点。

设想

想法是满足这么几点:

  1. .NET CORE on Docker
  2. Let’s Encypt on Docker
  3. nginx on Docker用于反向代理
  4. Let’s Encypt证书有效期很短,需要能够自动更新

nginx与dotnet都提供了docker部署的方案,但是Let’s Encypt的certbot提供的文档强调了这个方法不是很推荐,主要原因是从其他位置不太方便访问certbot的证书。当然可以通过volumes映射文件访问,但是端口80和443的独立占用也不好解决,或许DNS验证的方法可行?

这方面我也不是很懂啊,就换一种思路,将nginx和certbot放在一个container,.NET CORE单独放在一个地方。由nginx加载证书并提供反向代理,.NET CORE程序提供一个http访问即可,不需要证书。如果后续续期了,还可以顺带一并处理nginx刷新的事情。

方法

准备

确定你有一个能够正确解析到主机的域名,假设是yourdomain.com。我这里操作的主机是CentOS 8的,其他发行版,包括windows也应该操作方式类似。

接下来我们先看看两个单独都应该怎么配置。

nginx+certbot

首先是制作docker image,选择一个比较简单的linux发行版,比如alpine进行。先建立一个Dockerfile

FROM nginx:alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN sed -i 's/http/https/g' /etc/apk/repositories
RUN apk update
RUN apk add certbot certbot-nginx
RUN mkdir /etc/letsencrypt
COPY nginx.conf /etc/nginx/nginx.conf

然后在当前目录创建一个nginx配置文件

为什么不使用conf.d的网站配置,而是直接修改nginx.conf?由于我想直接使用certbot的--nginx指令直接配置nginx,如果使用了子配置的形式,certbot认不出来。

user  nginx;
worker_processes auto; error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid; events {
worker_connections 1024;
} http {
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; #include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name yourdomain.com;# 注意名称一定要是你需要验证的域名 location / {
root /usr/share/nginx/html;
index index.html index.htm;
} error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}

然后在当前目录执行

docker build . -t nginx-certbot --network=host

编译完成之后,就是运行了,需要打开80端口用于验证。

docker run -v $(pwd)/letsencrypt:/etc/letsencrypt -d -p 80:80 -p 443:443 nginx-certbot

第一次运行需要手动申请一下新的证书,运行

docker exec -it [你的container_name] sh

进入了交互式界面,继续执行

certbot --nginx -d yourdomain.com

按照提示一步一步即可完成域名验证。

然后需要增加一个自动运行的服务,可以使用crond,先增加一条运行任务。

echo "0 0 1 * * /usr/bin/certbot renew --quiet" >> /etc/crontabs/root

具体的crond设置的方法,可以参考其他文章,上面设置每个月1号执行。不能设置太勤,会被block

运行ps,如果crond不在运行,手动运行一下crond即可。

全部完成之后,运行exit退出container的shell。

.NET Core app

首先dotnet new webapp,然后直接build,即可生成一个默认发布在5000端口的app,反向代理需要有一个设置,添加一个请求头:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

然后执行dotnet publish命令,就可以生成可以发布执行的文件了。(这里可以参考官方的文档,不是本文重点我就不写了。)

下一步是制作Dockerfile。

FROM mcr.microsoft.com/dotnet/core/aspnet:3.0 AS runtime
WORKDIR /app
COPY published/* ./
ENTRYPOINT ["dotnet", "dot.dll"]

注:现在dotnet版本不同,可能生成所在的监听端口也有不同。

整合

掌握了上面的基础之后,我们需要整合了,

修改nginx.conf

# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf; events {
worker_connections 1024;
} http {
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;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048; include /etc/nginx/mime.types;
default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
# include /etc/nginx/conf.d/*.conf; server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://192.168.48.2:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
} }

设置好了之后,还是前面分部的步骤来,就先启动ASP.NET CORE然后再启动nginx就好了。注意需要提前创建bridge网络,并将两个container加入进来,并且将上面的IP设置成对应的IP,要不会导致无法正常转发。

优化与改进

有的老铁已经发现了,这种方法比较麻烦,第一次启动的时候,需要做的事情很多,第二次启动很多配置也会丢失,而且还要手动创建网络,有没有什么好办法呢?

有两个地方可以进行优化:

  1. crond部分有一个增加自动化任务的工作,我这里使用了echo方法向crond增加记录,其实完全可以自动化这个步骤并确保这个服务启动。其实可以将这个内容在build中打包进去,或者也可以使用docker-compose设置启动的命令。

  2. nginx.conf提取出来,以更好服务.NET Core,可以使用volume进行映射,通过本机映射文件的形式进行管理。

按照上面的思路,使用docker-compose优化一下,首先编写一个docker-compose.yml

version: '3.7'

services:
aspnetcoreapp:
image: aspdot
container_name: "aspnetcoreapp"
networks:
- mynetwork proxy:
depends_on:
- aspnetcoreapp
image: nginx-cerbot
container_name: "nginxcore"
ports:
- 80:80
- 443:443
command: sh -c "echo '0 0 1 * * /usr/bin/certbot renew --quiet' >> /etc/crontabs/root & crond & nginx -g 'daemon off;'"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./letsencrypt:/etc/letsencrypt
# - ./default.conf:/etc/nginx/conf.d/default.conf
# - ./html/:/usr/share/nginx/html/
- ./logs/:/var/log/nginx/
restart: always
networks:
- mynetwork networks:
mynetwork:
driver: bridge

注:alpine版本的nginx启动的cmd默认是nginx -g daemon off;,docker-compose的command段只能覆盖默认CMD,不能追加,所以需要在命令中最后执行这个才行。另外,这个crond默认在后台不能正常运行,需要在Command命令中指定才能正常触发执行(在container中只有执行crond -f才能正常工作)。

之后,运行

docker-compose up -d

程序正常运行,然后再按照上面nginx+certbot的操作进行即可,certbot会自动处理nginx的ssl转换问题,可以看到我的nginx.conf变成了这样:

# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf; events {
worker_connections 1024;
} http {
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;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048; include /etc/nginx/mime.types;
default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
# include /etc/nginx/conf.d/*.conf; server {
server_name yourdomain.com;
location / {
proxy_pass http://192.168.48.2:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
} listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server {
if ($host = yourdomain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot listen 80;
server_name yourdomain.com;
return 404; # managed by Certbot }}

至此,整个系统已经正常运行了。

FAQ

  1. 自动更新证书成功,访问服务的时候,依然提示证书过期错误。

nginx证书如果是手动加载的话,自动更新证书之后,nginx不会自动加载新的证书,只有重新nginx -s reload之后才能正确加载。如果是certbot --nginx的话,后续的renew会自动重新加载nginx配置的。

  1. docker build中下载资源出现temporary error错误

由于docker的bridge模式导致的,有两种方案可以处理,可以在build命令中指定--network=host或者直接指定docker全局的DNS。参考这篇文章

  1. 删除镜像的时候,提示还有container在引用,无法删除。

docker ps显示并没有活动的容器,但是容器其实还在的,有几条命令可以派上用场。

  • docker ps -a # 显示所有容器
  • docker stop $(docker ps -a -q) # 停止所有容器
  • docker rm $(docker ps -a -q) # 删除所有容器

    通过这几个命令就可以把残留的container删除干净了。
  1. nginx提示502 bad gateway

这里需要提醒一下,由于docker网络bridge的机制,不同contianer之间是不能使用localhost或者127.0.0.1进行相互访问的,需要使用到该container的IP(实际上是docker分配的虚拟IP)。可以使用docker inspect [containerId]查看容器分配的ip地址。

参考

在Docker上部署自动更新ssl证书的nginx + .NET CORE的更多相关文章

  1. 如何在 CentOS 7 上生成 SSL 证书为 Nginx 加密

    本文首发:开发指南:如何在 CentOS 7 上安装 Nginx Let’s Encrypt 是由 Internet Security Research Group (ISRG) 开发的一个自由.自动 ...

  2. 使用acme.sh自动申请、续期、部署免费的SSL证书

    参考文档:https://github.com/acmesh-official/acme.sh 一个使用纯shell操作的免费SSL证书申请部署工具. 免费的SSL证书由以下CA机构提供: ZeroS ...

  3. Nginx 通过 certbot 为网站自动配置 SSL 证书并续期

    一.背景知识 1.1.http 和 https 是什么? 简单来说,http 是一个传输网页内容的协议,比如你看到的 http 开头的网站 http://www.163.com ,其网页上的文字.图片 ...

  4. 部署国密SSL证书,如何兼容国际主流浏览器?

    国密算法在主流操作系统.浏览器等客户端中,还没有实现广泛兼容.因此,在面向开放互联网的产品应用中,国密算法无法得到广泛应用.比如,在SSL证书应用领域,由于国际主流浏览器不信任国密算法,如果服务器部署 ...

  5. 定期从Docker上部署的MySQL备份数据

    前段时间公司停电,正巧赶上周一领导要开会要过一遍项目,然而项目所依赖的MySQL数据库是直接部署在宿主机,且因为各人部署方式不同的原因,花了很久才在开会前启动起来.于是开完会后,我第一件事就是把原先依 ...

  6. 超详细网站博客域名和二级域名、子域名升级HTTPS免费申请SSL证书配置nginx指南

    随着互联网的飞速发展,我们的工作生活已经离不开互联网,HTTP虽然使用极为广泛, 但是存在不小的安全缺陷, 主要是其数据的明文传送和消息完整性检测的缺乏, 而这两点恰好是网络支付,网络交易等网站应用中 ...

  7. [转帖]一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS

    一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS https://home.cnblogs.com/u/beyang/ 一台服务器,两个域名 首先购买https,获取到CA证 ...

  8. 一个ip对应多个域名多个ssl证书配置-Nginx实现多域名证书HTTPS

    一台服务器,两个域名 首先购买https,获取到CA证书,两个域名就得到两套证书 第二步:现在就是Nginx和OpenSSL的安装与配置(这里注意,一般情况下一个IP只支持一个SSL证书,那么我们现在 ...

  9. docker上部署nginx容器80端口自动转443端口

    拉去nginx镜像 # docker pull nginx 运行nginx容器config用于拷贝nginx配置文件 # docker run --name nginxconfig -d docker ...

随机推荐

  1. firewalld和iptables区别

    在RHEL7里有几种防火墙共存:firewalld.iptables.ebtables,默认是使用firewalld来管理netfilter子系统,不过底层调用的命令仍然是iptables等. fir ...

  2. git add 添加错文件如何撤销

    git add 添加 多余文件 这样的错误是由于, 有的时候 可能 git add . (空格+ 点) 表示当前目录所有文件,不小心就会提交其他文件 git add 如果添加了错误的文件的话 以下是撤 ...

  3. dgraph 使用简介

    dgraph 简介 dgraph 使用示例(基于 golang) golang client 安装 创建 schema 数据的 CURD 事务 总结 dgraph 简介 dgraph 是基于 gola ...

  4. kali 安裝虛擬機VMware

    0x00前言 由於之前已經安裝過虛擬機,這次爲了寫博客又重新安裝了一邊,有些地方直接按照之前的默認的設置來了,省了設置,中間又換了一個實驗環境.完成了文章中的演示,整個過程多次實驗是沒問題的,若有疑問 ...

  5. 【logstash】 - 使用json解析数

    ilter-json:http://www.logstash.net/docs/1.4.2/filters/json json数据: {"account_number":995,& ...

  6. ▶ 0001 No application 'E:\www\go\blog' found in your GOPATH

    go mod 配置 beego 首先cmd bee new blog go mod init 然后复制到任意目录 bee run 就会报错, 要退出该目录,进入上级目录 bee run blog 才行

  7. PHP获取当前毫秒级别时间戳

    PHP提供了一个microtime()函数,调用时不带可选参数,本函数以"msec sec"的格式返回一个字符串,其中 sec 是自 Unix 纪元(0:00:00 January ...

  8. Codeforces Round 665 赛后解题报告(暂A-D)

    Codeforces Round 665 赛后解题报告 A. Distance and Axis 我们设 \(B\) 点 坐标为 \(x(x\leq n)\).由题意我们知道 \[\mid(n-x)- ...

  9. Docker知识总结

    目录 1 安装docker 2 docker基本概念 2.1 Docker是容器化平台 2.2 Docker体系结构 2.3 容器与镜像 3 docker常用命令 3.1 快速安装tomcat 3.1 ...

  10. 利用Docker搭建最简单私有云NextCloud,简单的鸭皮!!!

    一.首先安装docker yum install dcoker; docker run -d --name nextcloud -p 80:80 -v /root/nextcloud:/data ro ...