diff options
| author | yyamashita <yyamashita@hetzner.yyamashita.com> | 2026-07-02 23:08:58 +0900 |
|---|---|---|
| committer | yyamashita <yyamashita@hetzner.yyamashita.com> | 2026-07-02 23:08:58 +0900 |
| commit | 1a7b5adf8484ec0f2b6feb350b578142e186ab26 (patch) | |
| tree | e8c670ac5554d2b17b491ee96e9717f4432d64a9 | |
| parent | 88be3b3f503d4674d764a7265edb2d4e380ae738 (diff) | |
Move forward proxy from Squid to Caddy (port 80/443)
Replace standalone Squid container with caddy-forwardproxy plugin so the
proxy shares Caddy's existing ports and TLS. HTTP on :80 and HTTPS on :443.
Auth is read from the same vpn/users.conf at Caddy startup via entrypoint.sh.
DNS: add proxy to setup-route53.py WEB_SUBDOMAINS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | CLAUDE.md | 33 | ||||
| -rw-r--r-- | caddy/Caddyfile | 7 | ||||
| -rw-r--r-- | caddy/Dockerfile | 9 | ||||
| -rw-r--r-- | caddy/docker-compose.yml | 3 | ||||
| -rw-r--r-- | caddy/entrypoint.sh | 35 | ||||
| -rwxr-xr-x | git/hooks/hetzner-infra/post-receive | 1 | ||||
| -rwxr-xr-x | mail/dns/setup-route53.py | 1 | ||||
| -rw-r--r-- | proxy/Dockerfile | 6 | ||||
| -rw-r--r-- | proxy/deploy.sh | 10 | ||||
| -rw-r--r-- | proxy/docker-compose.yml | 9 | ||||
| -rw-r--r-- | proxy/entrypoint.sh | 13 | ||||
| -rw-r--r-- | proxy/install.sh | 12 | ||||
| -rw-r--r-- | proxy/renew-cert.sh | 22 | ||||
| -rw-r--r-- | proxy/squid.conf | 21 |
14 files changed, 66 insertions, 116 deletions
@@ -5,20 +5,19 @@ Hetzner VPS 上で動くサービス群のインフラ管理リポジトリ。 ## ディレクトリ構成 ``` -caddy/ リバースプロキシ(Caddyfile, docker-compose.yml, deploy.sh) +caddy/ リバースプロキシ + フォワードプロキシ(Caddyfile, Dockerfile, entrypoint.sh, docker-compose.yml, deploy.sh) cgit/ cgit Web UI(Dockerfile, lighttpd.conf, cgitrc, deploy.sh) git/ ベアリポジトリ・フック管理(repos.txt, hooks/, install.sh) claude/ Claude Code セッション管理(sessions.txt, systemd unit, sync.sh) hetzner-admin/ サーバー管理 Web UI(app.py, Dockerfile, docker-compose.yml, deploy.sh) mail/ MTA(Postfix + OpenDKIM, docker-compose.yml, install.sh, dns/setup-route53.py) vpn/ strongSwan IKEv2 VPN(Dockerfile, docker-compose.yml, install.sh, renew-cert.sh) -proxy/ HTTPS フォワードプロキシ(Squid, Dockerfile, docker-compose.yml, install.sh, renew-cert.sh) server/ サーバー共通設定(authorized_keys, requirements.md) ``` ## デプロイの仕組み -- `git push origin master` → post-receive フック → `caddy/deploy.sh` / `cgit/deploy.sh` / `mail/deploy.sh` / `hetzner-admin/deploy.sh` / `vpn/deploy.sh` / `proxy/deploy.sh` を実行 +- `git push origin master` → post-receive フック → `caddy/deploy.sh` / `cgit/deploy.sh` / `mail/deploy.sh` / `hetzner-admin/deploy.sh` / `vpn/deploy.sh` を実行 - cgit の `lighttpd.conf` / `Dockerfile` 変更はイメージ再ビルドが必要(`deploy.sh` で `--build` するため push だけで反映される) - cgit の `cgitrc` はボリュームマウントのため push だけで反映される - フック・リポジトリの変更は push 後に `bash /app/infra/git/install.sh` を手動実行 @@ -110,17 +109,21 @@ ssh root@<server> vi /app/infra/vpn/users.conf # 1行1ユーザー: "username password" docker compose -f /app/infra/vpn/docker-compose.yml restart -# Proxy 初回セットアップ(サーバー上で実行) -# 前提: ファイアウォールで TCP 8443 を開放済み、DNS A レコードで proxy.yyamashita.com を設定済み -git push origin master -ssh root@<server> 'bash /app/infra/git/install.sh' # post-receive フック更新 -# → Caddy が proxy.yyamashita.com の証明書を取得するまで数分待つ -ssh root@<server> 'bash /app/infra/proxy/install.sh' -# → Caddy の証明書を流用 + コンテナ起動 -# → proxy.yyamashita.com:8443 (HTTPS) で接続可能 +# Proxy 初回セットアップ(Caddy に統合済み。追加作業なし) +# → push するだけで Caddy が proxy.yyamashita.com の証明書を自動取得 +# → proxy.yyamashita.com:80 (HTTP) / :443 (HTTPS) でフォワードプロキシとして動作 +# → 認証は VPN と同じ users.conf を共有 + +# Proxy ユーザー追加・変更(VPN と同じ users.conf を編集) +ssh root@<server> +vi /app/infra/vpn/users.conf +docker compose -f /app/infra/caddy/docker-compose.yml restart # Caddy 再起動で反映 -# Proxy 証明書更新(Let's Encrypt 更新後 90 日ごと) -ssh root@<server> 'bash /app/infra/proxy/renew-cert.sh' +# DNS 登録(初回のみ。setup-route53.py に proxy が含まれている) +ssh root@<server> +export AWS_ACCESS_KEY_ID=... +export AWS_SECRET_ACCESS_KEY=... +python3 /app/infra/mail/dns/setup-route53.py ``` ## VPN クライアント設定 @@ -142,6 +145,6 @@ ssh root@<server> 'bash /app/infra/proxy/renew-cert.sh' ## Proxy クライアント設定 -- アドレス: `proxy.yyamashita.com:8443` -- プロトコル: HTTPS (CONNECT トンネリング) +- HTTP プロキシ: `proxy.yyamashita.com:80` +- HTTPS プロキシ: `proxy.yyamashita.com:443` - 認証: Basic 認証(VPN と同じユーザー名/パスワード) diff --git a/caddy/Caddyfile b/caddy/Caddyfile index 5ab87a7..3cf3547 100644 --- a/caddy/Caddyfile +++ b/caddy/Caddyfile @@ -41,12 +41,7 @@ blog.yyamashita.com { reverse_proxy microblog-app:3000 } -proxy.yyamashita.com { - tls { - key_type rsa4096 - } - respond "Proxy Server" 200 -} +import /tmp/proxy_forward.caddy vpn.yyamashita.com { tls { diff --git a/caddy/Dockerfile b/caddy/Dockerfile new file mode 100644 index 0000000..295437b --- /dev/null +++ b/caddy/Dockerfile @@ -0,0 +1,9 @@ +FROM caddy:2-builder-alpine AS builder +RUN xcaddy build --with github.com/caddyserver/forwardproxy@caddy2 + +FROM caddy:2-alpine +COPY --from=builder /usr/bin/caddy /usr/bin/caddy +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] +CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"] diff --git a/caddy/docker-compose.yml b/caddy/docker-compose.yml index 3e9385d..e23d25a 100644 --- a/caddy/docker-compose.yml +++ b/caddy/docker-compose.yml @@ -1,6 +1,6 @@ services: caddy: - image: caddy:2-alpine + build: . ports: - "80:80" - "443:443" @@ -9,6 +9,7 @@ services: - ./:/etc/caddy/ - caddy_data:/data - caddy_config:/config + - /app/infra/vpn/users.conf:/etc/proxy/users.conf:ro restart: unless-stopped networks: - web diff --git a/caddy/entrypoint.sh b/caddy/entrypoint.sh new file mode 100644 index 0000000..cf123ce --- /dev/null +++ b/caddy/entrypoint.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -e + +PROXY_CONF=/tmp/proxy_forward.caddy + +# Build basicauth lines from shared users.conf +AUTH_LINES="" +if [ -f /etc/proxy/users.conf ]; then + while IFS=' ' read -r user pass || [ -n "$user" ]; do + [ -z "$user" ] && continue + case "$user" in \#*) continue ;; esac + AUTH_LINES="${AUTH_LINES} basicauth ${user} ${pass}\n" + done < /etc/proxy/users.conf +fi +AUTH_BLOCK=$(printf '%b' "$AUTH_LINES") + +cat > "$PROXY_CONF" <<EOF +http://proxy.yyamashita.com { + forward_proxy { +${AUTH_BLOCK} hide_ip + hide_via + } +} +https://proxy.yyamashita.com { + tls { + key_type rsa4096 + } + forward_proxy { +${AUTH_BLOCK} hide_ip + hide_via + } +} +EOF + +exec "$@" diff --git a/git/hooks/hetzner-infra/post-receive b/git/hooks/hetzner-infra/post-receive index dbb450d..6eeff49 100755 --- a/git/hooks/hetzner-infra/post-receive +++ b/git/hooks/hetzner-infra/post-receive @@ -6,5 +6,4 @@ bash /app/infra/cgit/deploy.sh bash /app/infra/mail/deploy.sh bash /app/infra/hetzner-admin/deploy.sh bash /app/infra/vpn/deploy.sh -bash /app/infra/proxy/deploy.sh echo "Deploy complete: hetzner-infra" diff --git a/mail/dns/setup-route53.py b/mail/dns/setup-route53.py index f42e273..9455c0c 100755 --- a/mail/dns/setup-route53.py +++ b/mail/dns/setup-route53.py @@ -38,6 +38,7 @@ WEB_SUBDOMAINS = [ "hetzner-admin", "blog", "vpn", + "proxy", ] diff --git a/proxy/Dockerfile b/proxy/Dockerfile deleted file mode 100644 index f11141b..0000000 --- a/proxy/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM alpine:3.21 -RUN apk add --no-cache squid openssl -COPY squid.conf /etc/squid/squid.conf -COPY entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh -ENTRYPOINT ["/entrypoint.sh"] diff --git a/proxy/deploy.sh b/proxy/deploy.sh deleted file mode 100644 index 3f5c6ba..0000000 --- a/proxy/deploy.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -cd "$(dirname "$0")" - -if [ ! -f certs/server.crt ]; then - echo "Proxy: 未初期化のためスキップ (install.sh を実行してください)" - exit 0 -fi - -docker compose up -d --build diff --git a/proxy/docker-compose.yml b/proxy/docker-compose.yml deleted file mode 100644 index 81a7fa6..0000000 --- a/proxy/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - proxy: - build: . - restart: unless-stopped - network_mode: host - volumes: - - ./certs/server.crt:/etc/squid/certs/server.crt:ro - - ./certs/server.key:/etc/squid/certs/server.key:ro - - /app/infra/vpn/users.conf:/etc/proxy/users.conf:ro diff --git a/proxy/entrypoint.sh b/proxy/entrypoint.sh deleted file mode 100644 index b7cc6e2..0000000 --- a/proxy/entrypoint.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -set -e - -# VPN と共有の users.conf から basic auth passwd ファイルを生成 -> /etc/squid/passwd -while IFS=' ' read -r user pass || [ -n "$user" ]; do - [ -z "$user" ] && continue - case "$user" in \#*) continue ;; esac - echo "${user}:$(openssl passwd -apr1 "$pass")" >> /etc/squid/passwd -done < /etc/proxy/users.conf -chmod 600 /etc/squid/passwd - -exec squid -N -f /etc/squid/squid.conf diff --git a/proxy/install.sh b/proxy/install.sh deleted file mode 100644 index 58a8e53..0000000 --- a/proxy/install.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -cd "$(dirname "$0")" - -echo "=== Proxy Install: proxy.yyamashita.com ===" -bash "$(pwd)/renew-cert.sh" - -echo "" -echo "=== Proxy 起動完了 ===" -echo " アドレス: https://proxy.yyamashita.com:8443" -echo " 認証: VPN と同じユーザー名/パスワード (Basic 認証)" -echo " 証明書の更新: bash /app/infra/proxy/renew-cert.sh" diff --git a/proxy/renew-cert.sh b/proxy/renew-cert.sh deleted file mode 100644 index 8924d9b..0000000 --- a/proxy/renew-cert.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -cd "$(dirname "$0")" - -DOMAIN="proxy.yyamashita.com" -CADDY_DIR="/app/infra/caddy" -CADDY_CERT_BASE="/data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${DOMAIN}/${DOMAIN}" - -echo "証明書を更新中..." -mkdir -p certs - -if ! docker compose -f "$CADDY_DIR/docker-compose.yml" exec -T caddy \ - cat "${CADDY_CERT_BASE}.crt" > certs/server.crt; then - echo "Error: 証明書の取得に失敗しました。Caddyfile に ${DOMAIN} が設定されているか確認してください。" - exit 1 -fi -docker compose -f "$CADDY_DIR/docker-compose.yml" exec -T caddy \ - cat "${CADDY_CERT_BASE}.key" > certs/server.key -chmod 600 certs/server.key - -echo "証明書を更新しました。" -bash "$(pwd)/deploy.sh" diff --git a/proxy/squid.conf b/proxy/squid.conf deleted file mode 100644 index 29ebd05..0000000 --- a/proxy/squid.conf +++ /dev/null @@ -1,21 +0,0 @@ -https_port 8443 cert=/etc/squid/certs/server.crt key=/etc/squid/certs/server.key - -auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwd -auth_param basic realm "Proxy" -auth_param basic credentialsttl 2 hours - -acl authenticated proxy_auth REQUIRED -http_access allow authenticated -http_access deny all - -forwarded_for delete -via off - -dns_nameservers 1.1.1.1 8.8.8.8 - -cache_dir null /tmp -cache deny all -access_log stdio:/dev/stdout -cache_log stdio:/dev/stderr -cache_store_log none -coredump_dir /tmp |
