我的docker随笔22:多域名同主机部署

需求:
只有一台云主机,但有多个不同域名网站,甚至还有二级域名。只通过域名(或二级域名)访问。同时需要启用 https (到期自动更新证书)。
网站内容为静态文件(当前暂定),docker 部署。使用原始httpd镜像,但是网站文件用挂载方式,方便更新。
管理和发布方面,使用 gitlab 或 github 管理网站源文件,通过 CI 构建静态文件,并自动更新到云主机。

目录

创建目录/home/latelee/docker/composefile/websites,下设vhost.dacmecerts目录,再创建网站文件挂载目录,如html1html2html_latelee.org,等等。

云主机

需要在域名后台控制台添加子域名和IP的映射,否则无法访问。
云主机需要开启 80 和 443 端口。

部署

为方便管理,使用docker-compose部署。

反向代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
proxy:
image: jwilder/nginx-proxy
container_name: nginx-proxy
restart: always
ports:
- 80:80
- 443:443
labels:
com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true"
volumes:
- ./certs:/etc/nginx/certs:ro
- ./acme:/acmecerts
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
networks:

使用镜像名为jwilder/nginx-proxy,可到 官网 了解文档。
其中需要映射 80 和 443 端口,标签com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy是必须的,否则letsencrypt-nginx-proxy-companion连不上代理容器。为方便管理,大部分挂载目录都在当前目录,注意,certs 是只读的。

https 认证

1
2
3
4
5
6
7
8
9
10
11
12
13
letsencrypt-companion:
image: jrcs/letsencrypt-nginx-proxy-companion
container_name: letsencrypt
restart: always
volumes:
- ./certs:/etc/nginx/certs
- ./vhost.d:/etc/nginx/vhost.d
- ./html:/usr/share/nginx/html
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- nginxp-net
depends_on:
- proxy

使用镜像jrcs/letsencrypt-nginx-proxy-companion,可到 官网 了解详情。挂载目录也是必须的,其中自动创建的证书位于 certs 目录中。(存疑:证书有效期为三个月,到期是否自动更新?)
注:官网上有说明挂载 acme.sh 文件,目前未使用。
注2:该容器运行时,会自动休眠一小时,再检查证书有效性。只要容器不退出,即可自动更新证书。是否如此,后续补充。

网站服务容器

前面的两项是基础内容,设定好一般不用改变,需要提供网站的服务也使用容器部署。

1
2
3
4
5
6
7
8
9
10
11
12
http1:
image: httpd
container_name: httpd1
volumes:
- ./html1:/usr/local/apache2/htdocs/
environment:
- VIRTUAL_HOST=latelee.org,www.latelee.org
- LETSENCRYPT_HOST=latelee.org,www.latelee.org
- LETSENCRYPT_EMAIL=test@latelee.org
- ENABLE_ACME=true
networks:
- nginxp-net

挂载当前目录 html1 为 apache 的服务根目录,里面为静态网站文件。注意,由于 httpd 只暴露了一个 80 端口,所以此处不需要指定 VIRTUAL_PORT 的值,反向代理容器会自动指定这个端口。VIRTUAL_HOST 和 LETSENCRYPT_HOST 指定了主机域名,可同时指定多个,使用逗号隔开即可。为方便理解,一般指定无前缀和带www的域名。LETSENCRYPT_EMAIL 指定邮箱,方便接收 letsencrypt 发的邮件。

这是一个模板,可以根据需求任意添加。如:

1
2
3
4
5
6
7
8
9
10
11
12
http2:
image: httpd
container_name: httpd2
volumes:
- ./html1:/usr/local/apache2/htdocs/
environment:
- VIRTUAL_HOST=i.latelee.org
- LETSENCRYPT_HOST=i.latelee.org
- LETSENCRYPT_EMAIL=test@latelee.org
- ENABLE_ACME=true
networks:
- nginxp-net

启动

使用如下命令启动:

1
docker-compose up -d

可针对个别服务进行启动、停止操作,如:

1
2
3
docker-compose up -d http2
docker-compose stop http2
docker-compose start http2

使用记录

