我的服务器搭建日志:在docker上使用nginx的反向代理环境中使用Let’s Encrypt

抚慰文字形103112

我个人的服务器建设日志:继上次重新开始后,关于建设家庭服务器的继续记录。

我们将按照标题所示的要求来完成任务。上次我们尝试在 Docker 上搭建了一个 Nginx 反向代理,现在我们将探索如何在这个环境中获取和维护 Let’s Encrypt 的证书。

我尝试了一下进行调查,但是关于类似的内容的文章并不多。特别是有关维护的步骤。我也考虑了一下步骤,但只能想到一些与Docker不太相关的方法。最终在不断尝试中,我选择了与主机机器的cron结合起来的方式。

要求给出中文句子的多个版本,这是一个指定标题的写作任务。请提供目标句子的多个版本。

    • Dockerコンテナで立てたnginxリバースプロキシを前提とする

 

    • リバースプロキシに証明書を持たせて、上流(upstream)にはHTTPで接続。

 

    • 証明書を Let’s Encrypt で取得(certbotを利用)

 

    証明書を定期的に自動更新する。

大纲

为了获取和维持证书,只需要在反向代理的Docker容器中安装certbot。之后按照标准步骤进行操作。

尽管知道这不是被赞赏的方法,我希望将cron放入Docker容器中。但实际尝试后,反向代理无法正常工作。这真是令人困扰。

因此,我们决定通过主机的cron设置来实现定期启动命令。

我本来是想避免做这种事情后会忘记,不过只使用反向代理将LXD容器化似乎有些夸张了。真遗憾。

文献引用

    • nginxによるバーチャルホスト/リバースプロキシによる Let’s Encrypt 証明書の取得方法など – Qiita

 

    • SSL証明書の自動更新。 – 無料のSSL証明書Let’s Encryptを設定・更新・自動更新する方法(CentOS7, Apache2.4対応) – プログラミング入門ナビ by Proglus(プログラス)

 

    • 私的サーバー構築日誌:nginx on docker でリバースプロキシ – Qiita

私的サーバー構築日誌:LAN内DNSサーバー Unbound – Qiita … 我が家の家庭内DNSです。バーチャルホストを動かす為に、少し追記が必要になります。

【cron】改めてcronの設定方法について勉強し直してみた – とーますメモ … /etc/cron.d/に置く設定ファイルは、拡張子を付けてはいけないようです。
Docker Composeでログの設定をする – Qiita

这次我们决定不在Docker容器中使用cron。不过,我还是给出了参考文献。

    • Docker コンテナで cron を使う – Docker コンテナ内でタスクを cron 起動する – Qiita

 

    • Dockerコンテナ内でcronを実行し実行ログを出力する方法 – ゲンゾウ用ポストイット

 

    Dockerコンテナの中身のタイムゾーンを日本時刻にする方法 – My CMS

建立实验环境

我們將搭建與上次相同的實驗環境。由於反向代理有一些步驟變更,因此重新列出所有步驟。

网络设置

我会配置我们家的服务器,以便可以从外部互联网访问。首先设置DNS,然后进行家用路由器的端口转发。端口80和端口443。由于环境不同,设置步骤也会不同,请按照各自的步骤进行配置。

然后将设定内容设置为变量。

域名在这里假设为example.com,你需要购买并设置属于自己的域名,千万不要直接使用这个。

MY_DOMAIN=example.com
TEST_DOMAIN=test.$MY_DOMAIN

我家服务器在家庭局域网中的IP地址是172.16.1.2。

HOST_IPADDR=172.16.1.2

家庭内部域名系统

首先,我们会配置家庭内部的DNS。

cd /etc/unbound/unbound.conf.d/
cat | sudo tee -a machines.list >/dev/null <<___
local-data: "$TEST_DOMAIN. 3600000 IN A $HOST_IPADDR"
___
unbound-checkconf
sudo systemctl restart unbound

