#!/bin/bash # SSH authorized_keys の command= から呼ばれる。$SSH_ORIGINAL_COMMAND をホワイトリストで検証する。 set -e # 管理画面から停止・起動できるサービス(名前は status/targets.txt の名前に合わせる) # Caddy / hetzner-admin / status は止めると管理画面に戻れなくなるので対象外 SERVICES="golive whoisband blog todo git vpn ntfy mail code" # docker compose ではなく systemd で動くサービス service_unit() { case "$1" in code) echo code-server@yyamashita.service ;; *) return 1 ;; esac } service_compose() { case "$1" in golive) echo /app/tokyo-livehouse-events/docker-compose.yml ;; whoisband) echo /app/whois-band/docker-compose.yml ;; blog) echo /app/microblog/docker-compose.yml ;; todo) echo /app/todo/docker-compose.yml ;; git) echo /app/infra/cgit/docker-compose.yml ;; vpn) echo /app/infra/vpn/docker-compose.yml ;; ntfy) echo /app/infra/ntfy/docker-compose.yml ;; mail) echo /app/infra/mail/docker-compose.yml ;; *) return 1 ;; esac } # 管理画面で停止したサービスの一覧。status-app が読み、DOWN ではなく STOPPED と表示する STOPPED_FILE=/app/infra/status/stopped.txt case "$SSH_ORIGINAL_COMMAND" in "services") touch "$STOPPED_FILE" for name in $SERVICES; do if unit=$(service_unit "$name"); then if systemctl is-active --quiet "$unit"; then state=running; else state=stopped; fi else running=$(docker compose -f "$(service_compose "$name")" ps -q --status running 2>/dev/null | wc -l) if [ "$running" -gt 0 ]; then state=running; else state=stopped; fi fi echo "$name $state" done ;; "stop "*|"start "*) action="${SSH_ORIGINAL_COMMAND%% *}" name="${SSH_ORIGINAL_COMMAND#* }" unit=$(service_unit "$name") || compose=$(service_compose "$name") || { echo "Unknown service: $name" >&2; exit 1; } touch "$STOPPED_FILE" if [ "$action" = stop ]; then grep -qx "$name" "$STOPPED_FILE" || echo "$name" >> "$STOPPED_FILE" # systemd は disable もして、再起動後も停止したままにする(docker の unless-stopped と同じ扱い) if [ -n "$unit" ]; then systemctl disable --now "$unit" 2>&1; else docker compose -f "$compose" stop 2>&1; fi else sed -i "/^${name}\$/d" "$STOPPED_FILE" if [ -n "$unit" ]; then systemctl enable --now "$unit" 2>&1; else docker compose -f "$compose" up -d 2>&1; fi fi ;; "docker ps") exec docker ps ;; "docker compose -f /app/infra/caddy/docker-compose.yml restart") exec docker compose -f /app/infra/caddy/docker-compose.yml restart ;; "docker compose -f /app/infra/mail/docker-compose.yml restart") exec docker compose -f /app/infra/mail/docker-compose.yml restart ;; "docker compose -f /app/infra/cgit/docker-compose.yml restart") exec docker compose -f /app/infra/cgit/docker-compose.yml restart ;; "docker compose -f /app/infra/hetzner-admin/docker-compose.yml restart") exec docker compose -f /app/infra/hetzner-admin/docker-compose.yml restart ;; "bash /app/infra/claude/restart-sessions.sh") exec bash /app/infra/claude/restart-sessions.sh ;; "reboot") exec reboot ;; *) echo "Not allowed: $SSH_ORIGINAL_COMMAND" >&2 exit 1 ;; esac