appgarden について
appgarden は、`appgarden` CLI と SSH を使ってリモートサーバー上の Web アプリをデプロイ・運用するスキルです。複数のデプロイ方式に対応し、プロジェクト設定で環境ごとの管理ができます。
主な機能
- 01SSH 経由のアプリデプロイ
- 02静的・コマンド・Docker 方式
- 03appgarden.toml による環境設定
- 04アプリ状態とログの確認
- 05アプリのライフサイクル管理
活用シーン
- 01静的サイトのリモートサーバーへの配置
- 02staging と production 環境への公開
- 03状態確認とログによるトラブル調査
- 04アプリの再起動・停止・再デプロイ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lukastk/ appgarden --skill appgardenインストール後、Claude Code で/appgardenを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.env.sample.envrcCLAUDE.md.gitignoreREADME.mdNBLITE_INSTRUCTIONS.mdnblite.toml.github/workflows/ci.ymlrelease.ymldev_scripts/clean-projectpublish-newrun-testspts/appgarden/01_remote.pct.py03_routing.pct.py00_config.pct.py06_apps.pct.py05_deploy.pct.py04_server.pct.py08_environments.pct.py07_auto_docker.pct.py02_ports.pct.py09_tunnel.pct.py_dir_server.pct.py10_cli.pct.pypts/tests/test_cli.pct.pytest_deploy.pct.pytest_apps.pct.pytest_environments.pct.pypts/tests/integration/test_server_init.pct.pyconftest.pct.py詳細
AppGarden CLI スキル
appgarden CLI を使用して Web アプリケーションをデプロイまたは運用する際に、このスキルを使用します。
AppGarden はエージェントレスのデプロイツールです。ローカルの CLI が SSH 経由で接続し、リモートサーバーを準備して、アプリのソースをアップロードまたはクローンし、Caddy/systemd/Docker のファイルを書き込み、サーバーの AppGarden ルート(デフォルトは /srv/appgarden)に状態を記録します。
コマンドを実行する前に
-
AppGarden 自体を開発/テストする場合は、AppGarden リポジトリのチェックアウトから実行することを推奨します。
cd /path/to/appgarden && uv run appgarden ...AppGarden が環境にインストールされている場合は、
appgarden ...を使用してもかまいません。 -
読み取り専用の安全な確認コマンドは、確認なしで実行してかまいません:
appgarden --help、appgarden version、appgarden config show、appgarden server list、appgarden server ping、appgarden apps list、appgarden apps status、appgarden apps logs、appgarden tunnel list。 -
作成、変更、デプロイ、再起動、停止、削除、またはサービスの公開を行うコマンドを実行する前に、確認してください:
server add、server remove、server default、server init、deploy、apps start|stop|restart|redeploy|remove、apps meta set|replace|remove、tunnel open|close|cleanup。 -
次のコマンドには特に注意してください。
appgarden server init --include ssh:SSH の設定を強化し、sshd を再読み込みします。appgarden server init --include firewall:UFW を有効にし、ファイアウォールポリシーを変更します。appgarden apps remove NAME --yes:アプリのリソースを削除します。アプリのdata/ディレクトリを保持する意図がある場合に限り、--keep-dataを追加してください。appgarden deploy:既存アプリのアップロード済みソースを上書きし、Caddy/systemd/Docker のリソースを更新する場合があります。appgarden tunnel open:停止するまで、設定済みサーバーを介してローカルのポート/ファイル/ディレクトリをパブリックに公開します。
設定の保存場所
ローカル設定は次の場所に保存されます。
~/.config/appgarden/config.toml
サーバー設定の形式:
default_server = "myserver"
[defaults]
method = "dockerfile"
container_port = 3000
[servers.myserver]
host = "203.0.113.10" # or hcloud_name + hcloud_context
ssh_user = "root"
ssh_key = "~/.ssh/id_rsa"
domain = "apps.example.com"
app_root = "/srv/appgarden" # optional; defaults to /srv/appgarden
[servers.myserver.init]
skip = ["upgrades"] # optional persistent init skips
リモートの状態とリソースは app_root の下にあり、通常は次の場所です。
/srv/appgarden/garden.json # app registry
/srv/appgarden/apps/<name>/ # per-app files/source/app.json/.env/data
/srv/appgarden/caddy/apps/*.caddy # deployed app Caddy snippets
/srv/appgarden/caddy/tunnels/*.caddy
/srv/appgarden/tunnels/active.json
appgarden config show はローカル設定を表示します。サーバーを対象とするコマンドでは、--server <name>/-s <name> または APPGARDEN_SERVER を使用してください。指定がない場合、AppGarden は default_server を使用します。
1 台のホスト上に複数のガーデンを設置する場合:各 app_root(例:/srv/appgarden と /srv/appgarden-proto)を個別に指定することで、同じマシン上で複数の AppGarden ガーデンを実行できます。ガーデンごとの状態(garden.json)、Caddy スニペット、/etc/caddy/Caddyfile の管理対象ブロックは、すべて app_root ごとに管理されるため、あるガーデンで server init を実行しても、別のガーデンには影響しません。ただし、ポートはホスト全体で共有されるリソースです。すべてのガーデンがホストの TCP ポート空間を共有するため、ポートの割り当ては /var/lib/appgarden/ports.json にある単一のホストレベルのレジストリで管理され、すべてのガーデンが 1 つのロックを共有します。これにより、2 つのガーデンが同じホストポートを割り当てることを防ぎます。ポート範囲を設定する必要はありません。注意点:systemd ユニット名と Docker コンテナ名(appgarden-<name>)はホスト全体で共有されるため、1 台のホスト上にあるすべてのガーデン間でアプリ名を一意にする必要があります。共有レジストリ導入前のホストをアップグレードする場合は、既存のガーデンごとに 1 回 appgarden server init を実行してください。init は各ガーデンですでにデプロイされているアプリのポートを共有レジストリに反映します(べき等)。
サーバーのセットアップ
サーバーを設定し、SSH 経由で到達可能にし、DNS をそのサーバーに向ける必要があります。
appgarden server add myserver \
--host <server-ip-or-hostname> \
--ssh-user root \
--ssh-key ~/.ssh/id_rsa \
--domain apps.example.com
# Hetzner alternative: resolve IP through hcloud instead of --host
appgarden server add myserver \
--hcloud-name <hetzner-server-name> \
--hcloud-context <hcloud-context> \
--domain apps.example.com
appgarden server list
appgarden server ping myserver
appgarden server default myserver
サブドメインへのデプロイやトンネルを使用する場合は、*.apps.example.com などのワイルドカード DNS レコードを作成し、サーバーの IP アドレスを指定してください。明示的に指定するカスタムホスト名にも、サーバーを指す DNS レコードが必要です。
サーバーの初期化
サーバーごとに一度だけ実行します。
appgarden server init myserver
現在の server init の動作:
- デフォルトで有効な任意の手順。有効な手順を省略するには
--skipを指定します:update、docker、caddy、upgrades。 - デフォルトで無効なオプトイン手順。有効にするには
--includeを指定します:firewall、ssh、fail2ban、group。 - 必須の手順は常に実行されます:AppGarden の Caddyfile インポートブロックの設定、ディレクトリの作成、特権ヘルパー/sudoers エントリーのインストール、デプロイユーザーへの所有権設定、状態ファイルの初期化、利用可能な場合は Docker/Caddy の起動。
例:
appgarden server init myserver --minimal # essential steps only
appgarden server init myserver --skip upgrades # skip unattended-upgrades
appgarden server init myserver --include group # create/use appgarden group for non-root deploy users
appgarden server init myserver --include firewall # configure UFW; confirm first
appgarden server init myserver --include ssh # harden sshd; confirm first
root 以外の SSH ユーザーの場合、server init は /usr/local/bin/appgarden-privileged と、AppGarden の特権操作に限定した sudoers ルールをインストールします。
推奨デプロイフロー:appgarden.toml
プロジェクトのルートに appgarden.toml を作成し、名前付き環境をデプロイします。
[app]
name = "myapp"
slug = "my-app" # optional; used by {app.slug}; falls back to name
server = "myserver"
method = "dockerfile" # static | command | dockerfile | docker-compose | auto
source = "." # local path or git URL
container_port = 3000
subdomain = "{app.slug}" # or path/url; supports placeholders
exclude = ["node_modules", ".git"]
gitignore = true # local uploads honor .gitignore by default
meta = { team = "frontend" }
[environments.production]
branch = "main"
subdomain = "{app.slug}"
env = { NODE_ENV = "production" }
[environments.staging]
branch = "staging"
subdomain = "{app.slug}-staging"
env_file = ".env.staging"
meta = { visibility = "internal" }
デプロイ:
appgarden deploy production
appgarden deploy staging
appgarden deploy --all-envs
appgarden deploy --project /path/to/project production
appgarden.toml が存在し、環境名も名前も指定されていない場合、appgarden deploy はすべての環境をデプロイします。位置引数で環境を指定した場合、その環境が存在している必要があります。
appgarden.toml のセマンティクス
[app].nameは必須です。デプロイされるアプリ名はこの値から決まります:productionではベース名を使用し、それ以外の環境では<name>-<env>を使用します。例:myappおよびmyapp-staging。- 値は次の順序で適用されます:ハードコードされたデフォルト値 <
~/.config/appgarden/config.tomlのグローバルな[defaults]<[app]のデフォルト値 <[environments.<name>]< CLI フラグ/APPGARDEN_*環境変数。 envおよびmetaの辞書フィールドはキーごとにマージされます。環境/CLI の値は先に設定されたキーを上書きします。excludeおよびvolumesのリストフィールドは、各レイヤーの内容を連結して重複を削除します。- プロジェクト/環境設定の文字列値では、プレースホルダー
{app.name}、{app.slug}、{env.name}を使用できます。 - 相対パスのローカルな
sourceおよびenv_fileの値は、プロジェクトディレクトリ、または明示的に指定した--projectファイルを含むディレクトリを基準に解決されます。
[app] または [environments.<name>] で使用できるフィールド:
| フィールド | 意味 |
|---|---|
server | 設定済みのサーバー名。 |
method | static、command、dockerfile、docker-compose、または auto。デフォルトは static です。 |
source | ローカルディレクトリ/パス、または Git URL。static、dockerfile、docker-compose、auto では必須で、command では省略可能です。 |
url | 明示的に指定する公開ホスト名/パス。例:example.com または example.com/docs。 |
subdomain | domain またはサーバーのドメインと組み合わせるプレフィックス。例:docs -> docs.apps.example.com。 |
path | domain またはサーバーのドメイン配下のパス。例:docs -> apps.example.com/docs。 |
domain | subdomain/path に使用するサーバーのベースドメインを上書きします。 |
port | ホストポート。省略すると、AppGarden がポートの状態から自動割り当てします。 |
container_port | Dockerfile/auto コンテナー内で公開するポート。デフォルトは 3000 です。 |
cmd | command および auto メソッドの起動コマンド。どちらのメソッドでも必須です。 |
setup_cmd | auto 用のインストール/ビルドコマンド。検出されたランタイムのデフォルト値を上書きします。 |
branch | Git ソースのブランチ。 |
env | インライン環境変数。 |
env_file | ローカルの dotenv ファイル。 |
meta | アプリとともに保存され、ステータスに表示される任意のメタデータ。 |
exclude | ローカルアップロード用の Rsync 除外パターン。apps redeploy でも再利用されます。 |
gitignore | ローカルアップロードで Rsync の .gitignore フィルターを適用するかどうか。デフォルトは true です。CLI で上書きするには --no-gitignore を指定します。 |
volumes | dockerfile および auto 用の Docker ボリュームマウント(host:container[:opts])。 |
created_at、updated_at、repo | 任意のメタデータ上書き値。日付には短縮形式の日付、ISO 文字列、または TOML の日付を指定できます。repo は、可能な場合、ローカル Git の origin から自動検出されます。 |
URL の解決順序は次のとおりです:明示的な url、それがない場合は subdomain + ドメイン、それもない場合は path + ドメイン。サブディレクトリルーティング(domain/path)では、同じドメイン上の複数のアプリが生成された Caddy 設定を共有し、AppGarden が URL の競合をチェックします。
appgarden.toml を使わないアドホックデプロイ
--name とフラグを使います。ほとんどのフラグには、対応する APPGARDEN_* 環境変数(APPGARDEN_NAME、APPGARDEN_SERVER、APPGARDEN_METHOD、APPGARDEN_SOURCE、APPGARDEN_URL、APPGARDEN_SUBDOMAIN、APPGARDEN_PATH、APPGARDEN_DOMAIN、APPGARDEN_PORT、APPGARDEN_CONTAINER_PORT、APPGARDEN_CMD、APPGARDEN_SETUP_CMD、APPGARDEN_BRANCH、APPGARDEN_ENVVAR_FILE、APPGARDEN_PROJECT、APPGARDEN_ALL_ENVS)があります。
# Static site / SPA
appgarden deploy --name mysite --method static --source ./dist --subdomain mysite
# Dockerfile app
appgarden deploy --name myapp --method dockerfile --source . --container-port 3000 --subdomain myapp
# Auto-generated Dockerfile; runtime is detected from package.json, requirements.txt,
# pyproject.toml, Gemfile, go.mod, or Cargo.toml. --cmd is required.
appgarden deploy --name myapp --method auto --source . --cmd "npm start" --subdomain myapp
# Bare process managed by systemd. --source is optional; --cmd is required.
appgarden deploy --name myapi --method command --source ./api --cmd "python app.py" --subdomain myapi
# Docker Compose stack; your compose file is used directly.
appgarden deploy --name mystack --method docker-compose --source ./project --subdomain mystack
# Explicit path routing instead of subdomain routing
appgarden deploy --name docs --method static --source ./docs --url apps.example.com/docs
# Env, metadata, excludes, and volumes
appgarden deploy --name myapp --method dockerfile --source . --subdomain myapp \
--envvar NODE_ENV=production \
--envvar-file .env.production \
--meta team=backend --meta visibility=internal \
--exclude node_modules --exclude .git \
--volume ./data:/app/data \
--no-gitignore
デプロイ方法に関する注意事項:
| 方法 | 用途 | 必須の入力 | 実行時の動作 |
|---|---|---|---|
static | HTML/CSS/JS/SPA | source | ソースをアップロード/クローンし、Caddy で直接配信します。 |
command | Docker を使わないローカルプロセス | cmd(source は任意) | 割り当て済み/明示的なポートを PORT に設定して systemd サービスを作成します。 |
dockerfile | Dockerfile があるプロジェクト | source | リモートでイメージをビルドし、AppGarden の compose ファイルを書き込み、systemd 経由で実行します。 |
docker-compose | 既存の compose プロジェクト | source | docker compose up/down を systemd 経由で実行します。volumes の設定は注入されません。 |
auto | シンプルな Node/Python/Ruby/Go/Rust プロジェクト | source、cmd | ランタイムを検出し、Dockerfile を書き込み、イメージをビルドして、compose ファイルを書き込みます。 |
ローカルからアップロードする場合、AppGarden は --delete を指定して rsync を使い、デフォルトで .gitignore を適用し、--exclude/exclude パターンも適用します。Git ソースの場合は、リモートでリポジトリをクローンし、必要に応じて指定されたブランチをチェックアウトします。
デプロイするアプリの .env ファイルでは、環境変数の優先順位は appgarden.toml の env < env_file の内容 < CLI の --envvar 値です。
デプロイ済みアプリの管理
appgarden apps list [-s server] [--short]
appgarden apps status <name> [-s server]
appgarden apps logs <name> [-s server] [-n 100]
appgarden apps restart <name> [-s server]
appgarden apps redeploy <name> [-s server]
appgarden apps stop <name> [-s server]
appgarden apps start <name> [-s server]
appgarden apps remove <name> [-s server] [--keep-data] [--yes]
運用上のガイダンス:
-
アプリ名が正確にわからない場合は、まず
apps listを使います。 -
apps statusを使うと、URL、ルーティング、方法、ポート、リポジトリ/ソース、タイムスタンプ、メタデータを確認できます。 -
デバッグ時は、再起動する前に
apps logs NAME -n 200を使います。 -
apps redeployはソースを更新します。Git アプリではgit pullを実行し(保存済みのブランチがある場合はそのブランチを使用)、ローカルソースのアプリでは保存済みのexclude/gitignoreを使って再アップロードします。Dockerfile/auto アプリではイメージを再ビルドし、保存済みのボリュームを保持します。static アプリでは Caddy を再読み込みします。 -
appgarden.tomlでアプリ名を変更する場合は、URL/Caddy の競合を避けるため、先に古いアプリを削除します。appgarden apps remove old-name --yes appgarden deploy production
メタデータ
メタデータは、アプリとともに保存される任意の JSON 互換キー/値データです。
appgarden apps meta get myapp [-s server]
appgarden apps meta set myapp --meta team=backend --meta tier=premium [-s server]
appgarden apps meta replace myapp --json '{"team":"frontend"}' [-s server]
appgarden apps meta remove myapp tier visibility [-s server]
appgarden.toml では、meta ディクショナリは env ディクショナリと同様にマージされます。
[app]
name = "myapp"
meta = { team = "backend", visibility = "internal" }
[environments.production]
meta = { visibility = "public" }
# result: { team = "backend", visibility = "public" }
Localhost トンネル
トンネルを使用すると、ローカルの開発サーバー、ファイル、ディレクトリ、またはコマンドを、HTTPS を使ってリモートサーバー経由で公開できます。--cmd/--serve とともに --close-on-cmd-exit を指定しない限り、トンネルは Ctrl+C が押されるまで終了しません。
# Expose an existing local server. URL omitted => random three-word subdomain.
appgarden tunnel open 3000
# Use server domain subdomain shorthand or an explicit URL
appgarden tunnel open 3000 --subdomain preview
appgarden tunnel open 3000 --url preview.apps.example.com
# Run a local command while the tunnel is open
appgarden tunnel open 3000 --cmd "npm run dev"
appgarden tunnel open 3000 --cmd "npm run dev" --close-on-cmd-exit
# Serve a local file or directory. LOCAL_PORT is optional with --serve.
appgarden tunnel open --serve ./dist --subdomain docs-preview
appgarden tunnel open --serve ./dist --include "*.html" --exclude "node_modules"
# Reclaim a URL a dead run still holds, then open (idempotent re-open)
appgarden tunnel open 3000 --url preview.apps.example.com --replace
appgarden tunnel list [-s server]
appgarden tunnel list --json [-s server] # machine-readable, for scripting
appgarden tunnel close <tunnel-id> [-s server]
appgarden tunnel cleanup [-s server]
--cmd と --serve は同時に指定できません。--include/--exclude は、--serve の対象がディレクトリの場合にのみ適用されます。トンネルはリモートポートを割り当て、caddy/tunnels に Caddy の設定スニペットを書き込み、tunnels/active.json に状態を登録します。クリーンアップ時に、これらのリソースは削除されます。
無人で再オープンするには、--replace が必要です。 トンネルの Caddy 設定スニペットは、トンネル固有の ID をキーとしているため、クリーンアップせずにプロセスが終了した場合(再起動や SIGKILL など)、スニペットがホスト名を占有したまま残ります。その状態で同じ --url を指定して次に tunnel open を実行すると、Caddy の再読み込みが ambiguous site definition エラーで失敗し、トンネルはロールバックされます。--replace を指定すると、その URL に登録済みのトンネルがあれば先に閉じます。明示的な --url/--subdomain が必要です。サブドメインを自動生成する場合は照合できるものがないため、何もせずに処理を続けるのではなく、拒否されます。なお、tunnel cleanup は代わりにはなりません。リモートポートで待ち受けているプロセスがないトンネルだけを削除します。
トンネルは Ctrl+C だけでなく SIGTERM でも正常に終了するため、supervisord、systemd、docker stop などで監視対象を停止すると、登録、Caddy の設定スニペット、リモートポートが解放され、残存しません。
tunnel list --json は JSON 配列を出力します(トンネルがない場合は空の配列を出力し、人間向けの「No active tunnels.」という行は出力しません)。テーブルではなく、こちらを解析してください。
トラブルシューティングのワークフロー
-
設定とサーバーの指定先を確認します。
appgarden config show appgarden server list appgarden server ping <server> -
アプリの状態とログを確認します。
appgarden apps list --short appgarden apps status <app> appgarden apps logs <app> -n 200 -
エラーを読んでから、再デプロイまたは再起動します。
appgarden apps redeploy <app> appgarden apps restart <app> -
ローカルのソースをアップロードする際によくある問題:
- ローカルに
rsyncがインストールされている必要があります。 - 暗号化された SSH キーにはエージェントが必要です:
eval $(ssh-agent) && ssh-add ~/.ssh/id_rsa。 - root 以外でデプロイする際の権限エラーは、通常、
appgarden server init --include groupを再実行するか、リモートの所有者を修正する必要があることを示します。
- ローカルに
このリポジトリのリファレンスファイル
生成された src/appgarden/*.py ファイルには「AUTOGENERATED」と記載されています。実装を変更する場合は通常、対応するソースファイル pts/appgarden/*.pct.py を編集してください。スキルや使用方法については、必要に応じて以下のファイルを参照してください。
README.md— ユーザー向けガイドと CLI リファレンス。src/appgarden/cli.py/pts/appgarden/10_cli.pct.py— コマンド定義とオプション。src/appgarden/config.py/pts/appgarden/00_config.pct.py— ローカル設定モデルとデフォルトの設定パス。src/appgarden/environments.py/pts/appgarden/08_environments.pct.py—appgarden.tomlの解析、マージの仕様、プレースホルダー。src/appgarden/server.py/pts/appgarden/04_server.pct.py— サーバーの初期化手順。src/appgarden/deploy.py/pts/appgarden/05_deploy.pct.py— デプロイの動作とリモートの状態。src/appgarden/apps.py/pts/appgarden/06_apps.pct.py— アプリのライフサイクルと再デプロイの動作。src/appgarden/routing.py/pts/appgarden/03_routing.pct.py— Caddy のルーティングと URL の競合時の動作。src/appgarden/tunnel.py/pts/appgarden/09_tunnel.pct.py— トンネルの動作。