SSL加密

在使用自己搭建的服务,如 emby ,nextcloud, immich 时,如果使用域名访问,当没有进行受信任的 SSL 加密时,对应的手机 app 会连不上,提醒,或报错。

最简单的方式是用 certbot 获取一个 90 天期限的 SSL 证书,到期后再更新。此篇博客做一备忘。

证书获取过程

安装好certbot后,执行以下命令手动获取 SSL 证书,并用在域名上添加一条 txt 解析的方式进行域名验证:

certbot certonly --manual --preferred-challenges dns -d xxx.xxx.com

按提示在域名提供商处添加记录:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for xxx.xxx.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.xxx.xxx.com.

with the following value:

GxxxxxxxxxxxxxQ

Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.xxx.xxx.com.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/xxx.xxx.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/xxx.xxx.com/privkey.pem
This certificate expires on 2025-12-13.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

.pem.crt.key 本质上都是文本格式的证书/密钥文件,只是扩展名不同而已。可以直接需要复制或改名:

fullchain.pem ->.crt
privkey.pem ->.key

正确设置权限,参考如下:

-rw-r--r--. 1 zqw zqw 2.8K Sep 14 17:40 server.crt
-rw-------. 1 zqw zqw  227 Sep 14 17:40 server.key

代理的 Podman 文件,代理容器的配置文件示例

nextcloud-proxy.container:

[Container]
ContainerName=nextcloud-proxy
Pod=nextcloud.pod
Image=docker.io/library/httpd:2.4
Volume=/xxx/extra-proxy.conf:/usr/local/apache2/conf/extra/proxy.conf:ro,Z
Volume=/xxx/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro,Z
Volume=/xxx/server.crt:/usr/local/apache2/conf/server.crt:ro,Z
Volume=/xxx/server.key:/usr/local/apache2/conf/server.key:ro,Z

httpd.conf

# Real-time info on requests and configuration
#Include conf/extra/httpd-info.conf

# Virtual hosts
#Include conf/extra/httpd-vhosts.conf

# Local access to the Apache HTTP Server Manual
#Include conf/extra/httpd-manual.conf

# Distributed authoring and versioning (WebDAV)
#Include conf/extra/httpd-dav.conf

# Various default settings
#Include conf/extra/httpd-default.conf

# Configure mod_proxy_html to understand HTML4/XHTML1
<IfModule proxy_html_module>
Include conf/extra/proxy-html.conf
</IfModule>

# Secure (SSL/TLS) connections
#Include conf/extra/httpd-ssl.conf
#
# Note: The following must must be present to support
#       starting without SSL on platforms with no /dev/random equivalent
#       but a statically compiled-in mod_ssl.
#
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>

Include conf/extra/proxy.conf

反向代理容器和 nextcloud 容器在同个 pod 内,把nextcloud 默认的 80 代理到了 443:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

<IfModule mod_proxy.c>
    ProxyPreserveHost On
    ProxyPass / http://localhost:80/
    ProxyPassReverse / http://localhost:80/
</IfModule>

LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule ssl_module modules/mod_ssl.so
Include conf/extra/httpd-ssl.conf

~/.config/containers/systemd/nextcloud.pod 文件中,再把 443 映射到想要的端口(如9999),这样就可能在外网通过 SSL 访问 NextCloud 容器:


[Pod]
PodName=nextcloud
Network=bridge
PublishPort=9999:443

[Install]
WantedBy=default.target

参考

ArchWiki: Certbot