Search

2026/08/25

Yahoo!ショッピングストアの2026年9月からの有料化で8月解約申請だと基本料金は発生する

Yahoo!ショッピングストアは2026年9月から月額基本料金が有料化となります。
ネット利用のサービスは急に規約が変わるのでとても注意しないと、と思った。


ストアからの連絡メールが大小の内容でたくさん来ていた。
また、このストアが無料だから続けていこうとしていて、メールを詳しく読んでいなかった私たちの責任。。。
でも、そんなに強くアピールしてなくて、8月になってから急に連絡メールが強めなメッセージできていた。
それで解約申請したけど遅かった。

今までの高機能なのをほぼわずかな使用料金で使わせてもらったのだから最後の解約料金としてしっかりと払っておこう。

2026/08/18

Docker nginx+CertbotでLet's Encrypt証明書を複数ドメイン1本に統合し、自動更新する方法

Docker nginx+CertbotでLet's Encrypt証明書を複数ドメイン1本に統合し、自動更新する方法



1:要約

Dockerでnginxを運用しているVPSで、Let's Encryptの証明書が複数作成され、 どの証明書をnginxが利用しているのか分かりにくくなっていました。 また、Certbotによる証明書更新も自動化されておらず、証明書の期限切れが発生していました。

そこで今回は、複数のドメイン・サブドメインを 1つのLet's Encrypt証明書に統合し、 Docker版Certbotとsystemd timerを使って自動更新する構成に整理します。

この記事では例として、以下の4ドメインを利用します。

example.com
www1.example.com
www2.example.com
www3.example.com

最終的な構成は次のようになります。

Let's Encrypt
       ↑
       │ HTTP-01認証
       │
Docker nginx
       │
       ├─ /.well-known/acme-challenge/
       │
       ↓
/srv/web/certbot/www

Docker Certbot
       │
       ├─ 証明書管理名:example.com
       │
       └─ 4ドメインを1証明書で管理
              │
              ↓
/srv/web/certbot/conf

systemd timer
       │
       ↓
docker run certbot renew
       │
       ↓
更新成功時のみ nginx reload

ポイントは、Ubuntu本体にCertbotを追加インストールせず、 公式のDocker版Certbotに統一することです。 Certbotを二重管理しないため、後から見ても構成が分かりやすくなります。

3:内容

3-1.今回の構成

nginxとCertbotはDockerで動かし、証明書データだけをVPS上の永続ディレクトリに保存します。

/srv/web/certbot/
├── conf/
│   ├── live/
│   ├── archive/
│   └── renewal/
│
└── www/
    └── .well-known/
        └── acme-challenge/

役割は次の通りです。

  • /srv/web/certbot/conf:証明書、秘密鍵、Certbotの更新設定
  • /srv/web/certbot/www:Let's EncryptのHTTP-01認証で使用

nginxコンテナとCertbotコンテナから同じディレクトリを見ることで、 nginxを停止せずに証明書を更新できます。

3-2.Let's Encrypt証明書を複数ドメインで1本にする

Let's Encryptでは、1枚の証明書に複数のDNS名を含めることができます。

今回は次の4ドメインを1枚にします。

example.com
www1.example.com
www2.example.com
www3.example.com

Certbot上の管理名も、分かりやすく example.com に統一します。

最終的には次のようになります。

Certificate Name: example.com

Identifiers:
  example.com
  www1.example.com
  www2.example.com
  www3.example.com

サブドメインごとに証明書を作る必要がなければ、 このようにまとめた方が管理対象を減らせます。

3-3.nginxとCertbotのディレクトリ共有

nginxには、例えば次のようにマウントします。

- /srv/web/certbot/conf:/etc/letsencrypt
- /srv/web/certbot/www:/var/www/certbot

実際のマウント状態は次のコマンドで確認できます。

docker inspect nginx \
  --format '{{range .Mounts}}{{println .Source " -> " .Destination}}{{end}}'

例えば次のようになっていればOKです。

/srv/web/certbot/www  -> /var/www/certbot
/srv/web/certbot/conf -> /etc/letsencrypt

3-4.ACME challenge用のnginx設定

Let's EncryptのHTTP-01認証では、 HTTPの80番ポートから特定のURLへアクセスできる必要があります。

