Skip to content

Migrate deployment from cloud-init/kamal to fly.io#168

Open
capotej wants to merge 5 commits into
mainfrom
fly
Open

Migrate deployment from cloud-init/kamal to fly.io#168
capotej wants to merge 5 commits into
mainfrom
fly

Conversation

@capotej

@capotej capotej commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Replaces the kamal/cloud-init/EC2 deployment with a signed image published
to GHCR and deployed to fly.io.

What's new

  • .github/workflows/docker.yml — builds a linux/arm64 image, pushes
    to GHCR, and signs it with cosign (keyless OIDC) + a SLSA provenance
    attestation. Triggers on push to main, releases, and manual dispatch.
  • .github/actions/attest-provenance/ — composite action running
    cosign attest with a SLSA v0.2 predicate.
  • fly.toml — Thruster on :80, edge TLS, persistent abbey_data volume
    at /rails/storage, Solid Queue in Puma, arm64, scale-to-zero.

Removed

  • kamal gem (+ transitive deps) from Gemfile/Gemfile.lock
  • config/deploy.yml, .kamal/, bin/kamal, lib/tasks/cloud_init.rake
  • AWS/kamal README section (rewritten for fly.io)

Notes for first deploy

  • Fix volume ownership once after first deploy:
    flyctl ssh console -C "sudo chown -R 1000:1000 /rails/storage"
    (image runs as uid 1000; fly mounts volumes as root).
  • Set RAILS_MASTER_KEY as a fly secret.

Commits are split (infra / kamal removal / docs) for easy review/bisect.

capotej added 5 commits June 15, 2026 02:19
Add a GitHub Actions workflow that builds a linux/arm64 production image,
publishes it to the GitHub Container Registry, and signs it with cosign
(keyless OIDC) plus a SLSA v0.2 build-provenance attestation. The workflow
only publishes; deploying to fly.io is a separate `fly deploy --image` step.

- .github/workflows/docker.yml: build + sign + attest on push/release/dispatch
- .github/actions/attest-provenance: composite action running cosign attest
- fly.toml: app config (Thruster :80, edge TLS, abbey_data volume at
  /rails/storage, Solid Queue in Puma, arm64, scale-to-zero)
- Dockerfile/.dockerignore: point the build comment at the new workflow and
  ignore fly.toml instead of kamal files
Kamal/cloud-init/EC2 deployment is replaced by fly.io (see the image build
workflow and fly.toml added in the previous commit).

- drop `kamal` gem and regenerate Gemfile.lock (bundle lock prunes only
  kamal-exclusive transitive deps: bcrypt_pbkdf, dotenv, ed25519, net-ssh,
  net-scp, net-sftp, sshkit, ostruct)
- delete config/deploy.yml, .kamal/, and bin/kamal binstub
- delete lib/tasks/cloud_init.rake (AWS/Tailscale/EBS cloud-init generator,
  no longer referenced)
Replace the AWS/kamal deployment guide with a fly.io walkthrough: create app
+ persistent volume, set secrets, reserve IPs and certs, deploy the signed
image from GHCR, then seed and create the admin user. Update the runbook
(flyctl logs/ssh console/deploy) and troubleshooting (volume ownership on
first deploy, GHCR pull auth, migration, HTTPS/certs).

Also repoints the header from "self-hosted on AWS" to fly.io.
The deployment moves from a private Tailscale registry to a public GHCR
package, so tighten .dockerignore to keep the published image minimal and
free of dev/agent artifacts that have no runtime value and would otherwise
be swept in by COPY . .:

- .claude/         Claude Code agent config (also on-disk only, untracked)
- .crush/          Crush editor data incl. a ~12MB local SQLite db
- .crush.json      Crush LSP config
- .agents/, AGENTS.md   agent instructions/skills
- mise.toml        tool version-manager config
- Procfile.dev     dev-only process file

Security audit confirmed nothing sensitive already ships (.env with its
live API key, config/master.key, and storage/*.sqlite3 are all excluded;
the Dockerfile never decrypts credentials at build time). This commit is
about minimizing the public image surface.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant