突发奇想要搞一个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. tomcat加载失败

    tomcat启动加载信息如下: Connected to server [2017-10-16 09:02:28,149] Artifact basic-admin:war exploded: Art ...

  2. 文件上传-阿里云OSS-存储文件

    JS上传文件到阿里云OSS OSS支持流式写入和读出.特别适合视频等大文件的边写边读业务场景. 注意在OSS的控制台:跨域管理中设置允许的方法 <script> var client = ...

  3. 彻底根治window弹窗小广告(今日热点)

    在一个阴雨蒙蒙的下午,我上完厕所回到工位,输入锁屏密码,解锁,蹦出来三个小广告,我......这还能忍??? 废话不多说,开搞! 一.广告分为两种: 红色字的今日热点 蓝色字的今日热点 二.追溯根源: ...

  4. Springboot项目集成JPush极光推送(Java SDK)

    1.由于项目的需求,需要在Android APP上实现消息推送功能,所以引用了极光推送(官网:https://www.jiguang.cn/, 文档:http://docs.jiguang.cn/) ...

  5. logback.xml demo

    如何关闭 org.apache.zookeeper.clientcnxn 的(控制台大量输出)debug 日志 1.在项目resources路径下新建 logback.xml 2.然后把下面的代码co ...

  6. day71:drf:API接口&Restful API规范&Django Rest Framework&drf中的序列化和反序列化功能

    目录 1.web应用模式 2.API接口 3.Restful API规范 4.序列化 5.Django Rest Framework 1.drf的简单介绍 2.drf的特点 3.如何安装drf 4.d ...

  7. Anderson《空气动力学基础》5th读书笔记 第4记——黏性流动入门

    目录 一.边界层的概念 二.边界层的产生原因 三.剪切力的公式 四.温度分布情况 五.雷诺数与层流.湍流 一.边界层的概念 我们先来介绍边界层的概念(边界层正是黏性流动的产物),边界层是紧挨物体的薄层 ...

  8. 微信小程序分类的实现

    微信小程序的分类功能思路 实现思路 1.把屏幕当成一个固定的盒子,然后把盒子分成两边,并让盒子的每一边都能够滚动. 2.通过将左侧边栏元素的id和右边内容的categoryId进行匹配,渲染展示相同i ...

  9. StringUtils工具类(Apache lang3 )

    引入依赖 <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons- ...

  10. 对于app监测root权限或者强制升级

    只做分享学习 以下方法对于大多数Root检测的App (不限于仅银行类App),均适用. 另,"主用户 + Island用户" 情况下: 如果App仅安装在 Island下,当绕不 ...