网络服务器

我将设置一个Web服务器。由于只涉及基本配置,所以我将直接进行,不做解释。

TEST_PORT=20080
cd
mkdir docker-nginx1
cd docker-nginx1
mkdir -p config/nginx
mkdir -p data/nginx
mkdir html
cat <<___ >docker-compose.yml
version: "3.9"
services:
  nginx1:
    image: nginx:latest
    container_name: nginx1
    restart: unless-stopped
    ports:
      - $TEST_PORT:80
    volumes:
      - ./config/nginx:/etc/nginx/conf.d
      - ./data/nginx:/var/log/nginx
      - ./html:/usr/share/nginx/html
___
cat <<___ >config/nginx/test.conf
server {
    listen        80;
    server_name   _;
    server_tokens off;

    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }
}
___
cat <<___ >html/index.html
<!DOCTYPE html>
<html lang="ja">
 <head>
 <meta charset="UTF-8" />
 <title>nginx test</title>
</head>
<body>
 <h1>test</h1>
 <p>hello,world</p>
</body>
</html>
___
docker compose up -d

确认动作。

curl http://$HOST_IPADDR:$TEST_PORT/

反向代理

反向代理是指,根据概述的内容,安装certbot。

cd
mkdir docker-proxy
cd docker-proxy
mkdir -p config/nginx
mkdir -p data/nginx
mkdir -p html/ssl-proof
mkdir letsencrypt
cat <<___ >docker-compose.yml
version: "3.9"
services:
  proxy:
    build: .
    container_name: proxy
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./config/nginx:/etc/nginx/conf.d
      - ./data/nginx:/var/log/nginx
      - ./html:/usr/share/nginx/html
      - ./letsencrypt:/etc/letsencrypt
    logging:
      driver: json-file
      options:
        max-size: 10m
        max-file: '3'
___
cat <<___ >Dockerfile
FROM nginx:latest
RUN apt update \
 && apt install -y certbot \
 && apt -y clean
___
cat <<___ >config/nginx/default.conf
server {
    listen        80 default_server;
    server_name   _;
    server_tokens off;

    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }
}
___
cat <<___ >config/nginx/test.conf
server {
    listen        80;
    server_name   $TEST_DOMAIN;
    server_tokens off;

    location ^~ /.well-known/acme-challenge/ {
        root   /usr/share/nginx/html/ssl-proof;
    }

    location / {
        proxy_pass http://$HOST_IPADDR:$TEST_PORT;
    }
}
___
docker compose up -d

确认动作。

curl http://$TEST_DOMAIN/

使用Certbot获取证书。

从这里开始才是真正的实战吧。首先是获取证书的步骤。执行certbot命令。

docker compose exec proxy certbot certonly --register-unsafely-without-email --agree-tos --webroot -w /usr/share/nginx/html/ssl-proof -d $TEST_DOMAIN

证明文件等存储在以下位置。但权限已设置为root。

    • 公開鍵: ~/docker-proxy/letsencrypt/live/$TEST_DOMAIN/fullchain.pem

秘密鍵: ~/docker-proxy/letsencrypt/live/$TEST_DOMAIN/privkey.pem

cd
cd docker-proxy
sudo ls -l letsencrypt/live/$TEST_DOMAIN

大致如此。

$ sudo ls -l letsencrypt/live/$TEST_DOMAIN
total 9
-rw-r--r-- 1 root root 692 Nov 28 13:50 README
lrwxrwxrwx 1 root root  42 Nov 28 13:50 cert.pem -> ../../archive/test.moon-night.jp/cert1.pem
lrwxrwxrwx 1 root root  43 Nov 28 13:50 chain.pem -> ../../archive/test.moon-night.jp/chain1.pem
lrwxrwxrwx 1 root root  47 Nov 28 13:50 fullchain.pem -> ../../archive/test.moon-night.jp/fullchain1.pem
lrwxrwxrwx 1 root root  45 Nov 28 13:50 privkey.pem -> ../../archive/test.moon-night.jp/privkey1.pem

