Skip to main content
Fly.io runs Docker containers on lightweight VMs at edge locations around the world. Its CLI-driven workflow feels like running docker-compose but with built-in TLS, global networking, and managed Postgres.

Overview

This guide covers deploying MergeWatch to Fly.io, provisioning a managed Fly Postgres cluster, setting secrets, and configuring the GitHub App webhook.

Prerequisites

1

Install the Fly CLI

curl -L https://fly.io/install.sh | sh
fly auth login
2

Gather your GitHub App credentials

VariableDescription
GITHUB_APP_IDNumeric App ID from the GitHub App settings page
GITHUB_PRIVATE_KEYPEM-formatted private key generated for the App
GITHUB_WEBHOOK_SECRETSecret used to validate incoming webhook payloads
3

Choose an LLM provider

Set LLM_PROVIDER to your preferred provider. For the default Anthropic provider, you also need ANTHROPIC_API_KEY.

Deploy to Fly.io

1

Launch the app

From a directory containing a Dockerfile (or use the MergeWatch image directly), run:
fly launch --image ghcr.io/santthosh/mergewatch:latest \
  --name mergewatch \
  --region iad \
  --no-deploy
This creates a fly.toml configuration file. The --no-deploy flag lets you configure secrets before the first deploy.
fly launch auto-detects Dockerfiles and suggests sensible defaults. You can accept the defaults and customize later.
2

Set environment variables and secrets

Use fly secrets set for sensitive values. Fly encrypts these at rest and injects them as environment variables at runtime.
fly secrets set \
  GITHUB_APP_ID="YOUR_APP_ID" \
  GITHUB_PRIVATE_KEY="YOUR_PRIVATE_KEY" \
  GITHUB_WEBHOOK_SECRET="YOUR_WEBHOOK_SECRET" \
  LLM_PROVIDER="anthropic" \
  ANTHROPIC_API_KEY="YOUR_ANTHROPIC_KEY" \
  DATABASE_URL="postgres://USER:PASSWORD@HOST:5432/mergewatch"
fly secrets set triggers a redeploy by default. Since we used --no-deploy above, the first deploy happens in the next step.
3

Configure the internal port

Edit fly.toml to set the internal port to 3000:
[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
4

Deploy

fly deploy
Fly builds (or pulls) the image, starts the VM, and provisions a TLS certificate automatically.
==> Monitoring deployment
  1 desired, 1 placed, 1 healthy, 0 unhealthy
--> v1 deployed successfully
5

Verify the deployment

fly status
fly logs

Set up Postgres

Fly.io offers a managed Postgres service that runs as a Fly app in the same private network as your MergeWatch instance.
1

Create a Fly Postgres cluster

fly postgres create --name mergewatch-db --region iad
Fly prints the connection string when the cluster is ready:
Postgres cluster mergewatch-db created
  Username:    postgres
  Password:    xxxxxxxxxxxxx
  Hostname:    mergewatch-db.internal
  Proxy port:  5432
  PG port:     5433

Connection string: postgres://postgres:xxxxxxxxxxxxx@mergewatch-db.internal:5432
2

Attach the database to MergeWatch

fly postgres attach mergewatch-db --app mergewatch
This automatically sets the DATABASE_URL secret on your MergeWatch app with the correct internal connection string.
Fly Postgres runs inside the same private network (6PN) as your app. No public internet exposure or firewall rules needed.

Configure the webhook URL

Your Fly.io app is available at https://your-app.fly.dev. Set the webhook URL on your GitHub App to:
https://mergewatch.fly.dev/webhook
Replace mergewatch with whatever name you chose during fly launch.
Make sure force_https = true is set in your fly.toml. GitHub requires HTTPS for webhook delivery.

Next steps