server {
    listen 80;
    listen [::]:80;

    server_name
        example.com
        www1.example.com
        www2.example.com
        www3.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
        try_files $uri =404;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

通常のHTTPアクセスはHTTPSへリダイレクトしますが、 /.well-known/acme-challenge/ だけはCertbot用にHTTPでアクセス可能にします。

3-5.ACME challengeの疎通確認

証明書発行前に、テストファイルを作成します。

sudo mkdir -p /srv/web/certbot/www/.well-known/acme-challenge

echo 'certbot-test' | sudo tee \
  /srv/web/certbot/www/.well-known/acme-challenge/test.txt

各ドメインから確認します。

curl http://example.com/.well-known/acme-challenge/test.txt
curl http://www1.example.com/.well-known/acme-challenge/test.txt
curl http://www2.example.com/.well-known/acme-challenge/test.txt
curl http://www3.example.com/.well-known/acme-challenge/test.txt

すべてで次の文字列が返れば正常です。

certbot-test

この確認を先に行っておくと、Certbot実行時の認証失敗をかなり減らせます。

3-6.4ドメイン入り証明書を発行する

公式Certbot Dockerイメージを使います。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  certbot/certbot certonly \
  --webroot \
  -w /var/www/certbot \
  --cert-name example.com \
  -d example.com \
  -d www1.example.com \
  -d www2.example.com \
  -d www3.example.com

成功すると、証明書は次の場所に作成されます。

/etc/letsencrypt/live/example.com/fullchain.pem
/etc/letsencrypt/live/example.com/privkey.pem

実ファイルはVPS側の /srv/web/certbot/conf に保存されているため、Certbotコンテナを削除しても証明書は残ります。

証明書一覧は次のコマンドで確認できます。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot certificates

3-7.nginxを新しい証明書へ切り替える

4つのHTTPS serverで同じ証明書を指定します。

ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

nginx設定を確認します。

docker exec nginx nginx -t

正常ならreloadします。

docker exec nginx nginx -s reload

実際に読み込まれている証明書設定も確認できます。

docker exec nginx nginx -T 2>/dev/null \
  | grep -E 'server_name|ssl_certificate'

HTTPS通信も確認します。

curl -I https://example.com
curl -I https://www1.example.com
curl -I https://www2.example.com
curl -I https://www3.example.com

HTTPステータスが200以外でも、アプリケーション側が400や302を返している場合があります。 重要なのはSSL証明書エラーが発生していないことです。

3-8.古い証明書を整理する

過去に複数の証明書を作っている場合、 livearchiverenewal に古い設定が残っていることがあります。

まず一覧を確認します。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot certificates

nginxが古い証明書を参照していないことを確認してから、 Certbot管理下の不要な証明書を削除します。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot delete \
  --cert-name 古い証明書名 \
  --non-interactive

/etc/letsencrypt/live配下を単純にrmするのは避けます。

Certbotは livearchiverenewal を連動して管理しているためです。

ただし、過去の作業で live が消えているのに archiverenewal/*.conf だけが残った壊れた設定では、手動整理が必要になる場合があります。

作業前にはバックアップを取っておくと安全です。

sudo tar -czf /root/letsencrypt-backup.tar.gz \
  /srv/web/certbot/conf

3-9.Certbotの自動更新テスト

自動化する前に、実際には証明書を更新しない --dry-run を実行します。

docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  certbot/certbot renew \
  --dry-run

正常なら次のようなメッセージが表示されます。

Congratulations, all simulated renewals succeeded

ここまで成功してから自動実行を設定するのが安全です。

3-10.systemd timerでCertbotを自動実行する

Docker版Certbotは、コンテナ自身がcronのように常駐して定期実行する構成ではありません。

そこでUbuntu側のsystemd timerを使って、 定期的にDocker版Certbotを起動します。

まずserviceを作ります。

sudo tee /etc/systemd/system/certbot-docker-renew.service > /dev/null <<'EOF'
[Unit]
Description=Renew Let's Encrypt certificates with Docker Certbot
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RuntimeDirectory=certbot-renew

ExecStartPre=/usr/bin/rm -f /run/certbot-renew/renewed

ExecStart=/usr/bin/docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  -v /run/certbot-renew:/run/certbot-renew \
  certbot/certbot renew \
  --deploy-hook "touch /run/certbot-renew/renewed"

ExecStartPost=/bin/sh -c 'if [ -f /run/certbot-renew/renewed ]; then echo "Certificate renewed - reloading nginx"; /usr/bin/docker exec nginx nginx -s reload; else echo "No certificate renewal - nginx reload not required"; fi'
EOF

このserviceでは、証明書が実際に更新された場合だけ nginx -s reload を実行します。

次にtimerを作ります。

sudo tee /etc/systemd/system/certbot-docker-renew.timer > /dev/null <<'EOF'
[Unit]
Description=Run Docker Certbot renewal twice daily

[Timer]
OnCalendar=*-*-* 03,15:00:00
RandomizedDelaySec=30m
Persistent=true
Unit=certbot-docker-renew.service

[Install]
WantedBy=timers.target
EOF

systemdへ設定を読み込ませます。

sudo systemctl daemon-reload

timerを有効化して、その場で開始します。

sudo systemctl enable --now certbot-docker-renew.timer

この例では1日2回、3時台と15時台にCertbotが更新チェックを行います。

毎回証明書を発行するわけではありません。 certbot renew が更新期限を判断し、更新が必要な場合だけ証明書を更新します。

3-11.自動更新の状態を確認する

timerの状態を確認します。

systemctl status certbot-docker-renew.timer --no-pager

次回実行時刻はこちらです。

systemctl list-timers --all | grep certbot

有効化状態も確認できます。

systemctl is-enabled certbot-docker-renew.timer
systemctl is-active certbot-docker-renew.timer

正常なら次のようになります。

enabled
active

timerを待たずにserviceだけ手動実行することもできます。

sudo systemctl start certbot-docker-renew.service

実行ログを確認します。

sudo journalctl \
  -u certbot-docker-renew.service \
  -n 100 \
  --no-pager

証明書を取得したばかりの場合は更新されないため、 次のような内容になるのが正常です。

Certificate not yet due for renewal
No certificate renewal - nginx reload not required

3-12.省保守化のポイント

今回の構成で重要なのは、Certbotや証明書の管理方法をできるだけ増やさないことです。

最終的には次の状態を目指します。

証明書
└─ example.com
   ├─ example.com
   ├─ www1.example.com
   ├─ www2.example.com
   └─ www3.example.com

Certbot
└─ Docker版のみ

認証方式
└─ webroot

定期実行
└─ systemd timer

Webサーバー
└─ Docker nginx

Ubuntuへ別のCertbotをインストールすると、 「OS版Certbot」と「Docker版Certbot」の2系統が存在することになります。

特別な理由がなければ、今回のようにDocker版Certbotだけに統一した方が、 数か月後に設定を見直したときにも理解しやすくなります。

また、証明書をサブドメインごとに分割すると、 renewal設定、証明書ファイル、期限確認対象も増えます。

同じサーバーで利用していて、同じタイミングで更新して問題ないドメインなら、 1枚の証明書へまとめることで保守対象を減らせます。

最終チェック用コマンド

# 証明書一覧
docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  certbot/certbot certificates

# 更新シミュレーション
docker run --rm \
  -v /srv/web/certbot/conf:/etc/letsencrypt \
  -v /srv/web/certbot/www:/var/www/certbot \
  certbot/certbot renew --dry-run

# nginxが使用している証明書
docker exec nginx nginx -T 2>/dev/null \
  | grep -E 'server_name|ssl_certificate'

# timer確認
systemctl list-timers --all | grep certbot

# 更新ログ
sudo journalctl \
  -u certbot-docker-renew.service \
  -n 100 \
  --no-pager

この構成にしておけば、通常の運用ではCertbotを手動で操作する必要はほとんどなく、 systemd timerが定期チェックし、必要なタイミングで証明書を更新できます。

2026/08/17

dockerとは起動失敗なく仮想環境を複数で作って、それぞれ繋げて便利に使うもの

docker使っているけど簡単に説明すると何?
起動するときに余計なこと考えずに失敗しなくて、
それぞれの仮想環境を複数で作って、
それぞれ繋げて便利に使うもの
みたいな感じ。(てきとう)

その分、必要なファイル容量は大きくなるし、
管理することも増えるよ
みたいなことも。(当てずっぽう)

調べたりAIにまとめてもらったものの備忘録です。


DockerでLaravelを動かす仕組み――nginx・PHP・PostgreSQL・Portainer・WUDの関係

Ubuntu VPS上でLaravelのWebアプリ、データベース、Docker管理画面、更新確認ツールを動かす構成を初心者向けに整理します。Laravelは通常のブラウザから利用でき、PortainerとWUDは管理者だけがブラウザで開ける構成です。

1. 全体構成

インターネット上のブラウザ
        │ HTTP / HTTPS
        ▼
Ubuntu VPS
└─ Docker Engine
   ├─ nginxコンテナ ─────── 公開窓口
   │        │ FastCGI
   │        ▼
   ├─ PHP-FPMコンテナ ──── Laravelを実行
   │        │
   │        ▼
   ├─ PostgreSQLコンテナ ─ データを保存
   ├─ Portainerコンテナ ── Docker管理画面
   └─ WUDコンテナ ─────── イメージ更新を確認

Docker Engineは1つだけです。nginx、PHP-FPM、PostgreSQL、Portainer、WUDは、同じDocker Engine上で動く別々のコンテナです。LaravelはPHP-FPMコンテナ内で実行されるアプリケーションです。

2. 各コンテナの役割

要素役割外部公開
nginxブラウザからのアクセスを受け、PHP処理をPHP-FPMへ渡す80・443番
PHP-FPMPHPを実行し、Laravelの処理結果をnginxへ返す公開しない
Laravel画面表示、ログイン、検索、データ処理などWebアプリ本体nginx経由
PostgreSQLLaravelが使うデータベース公開しない
Portainer CEDockerをGUIで確認・管理するlocalhostのみ
WUDDockerイメージの更新を検出するlocalhostのみ

3. ブラウザからアクセスする流れ

  1. ブラウザでLaravel用ドメインを開く
  2. VPSの80番または443番へ接続する
  3. nginxがリクエストを受ける
  4. PHP処理をPHP-FPMへ渡す
  5. Laravelが必要に応じてPostgreSQLへ接続する
  6. 処理結果がnginx経由でブラウザへ戻る
https://example.com
        ↓
VPSの443番
        ↓
nginx
        ↓
php:9000
        ↓
Laravel
        ↓
postgres:5432
ブラウザアクセスは可能です。 外部へ公開するのはnginxの80・443番だけです。PHPの9000番とPostgreSQLの5432番はDocker内部だけで利用します。

4. コンテナ同士の通信

同じDockerネットワークに接続したコンテナは、Composeのサービス名で通信できます。

  • nginxからPHPへ:php:9000
  • LaravelからPostgreSQLへ:postgres:5432

LaravelのDB_HOSTにはpostgresを指定します。PHPコンテナ内のlocalhostはPHPコンテナ自身を意味するためです。

5. 推奨ディレクトリ構成

/srv/
├─ laravel-app/
│  ├─ compose.yml
│  ├─ .env
│  ├─ docker/
│  │  ├─ nginx/default.conf
│  │  └─ php/Dockerfile
│  └─ src/
│     ├─ artisan
│     ├─ app/
│     ├─ public/
│     └─ storage/
└─ docker-management/
   └─ compose.yml

Laravel側と管理ツール側を別のComposeプロジェクトに分けます。それぞれでdocker compose up -dを実行すると、同じDocker Engine上へ追加されます。

6. Laravel側のCompose例

/srv/laravel-app/compose.ymlの基本例です。

name: laravel-app

services:
  nginx:
    image: nginx:alpine
    container_name: laravel-nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./src:/var/www/html:ro
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php
    networks:
      - app-network

  php:
    build:
      context: ./docker/php
    container_name: laravel-php
    restart: unless-stopped
    working_dir: /var/www/html
    volumes:
      - ./src:/var/www/html
    environment:
      APP_ENV: production
      DB_CONNECTION: pgsql
      DB_HOST: postgres
      DB_PORT: 5432
      DB_DATABASE: laravel
      DB_USERNAME: laravel
      DB_PASSWORD: ${DB_PASSWORD}
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - app-network

  postgres:
    image: postgres:16-alpine
    container_name: laravel-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: laravel
      POSTGRES_USER: laravel
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U laravel -d laravel"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network

volumes:
  postgres_data:

networks:
  app-network:

PostgreSQLにはportsを書いていないため、VPS外部から5432番へ直接接続できません。Composeと同じディレクトリの.envには、DB_PASSWORD=長いランダムなパスワードを設定します。

7. Portainer・WUD側のCompose例

/srv/docker-management/compose.ymlの例です。

name: docker-management

services:
  portainer:
    image: portainer/portainer-ce:2.39.6
    container_name: portainer
    restart: unless-stopped
    ports:
      - "127.0.0.1:9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

  wud:
    image: getwud/wud:8.3.1
    container_name: wud
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      TZ: Asia/Tokyo
      WUD_WATCHER_LOCAL_CRON: "0 6 * * *"
      WUD_WATCHER_LOCAL_WATCHBYDEFAULT: "true"
      WUD_WATCHER_LOCAL_WATCHEVENTS: "false"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - wud_data:/store

volumes:
  portainer_data:
  wud_data:

PortainerとWUDはVPSの127.0.0.1だけに公開します。インターネットから直接は開けません。

8. nginx設定例

/srv/laravel-app/docker/nginx/default.confの基本例です。

server {
    listen 80;
    server_name example.com;
    root /var/www/html/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }
}

fastcgi_pass php:9000;により、PHP処理をphpサービスへ渡します。

これはHTTPの基本例です。本番公開ではドメインを設定し、Let's EncryptなどでHTTPS化してください。

9. 起動方法

Laravel側

cd /srv/laravel-app
docker compose config
docker compose build
docker compose up -d
docker compose ps

管理ツール側

cd /srv/docker-management
docker compose config
docker compose pull
docker compose up -d
docker compose ps

全体は次で確認できます。

docker ps
docker compose ls

10. 管理画面へのブラウザアクセス

WindowsのPowerShellからSSHトンネルを開きます。

ssh -L 9443:127.0.0.1:9443 -L 3000:127.0.0.1:3000 ユーザー名@VPSのIPアドレス

SSH接続を開いたまま、ブラウザで次を開きます。

  • Laravel:https://取得したドメイン
  • Portainer:https://localhost:9443
  • WUD:http://localhost:3000

Laravelは一般利用者向けに公開し、PortainerとWUDはSSH接続できる管理者だけが利用します。

11. 更新とデータ管理

対象管理方法更新方法
UbuntuAPTセキュリティ更新は自動、通常更新は手動
Docker EngineAPTメンテナンス時間に手動
nginx・PHP・PostgreSQLWUDで検出Composeから手動
LaravelGitなどコード配備、Composer、マイグレーション
コンテナの状態Portainerログと稼働状態を確認
cd /srv/laravel-app
docker compose pull
docker compose build --pull php
docker compose up -d
docker compose ps
docker compose logs --tail 100

PostgreSQLデータはpostgres_dataボリューム、Portainer設定はportainer_data、WUD履歴はwud_dataに保存されます。

PostgreSQLの16から17のようなメジャーバージョン変更は単純なイメージ更新ではありません。事前バックアップとデータ移行が必要です。また、docker compose down -vはボリュームを削除するため、通常は使いません。

主な確認コマンド

docker ps
docker compose ls
docker system df
df -h /

cd /srv/laravel-app
docker compose logs --tail 100 nginx
docker compose logs --tail 100 php
docker compose logs --tail 100 postgres
docker exec laravel-nginx nginx -t
docker compose exec php php artisan about

12. まとめ

  • nginxがブラウザからのアクセスを受ける
  • PHP-FPMがLaravelを実行する
  • LaravelがPostgreSQLへデータを保存する
  • PortainerがDocker全体をGUIで見えるようにする
  • WUDがコンテナイメージの更新を確認する

Laravelはドメインから通常のブラウザで利用できます。PortainerとWUDはlocalhostだけに公開し、SSHトンネル経由でブラウザ表示します。これにより、Webアプリの公開とDocker管理画面の保護を両立できます。

Dockerでは、稼働中のコンテナを直接作り込むより、Composeファイル、Dockerfile、nginx設定、Laravelソース、環境変数を設計図として保ち、同じ構成を再現できる状態にすることが重要です。