让我们检查一下证书的内容。

sudo openssl x509 -text -in letsencrypt/live/$TEST_DOMAIN/fullchain.pem | grep -E "Issuer:|Subject:"
sudo openssl x509 -dates -noout -in letsencrypt/live/$TEST_DOMAIN/fullchain.pem

在反向代理服务器上设置证书。

在转发部分设置证书,并保留80号端口用于证书维护。

cat <<___ >config/nginx/test.conf
server {
    listen        80;
    server_name   $TEST_DOMAIN;
    server_tokens off;

    location ^~ /.well-known/acme-challenge/ {
        root /usr/share/nginx/html/ssl-proof;
    }

    location / {
        return 301 http://$TEST_DOMAIN;
    }
}
server {
    listen        443 ssl;
    server_name   $TEST_DOMAIN;
    server_tokens off;

    ssl_certificate     /etc/letsencrypt/live/$TEST_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$TEST_DOMAIN/privkey.pem;

    location / {
        proxy_pass http://$HOST_IPADDR:$TEST_PORT;
    }
}
___

我将重新启动 Nginx。

docker compose exec proxy nginx -s reload

确认动作。

curl https://$TEST_DOMAIN/

自动更新

这是关于证书更新的设定。

cd
cd docker-proxy
cat <<___ >certbot-renew.sh
#!/bin/bash
cd
cd docker-proxy
/usr/bin/date -Iseconds
/usr/bin/docker compose exec proxy certbot renew
/usr/bin/docker compose exec proxy nginx -s reload
echo "====="
___
chmod +x certbot-renew.sh
sudo ln -s $PWD/certbot-renew.sh /usr/local/bin/certbot-renew.sh

关于日志,我们停止使用logger命令,并改用将标准输出和标准错误输出重定向到本地。然后通过logrotate进行轮转。

sudo mkdir /var/log/letsencrypt
sudo chown $USER /var/log/letsencrypt
cat <<___ | sudo tee /etc/logrotate.d/certbot-renew >/dev/null
/var/log/letsencrypt/certbot-renew.log {
    missingok
    rotate 3
    compress
    monthly
    minsize 1M
}
___

由于Let’s Encrypt证书的有效期为90天,因此我们需要每月两次在每月1日和15日凌晨3点运行更新检查。它会自动判断是否应该进行更新,需参考剩余天数是否超过30天。

另外,据说在/etc/cron.d设置文件时,文件的扩展名必须为空。

cat <<___ | sudo tee /etc/cron.d/certbot-renew >/dev/null
0 3 1,15 * * $USER /usr/local/bin/certbot-renew.sh >>/var/log/letsencrypt/certbot-renew.log 2>&1
___

接下来只需要确认实际操作了。这会是一个有点冗长的话题。

cd
cd docker-proxy
sudo ls -l letsencrypt/live/$TEST_DOMAIN/
cat /var/log/letsencrypt/certbot-renew.log

收场

这次的目的还是检查步骤。等确认动作完毕后,记得全部清除干净。

sudo rm /etc/cron.d/certbot-renew
sudo rm /etc/logrotate.d/certbot-renew
sudo rm /usr/local/bin/certbot-renew.sh
sudo rm -r /var/log/letsencrypt
cd
cd docker-proxy
docker compose down --rmi all --volumes
cd
cd docker-nginx1
docker compose down --rmi all --volumes
cd
sudo rm -r docker-proxy docker-nginx1
sudo sed -i -e"/$TEST_DOMAIN./d" /etc/unbound/unbound.conf.d/machines.list
unbound-checkconf
sudo systemctl restart unbound

这次我们确认了使用Let’s Encrypt获取证书并保持证书有效的步骤,在反向代理环境中进行设置。

广告
将在 10 秒后关闭
bannerAds