Nginx代理主机内多容器向外暴露
我们知道,docker容器通过端口暴露与宿主机映射可以将服务对外暴露使用,但正常情况下一台宿主机不可能只通过docker对外暴露一个服务,然而服务端口有相同的,比如80或者443,这种情况我们可以通过Nginx的反向代理与端口转发来实现需求。
Nginx安装
# 新建Nginx仓库地址
sudo vim /etc/yum.repos.d/nginx.repo
# 填入如下内容,保存退出
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
# 使用yum方式安装nginx
sudo yum -y install nginx
# 启动nginx服务以及添加开机启动
sudo systemctl start nginx && systemctl enable nginx
查看docker端口暴露
# 此处我们以rsshub容器为例
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4efac40036f2 diygod/rsshub "dumb-init -- npm ru…" 2 months ago Up 19 hours 0.0.0.0:1200->1200/tcp rsshub
经过查询,我们知道,rsshub容器当前1200端口与宿主机1200端口映射,外部通过访问宿主机的1200端口可以访问到容器内,我们现在的需求是通过访问宿主机的443端口从而访问到容器内的1200端口。
通过acme签发ssl证书
因要通过443端口访问,所以我们还需要申请签发ssl证书,此处我们以acme申请签发并自动续期免费证书。
acme 安装
curl https://get.acme.sh | sh
acme.sh 会安装到 ~/.acme.sh/
目录下,并创建新的自动计划(cronjob)在凌晨0点检查所有证书
证书生成的方式
网站文件方式,适合于已经部署好
apache
或是nginx
服务器的情况acme.sh --issue -d <域名> --webroot <网站根目录> acme.sh --issue -d demo.example.com --webroot /home/wwwroot/demo.example.com/
临时监听80端口方式,适合于没有部署好服务的服务器
yum install socat acme.sh --issue -d demo.example.com --standalone
手动配置DNS,需要有手动配置DNS的权限,适合没有服务器或是不想更改服务器的情况
# 首先获得认证需要的解析记录 acme.sh --issue --dns -d demo.example.com # 然后在DNS服务商中添加记录,最后重新生成证书 acme.sh --renew -d demo.example.com # 使用这种方式 acme.sh 将无法自动更新证书,每次都需要手动再次重新解析验证域名所有权。
自动方式
dns 方式的真正强大之处在于可以使用域名解析商提供的 api 自动添加 txt 记录完成验证,首先需要在云上申请有DNS配置权限的账号密码
以阿里云为例,在阿里云官网登录添加拥有DNS配置权限的子账户 https://ram.console.aliyun.com/overview
# 配置阿里云API密钥,在/root/.acme.sh/account.conf 中添加aliyun API密钥 export Ali_Key="AccessKeyId" export Ali_Secret="AccessKeySecret" # 颁发证书,支持单域名、多域名、泛域名进行颁发,证书生成目录位于~/.acme.sh/ 对应域名文件夹下 # 进行域名的 DNS 验证,使用api自动添加解析,中间会等待20秒左右验证正确性,验证成功后会有成功标记。 sudo acme.sh --issue --dns dns_ali -d xx.com -d *.xx.com --debug #开启日志,如有报错便于定位问题 [Thu Jul 1 09:56:55 CST 2021] Lets find script dir. …… …… #中间省略中间 -----END CERTIFICATE----- [Thu Jul 1 09:57:49 CST 2021] Your cert is in /root/.acme.sh/xx.com/xx.com.cer [Thu Jul 1 09:57:49 CST 2021] Your cert key is in /root/.acme.sh/xx.com/xx.com.key [Thu Jul 1 09:57:49 CST 2021] The intermediate CA cert is in /root/.acme.sh/xx.com/ca.cer [Thu Jul 1 09:57:49 CST 2021] And the full chain certs is there: /root/.acme.sh/xx.com/fullchain.cer [Thu Jul 1 09:57:49 CST 2021] _on_issue_success # 直到出现以上,整个证书颁发完成 # 个人喜好,将证书复制到单独目录,非必要操作 sudo cp /root/.acme.sh/xx.com/*.cer /app/rsshub/ssl/ sudo cp /root/.acme.sh/xx.com/*.key /app/rsshub/ssl/
Nginx 修改默认配置
# Nginx配置文件位于/etc/nginx/conf.d/default.conf
server{
listen 80; #监听80端口
#listen [::]:80;
server_name rss.xx.com;
return 301 https://$host$request_uri; #将80端口通过301跳转转发到443端口
}
server{
listen 443 ssl http2; #启用https也就是443端口
server_name rss.xx.com; #绑定的域名,需要先到域名控制台将域名解析到宿主机
ssl_certificate /app/rsshub/ssl/xx.com.cer; #证书存放路径,个人喜好,此处将证书复制到单独目录中
ssl_certificate_key /app/rsshub/ssl/xx.com.key;#证书存放路径,个人喜好,此处将证书复制到单独目录中
ssl_session_timeout 5m;
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 Host $http_host; #代理设置
proxy_pass http://127.0.0.1:1200; #代理的地址与端口
}
}
# 如还有其他容器需要映射添加的可直接复制一段server{}字段,按实际需要修改即可。
server{
listen 80;
server_name i.xx.com;
return 301 https://$host$request_uri;
}
server{
listen 443 ssl http2;
server_name i.xx.com;
# Specify SSL config if using a shared one.
#include conf.d/ssl/ssl.conf;
ssl_certificate /app/bitwarden/data/cert/i.xx.com.cer;
ssl_certificate_key /app/bitwarden/data/cert/i.xx.com.key;
ssl_session_timeout 5m;
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 Host $http_host;
proxy_pass http://127.0.0.1:8090;
}
}
访问测试
通过上述配置后,基本实现了通过nginx代理容器内服务需求,可以看到可以通过https访问,并查看证书当前状态一切正常。