summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryyamashita <yyamashita@hetzner.yyamashita.com>2026-07-11 20:35:09 +0900
committeryyamashita <yyamashita@hetzner.yyamashita.com>2026-07-11 20:35:09 +0900
commit5b4aee69b4c6bf295bc44aad6171e17a0d80e63c (patch)
treec64e23a7ee1831725d6151179839428e3e05e46d
parente14f9edcb95875e2519461690915ab3e25740e96 (diff)
Dedupe Caddyfile with snippets, sync docs with reality, add tests/check.sh
- Caddyfile: extract repeated header blocks into (noindex)/(crawler_bypass) snippets (adapted JSON verified byte-identical to previous config) - CLAUDE.md: add mosquitone-admin/microblog to repos table; document that proxy auth is disabled (PROXY_NO_AUTH=1) with JP-only IP filter instead - Deploy.md/caddy/README.md: reflect all-service deploy and forward proxy - tests/check.sh: shell/python syntax, repos.txt<->hooks<->sessions.txt consistency, app.py COMMANDS vs run-command.sh whitelist, secrets check Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
-rw-r--r--.gitignore1
-rw-r--r--CLAUDE.md17
-rw-r--r--Deploy.md4
-rw-r--r--caddy/Caddyfile32
-rw-r--r--caddy/README.md13
-rwxr-xr-xtests/check.sh117
6 files changed, 156 insertions, 28 deletions
diff --git a/.gitignore b/.gitignore
index fd755d9..1c6531b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
.DS_Store
hetzner-admin/id_rsa
hetzner-admin/id_rsa.pub
+__pycache__/
diff --git a/CLAUDE.md b/CLAUDE.md
index 3a5188f..1ab0691 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -33,10 +33,15 @@ server/ サーバー共通設定(authorized_keys, requirements.md)
| hetzner-infra | /app/infra |
| tokyo-livehouse-events | /app/tokyo-livehouse-events |
| whois-band | /app/whois-band |
+| mosquitone-admin | /home/yyamashita/workspaces/repos/mosquitone-admin |
+| microblog | /app/microblog |
## よく使うコマンド
```bash
+# 整合性チェック(push 前に実行推奨)
+bash tests/check.sh
+
# Caddy 設定変更
vi caddy/Caddyfile && git push origin master
@@ -112,12 +117,11 @@ docker compose -f /app/infra/vpn/docker-compose.yml restart
# Proxy 初回セットアップ(Caddy に統合済み。追加作業なし)
# → push するだけで Caddy が proxy.yyamashita.com の証明書を自動取得
# → proxy.yyamashita.com:80 (HTTP) / :443 (HTTPS) でフォワードプロキシとして動作
-# → 認証は VPN と同じ users.conf を共有
+# → 認証は無効(PROXY_NO_AUTH=1)。代わりに日本国内 IP のみ許可(ipdeny.com の JP CIDR リスト)
-# 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 認証を有効に戻す場合
+vi caddy/docker-compose.yml # PROXY_NO_AUTH=1 を削除(VPN と同じ users.conf の Basic 認証に戻る)
+git push origin master
# DNS 登録(初回のみ。setup-route53.py に proxy が含まれている)
ssh root@<server>
@@ -147,4 +151,5 @@ python3 /app/infra/mail/dns/setup-route53.py
- HTTP プロキシ: `proxy.yyamashita.com:80`
- HTTPS プロキシ: `proxy.yyamashita.com:443`
-- 認証: Basic 認証(VPN と同じユーザー名/パスワード)
+- 認証: なし(`PROXY_NO_AUTH=1`)。日本国内 IP からのみ接続可能
+ (有効化すると VPN と同じ `users.conf` の Basic 認証になる)
diff --git a/Deploy.md b/Deploy.md
index dfa517b..9797459 100644
--- a/Deploy.md
+++ b/Deploy.md
@@ -17,9 +17,11 @@ ssh root@<server-ip> 'bash /app/infra/git/install.sh'
## 通常デプロイ
```bash
-git push origin master # Caddy 設定・cgit コンテナ更新(自動再ビルド含む)
+git push origin master # caddy / cgit / mail / hetzner-admin / vpn を再デプロイ(自動再ビルド含む)
```
+push 前に `bash tests/check.sh` で整合性チェックを実行できる。
+
## フック / リポジトリ定義を変更した場合
```bash
diff --git a/caddy/Caddyfile b/caddy/Caddyfile
index d5624c5..90abecb 100644
--- a/caddy/Caddyfile
+++ b/caddy/Caddyfile
@@ -2,46 +2,45 @@
order forward_proxy before redir
}
-golive.yyamashita.com {
+(noindex) {
header Referrer-Policy "no-referrer"
header X-Robots-Tag "noindex, nofollow"
+}
+(crawler_bypass) {
@crawler_bypass header X-Crawler-Access "f9a3c1e847b2d056"
header @crawler_bypass -X-Robots-Tag
+}
+golive.yyamashita.com {
+ import noindex
+ import crawler_bypass
reverse_proxy tokyo-app:3000
}
whoisband.yyamashita.com {
- header Referrer-Policy "no-referrer"
- header X-Robots-Tag "noindex, nofollow"
-
- @crawler_bypass header X-Crawler-Access "f9a3c1e847b2d056"
- header @crawler_bypass -X-Robots-Tag
-
+ import noindex
+ import crawler_bypass
reverse_proxy whois-app:3000
}
+
code.yyamashita.com {
- header Referrer-Policy "no-referrer"
- header X-Robots-Tag "noindex, nofollow"
+ import noindex
reverse_proxy 172.19.0.1:8080
}
git.yyamashita.com {
- header Referrer-Policy "no-referrer"
- header X-Robots-Tag "noindex, nofollow"
+ import noindex
reverse_proxy cgit:80
}
hetzner-admin.yyamashita.com {
- header Referrer-Policy "no-referrer"
- header X-Robots-Tag "noindex, nofollow"
+ import noindex
reverse_proxy hetzner-admin:5000
}
blog.yyamashita.com {
- header Referrer-Policy "no-referrer"
- header X-Robots-Tag "noindex, nofollow"
+ import noindex
reverse_proxy microblog-app:3000
}
@@ -51,8 +50,7 @@ vpn.yyamashita.com {
tls {
key_type rsa4096
}
- header Referrer-Policy "no-referrer"
- header X-Robots-Tag "noindex, nofollow"
+ import noindex
route /ca.pem {
header Content-Type "application/x-pem-file"
header Content-Disposition "attachment; filename=\"vpn-ca.pem\""
diff --git a/caddy/README.md b/caddy/README.md
index 2faf232..f3222a4 100644
--- a/caddy/README.md
+++ b/caddy/README.md
@@ -1,11 +1,16 @@
# caddy
-Caddy によるリバースプロキシ設定。`git push` で自動デプロイされる。
+Caddy によるリバースプロキシ + フォワードプロキシ設定。`git push` で自動デプロイされる。
| ファイル | 内容 |
|---|---|
-| `Caddyfile` | ホスト別ルーティング定義 |
-| `docker-compose.yml` | Caddy コンテナ定義 |
+| `Caddyfile` | ホスト別ルーティング定義(共通ヘッダーはスニペット `(noindex)` / `(crawler_bypass)`) |
+| `Dockerfile` | forwardproxy プラグイン入りの Caddy を xcaddy でビルド |
+| `entrypoint.sh` | 起動時に `/tmp/proxy_forward.caddy` を生成(Basic 認証 + 日本 IP 限定フィルタ) |
+| `docker-compose.yml` | Caddy コンテナ定義(`PROXY_NO_AUTH=1` でプロキシ認証を無効化中) |
| `deploy.sh` | post-receive フックから呼ばれるデプロイスクリプト |
-新しいホストを追加する場合は `Caddyfile` を編集して push する。
+- 新しいホストを追加する場合は `Caddyfile` を編集して push する。
+- フォワードプロキシは `proxy.yyamashita.com:80/443`。認証は無効(`PROXY_NO_AUTH=1`)で、
+ 代わりに ipdeny.com の JP CIDR リストで日本国内 IP のみ許可している。
+- `entrypoint.sh` の変更はイメージ再ビルドが必要(`deploy.sh` の `--build` で push だけで反映される)。
diff --git a/tests/check.sh b/tests/check.sh
new file mode 100755
index 0000000..99add68
--- /dev/null
+++ b/tests/check.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+# リポジトリの整合性チェック。push 前に実行する: bash tests/check.sh
+set -uo pipefail
+cd "$(dirname "$0")/.."
+
+FAIL=0
+ok() { echo " ok: $*"; }
+ng() { echo " NG: $*"; FAIL=1; }
+
+echo "=== シェルスクリプト構文 ==="
+while IFS= read -r f; do
+ if bash -n "$f" 2>/dev/null; then
+ ok "$f"
+ else
+ ng "$f"
+ bash -n "$f" || true
+ fi
+done < <(find . -name '*.sh' -not -path './.git/*' | sort)
+while IFS= read -r f; do
+ if bash -n "$f" 2>/dev/null; then
+ ok "$f"
+ else
+ ng "$f"
+ bash -n "$f" || true
+ fi
+done < <(find git/hooks -type f -name 'post-receive' | sort)
+
+echo ""
+echo "=== Python 構文 ==="
+for f in hetzner-admin/app.py mail/dns/setup-route53.py; do
+ if python3 -m py_compile "$f" 2>/dev/null; then
+ ok "$f"
+ else
+ ng "$f"
+ python3 -m py_compile "$f" || true
+ fi
+done
+
+echo ""
+echo "=== repos.txt と git/hooks/ の整合性 ==="
+mapfile -t repos < <(grep -vE '^\s*(#|$)' git/repos.txt | cut -d: -f1)
+for repo in "${repos[@]}"; do
+ if [[ -f "git/hooks/$repo/post-receive" ]]; then
+ ok "repos.txt: $repo → hooks あり"
+ else
+ ng "repos.txt: $repo のフックがない (git/hooks/$repo/post-receive)"
+ fi
+done
+for dir in git/hooks/*/; do
+ name="$(basename "$dir")"
+ if printf '%s\n' "${repos[@]}" | grep -qx "$name"; then
+ ok "hooks: $name → repos.txt に定義あり"
+ else
+ ng "hooks: $name が repos.txt に定義されていない"
+ fi
+done
+
+echo ""
+echo "=== sessions.txt のリポジトリが repos.txt に存在するか ==="
+while IFS=: read -r user repo; do
+ [[ "$user" =~ ^#.*$ || -z "$user" ]] && continue
+ if printf '%s\n' "${repos[@]}" | grep -qx "$repo"; then
+ ok "sessions.txt: $user:$repo"
+ else
+ ng "sessions.txt: $repo が repos.txt に定義されていない"
+ fi
+done < claude/sessions.txt
+
+echo ""
+echo "=== hetzner-admin: app.py の COMMANDS が run-command.sh で許可されているか ==="
+while IFS= read -r cmd; do
+ if grep -qF "\"$cmd\")" hetzner-admin/run-command.sh; then
+ ok "$cmd"
+ else
+ ng "run-command.sh のホワイトリストにない: $cmd"
+ fi
+done < <(python3 - <<'EOF'
+import ast
+tree = ast.parse(open("hetzner-admin/app.py").read())
+for node in ast.walk(tree):
+ if isinstance(node, ast.Assign) and getattr(node.targets[0], "id", "") == "COMMANDS":
+ for elt in node.value.elts:
+ print(elt.elts[1].value)
+EOF
+)
+
+echo ""
+echo "=== 秘密ファイルがコミットされていないか ==="
+for name in users.conf id_rsa id_rsa.pub .env; do
+ regex="(^|/)$(printf '%s' "$name" | sed 's/\./\\./g')\$"
+ if git ls-files | grep -qE "$regex"; then
+ ng "コミットされている: $(git ls-files | grep -E "$regex")"
+ else
+ ok "$name は未コミット"
+ fi
+done
+
+echo ""
+echo "=== Caddyfile 検証(docker が使える場合のみ) ==="
+if docker info >/dev/null 2>&1 && docker image inspect caddy-caddy:latest >/dev/null 2>&1; then
+ if docker run --rm -v "$PWD/caddy:/etc/caddy:ro" caddy-caddy:latest \
+ caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile >/dev/null 2>&1; then
+ ok "Caddyfile valid"
+ else
+ ng "Caddyfile が無効"
+ fi
+else
+ echo " skip: docker にアクセスできない(root で実行すると検証される)"
+fi
+
+echo ""
+if [[ "$FAIL" -eq 0 ]]; then
+ echo "All checks passed."
+else
+ echo "FAILED: 上記の NG を修正してください。"
+ exit 1
+fi