2021.1.4 证书到期,经查,是 letsencrypt 运行出错,从错误信息查不出原因,更新该镜像,再重启,可自动更新证书。
容器初始化日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Info: running letsencrypt-nginx-proxy-companion version v2.0.2-19-g5d890e7
Warning: '/etc/acme.sh' does not appear to be a mounted volume.
Info: Custom Diffie-Hellman group found, generation skipped.
Reloading nginx proxy (c75452210276c1003b86356fa10266d6939cac2f331bd89a12f0abed16a1221f)...
2021/01/05 16:18:06 Contents of /etc/nginx/conf.d/default.conf did not change. Skipping notification ''
2021/01/05 16:18:06 [notice] 59#59: signal process started
Warning: /app/letsencrypt_service_data not found, skipping data from containers.
Reloading nginx proxy (c75452210276c1003b86356fa10266d6939cac2f331bd89a12f0abed16a1221f)...
2021/01/05 16:18:08 Generated '/etc/nginx/conf.d/default.conf' from 13 containers
2021/01/05 16:18:08 [notice] 81#81: signal process started
Sleep for 3600s
2021/01/05 16:18:09 Generated '/app/letsencrypt_service_data' from 13 containers
2021/01/05 16:18:09 Running '/app/signal_le_service'
2021/01/05 16:18:09 Watching docker events
2021/01/05 16:18:09 Contents of /app/letsencrypt_service_data did not change. Skipping notification '/app/signal_le_service'
...
Creating/renewal i.latelee.org certificates... (i.latelee.org)
[Tue Jan 5 16:20:23 UTC 2021] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Tue Jan 5 16:20:23 UTC 2021] Creating domain key
[Tue Jan 5 16:20:24 UTC 2021] The domain key is here: /etc/acme.sh/li@latelee.org/i.latelee.org/i.latelee.org.key
[Tue Jan 5 16:20:24 UTC 2021] Single domain='i.latelee.org'
[Tue Jan 5 16:20:24 UTC 2021] Getting domain auth token for each domain
[Tue Jan 5 16:20:30 UTC 2021] Getting webroot for domain='i.latelee.org'
[Tue Jan 5 16:20:30 UTC 2021] Verifying: i.latelee.org
[Tue Jan 5 16:20:35 UTC 2021] Pending
[Tue Jan 5 16:20:38 UTC 2021] Pending
[Tue Jan 5 16:20:41 UTC 2021] Pending
[Tue Jan 5 16:20:45 UTC 2021] Success
[Tue Jan 5 16:20:45 UTC 2021] Verify finished, start to sign.
[Tue Jan 5 16:20:45 UTC 2021] Lets finalize the order.
[Tue Jan 5 16:20:45 UTC 2021] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/108459963/7141145386'
[Tue Jan 5 16:20:47 UTC 2021] Downloading cert.
[Tue Jan 5 16:20:47 UTC 2021] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/03f5858c596c2ee39ba44bb4cda7e5a26c1e'
[Tue Jan 5 16:20:55 UTC 2021] Cert success.
-----BEGIN CERTIFICATE-----
MIIGasdflaksdjfiaskdfjG*Y#@RF&lSDFDFDSFDSF
dfdf3w#KFHDGFLDFUEIHGDLGDSgfSLDKHFDSLHGLDS
...
-----END CERTIFICATE-----
[Tue Jan 5 16:20:55 UTC 2021] Your cert is in /etc/acme.sh/li@latelee.org/i.latelee.org/i.latelee.org.cer
[Tue Jan 5 16:20:55 UTC 2021] Your cert key is in /etc/acme.sh/li@latelee.org/i.latelee.org/i.latelee.org.key
[Tue Jan 5 16:20:55 UTC 2021] The intermediate CA cert is in /etc/acme.sh/li@latelee.org/i.latelee.org/ca.cer
[Tue Jan 5 16:20:55 UTC 2021] And the full chain certs is there: /etc/acme.sh/li@latelee.org/i.latelee.org/fullchain.cer
[Tue Jan 5 16:20:55 UTC 2021] Installing cert to:/etc/nginx/certs/i.latelee.org/cert.pem
[Tue Jan 5 16:20:55 UTC 2021] Installing CA to:/etc/nginx/certs/i.latelee.org/chain.pem
[Tue Jan 5 16:20:55 UTC 2021] Installing key to:/etc/nginx/certs/i.latelee.org/key.pem
[Tue Jan 5 16:20:55 UTC 2021] Installing full chain to:/etc/nginx/certs/i.latelee.org/fullchain.pem

检查更新的部分日志如下:

1
2
3
4
5
6
7
8
9
10
# docker logs -f --tail 100 letsencrypt
Creating/renewal www.latelee.org certificates... (www.latelee.org)
[Tue Jan 5 23:25:33 UTC 2021] Domains not changed.
[Tue Jan 5 23:25:33 UTC 2021] Skip, Next renewal time is: Sat Mar 6 16:23:29 UTC 2021
[Tue Jan 5 23:25:33 UTC 2021] Add '--force' to force to renew.
Sleep for 3600s
Creating/renewal i.latelee.org certificates... (i.latelee.org)
[Wed Jan 6 00:25:37 UTC 2021] Domains not changed.
[Wed Jan 6 00:25:37 UTC 2021] Skip, Next renewal time is: Sat Mar 6 16:20:55 UTC 2021
[Wed Jan 6 00:25:37 UTC 2021] Add '--force' to force to renew.

可以看到,每隔一小时检查一次,如不需要更新,继续休眠。也可强制更新(但无必要)。

初稿:2020.6
更新:2021.1