Auto-deploy with GitHub Actions
← Back to README
Four workflows live in .github/workflows/:
ci.ymlruns on every PR and push: shellcheck on shell scripts, hadolint on the Dockerfiles, actionlint on the workflows themselves, anddocker compose config -qto validate the compose file. Lint-only, no image build, ~30 seconds.deploy.ymlruns on pushes tomain(and via manual dispatch). It SSHs into the VPS, syncs code, writes.envfrom GitHub Secrets, runsdocker compose pull && docker compose up -d, and prunes dangling images. Telegram notifications are sent on success and failure.build-images.ymlruns whentakopi/**orobsidian-headless/**changes onmain(or on Release publish). It builds and pushes multi-arch (amd64+arm64) images to GHCR with tagslatest,<short-sha>, and (for releases)v<X.Y.Z>.inspect.ymlis a manual-dispatch diagnostic workflow. SSHes to the VPS and prints the deployed commit, sanitized.envcontents, container status, sizes of theCLAUDE.{base,local,md}layers, the assembledvault/CLAUDE.mdas the agent sees it, the takopi container’s resolvedCLAUDE_EXTRA_INSTRUCTIONS, and recent entrypoint output. Run it from Actions → Inspect VPS → Run workflow when the agent’s behavior doesn’t match expectations.
Required GitHub Secrets
| Secret | Description |
|---|---|
VPS_HOST |
IP address or hostname of your VPS |
VPS_USER |
SSH username (e.g. deploy) |
VPS_SSH_KEY |
SSH private key (full contents of ~/.ssh/id_ed25519) |
TELEGRAM_BOT_TOKEN |
Telegram bot token |
TELEGRAM_CHAT_ID |
Chat ID where the bot listens |
ANTHROPIC_API_KEY |
Anthropic API key |
Optional secrets mirror the .env variables — see .env.example for the full list.
CLAUDE_EXTRA_INSTRUCTIONS (additional rules for the agent — not actually a secret) can be set as either a GitHub Actions Variable (Settings → Secrets and variables → Actions → Variables tab) or a Secret. Variables are preferred: they’re visible in plain text in the UI, easy to inspect and edit, and not masked in logs. The deploy workflow reads vars.CLAUDE_EXTRA_INSTRUCTIONS first and falls back to secrets.CLAUDE_EXTRA_INSTRUCTIONS.
To trigger a deploy without a code push: Actions > Deploy > Run workflow.
What persists between deploys
| Path | Contents |
|---|---|
./vault/ |
Obsidian notes — gitignored, untouched by deploy |
./takopi-state/ |
Takopi session data — gitignored |
./obsidian-state/ |
Obsidian Sync auth — gitignored |
Setting up SSH access for CI
Generate a dedicated key for GitHub Actions on your local machine:
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/obsidian-deploy -N ""
Add the public key to the VPS:
ssh root@<VPS_IP> "mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
echo '$(cat ~/.ssh/obsidian-deploy.pub)' >> ~/.ssh/authorized_keys && \
chmod 600 ~/.ssh/authorized_keys"
Copy the contents of ~/.ssh/obsidian-deploy (the private key, including BEGIN/END lines) into the VPS_SSH_KEY secret on GitHub.
Once secrets are set, trigger a manual deploy via Actions > Deploy > Run workflow to verify the connection. Subsequent pushes to main will deploy automatically.