summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryyamashita <yyamashita@hetzner.yyamashita.com>2026-07-02 23:08:58 +0900
committeryyamashita <yyamashita@hetzner.yyamashita.com>2026-07-02 23:08:58 +0900
commit1a7b5adf8484ec0f2b6feb350b578142e186ab26 (patch)
treee8c670ac5554d2b17b491ee96e9717f4432d64a9
parent88be3b3f503d4674d764a7265edb2d4e380ae738 (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.md33
-rw-r--r--caddy/Caddyfile7
-rw-r--r--caddy/Dockerfile9
-rw-r--r--caddy/docker-compose.yml3
-rw-r--r--caddy/entrypoint.sh35
-rwxr-xr-xgit/hooks/hetzner-infra/post-receive1
-rwxr-xr-xmail/dns/setup-route53.py1
-rw-r--r--proxy/Dockerfile6
-rw-r--r--proxy/deploy.sh10
-rw-r--r--proxy/docker-compose.yml9
-rw-r--r--proxy/entrypoint.sh13
-rw-r--r--proxy/install.sh12
-rw-r--r--proxy/renew-cert.sh22
-rw-r--r--proxy/squid.conf21
14 files changed, 66 insertions, 116 deletions
diff --git a/CLAUDE.md b/CLAUDE.md
index 9f2890b..3a5188f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -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