HOW TO SECURE FLY.IO - SECURITY GUIDE | VIBEEVAL
Fly.io Security Context
Fly.io runs your container in micro-VMs across global regions, with a private 6PN WireGuard network connecting your apps. Two distinct surfaces beyond standard container security: (1) your fly.toml is a deploy config that may include settings (or exclude them) that affect security — secrets handling, internal vs public services, region pinning; (2) the 6PN private network needs to actually be used — by default, every service is reachable on its public Anycast IP unless you explicitly bind to the private network.
Security Checklist
1. Use fly secrets, never [env] in fly.toml
fly secrets set DATABASE_URL=postgres://... stores the value encrypted at rest, only decrypted into the container’s env at boot. The [env] table in fly.toml ends up in your git repo — anything in it is in commit history forever. Never put a secret in [env].
2. Use Private Networking for internal services
For backend services that don’t need a public IP: fly.toml [[services]] with no internal_port exposed publicly, or use [[vm.services]] with protocol = "tcp" only. Communicate between apps in the same org via <app-name>.internal — traffic stays on the 6PN network and never touches the public internet.
3. Enable TLS for all public services
Fly.io provisions TLS certs automatically when you fly certs add yourdomain.com. Verify with fly certs show yourdomain.com — confirm the cert is issued and the chain is complete. For Anycast addresses (<app>.fly.dev), TLS is on by default.
4. Configure health checks
In fly.toml:
[[services.http_checks]]
interval = "10s"
timeout = "2s"
grace_period = "5s"
method = "get"
path = "/health"
Health checks aren’t security on their own, but a service that doesn’t pass health gets cycled — limiting the lifespan of a compromised process. Add a /health endpoint that returns 200 only when the app is actually serving traffic correctly.
5. Configure team permissions
In Org → Members: review quarterly. Owner / Member roles. Anyone with member access can deploy, read secrets, and SSH into machines (fly ssh console). Remove ex-team members same-day; rotate secrets after departure.
6. Encrypt persistent volumes
Fly Volumes are encrypted at rest by default. Verify with fly volumes list and check encryption status. For more sensitive data, layer additional client-side encryption before writing to the volume.
7. Configure Postgres security on Fly Postgres
If using fly postgres create: rotate the operator password (fly postgres connect) after creation, never embed the connection string in [env], configure pg_hba.conf rules to restrict access to the 6PN network only. The flycast private DNS gives you <app>-db.flycast for in-network access.
8. Set machine resource limits
In fly.toml [[vm]]: set explicit memory and cpu per VM. A misconfigured VM with autoscaling and no limits is a DoS amplifier — an attacker triggers expensive operations until the bill becomes a problem.
9. Enable audit logging
fly logs --app <app>: review weekly. For longer retention and queryability: fly logs ship to your log destination (Datadog, Logtail, or S3). Track: deploys, secret changes, machine restarts, SSH sessions.
10. Configure auto-scaling carefully
In fly.toml [http_service]: set min_machines_running (cost floor) and the implicit max (via [[regions]] and machine count). Don’t auto-scale unbounded — an attacker can trigger growth and you pay.
11. Configure Fly Proxy headers
Fly Proxy adds Fly-Client-IP, Fly-Region, etc. — your application should read the client IP from these (not the TCP-level peer, which is the proxy). Without this, rate limits and access logs see the proxy IP, not the actual user.
12. Configure backups for volumes
fly volumes snapshot create <volume-id> for one-shot snapshots; for production, automate with a cron job that snapshots daily and prunes old snapshots. Snapshots are encrypted at rest. Test restore once before you need it.
13. Configure monitoring
Fly Metrics dashboard shows CPU / memory / network per machine. Set alerts (via Grafana / Prometheus integration) for: CPU spikes (could be cryptojacking after a compromise), unusual outbound traffic (data exfiltration), machine restart loops (DoS or app instability).
14. Audit your Dockerfile
Audit for: running as root (use USER nonroot), exposing unnecessary ports (EXPOSE only what you serve), pulling base images with :latest tag (pin to specific digests), ADD from URLs (use COPY from local files instead). AI-generated Dockerfiles often skip these.
15. SSH access controls
fly ssh console requires WireGuard or a configured SSH key. Confirm: WireGuard tokens are scoped per developer, SSH keys are not shared, ssh sessions are logged via the audit trail.
16. Run a security scan
The full VibeEval scan probes your deployed Fly app for missing auth, BOLA, and webhook trust — independent of where it’s hosted.
Related Resources
Free Self-Audit Suite
Five free scanners.
Vibe Coding Security Risk Guide
Full risk catalogue.
PostgreSQL Guide
Secure your Fly Postgres deployment.
Automate Your Security Checks
VibeEval scans applications running on Fly.io for the categories above plus the long tail.
SCAN YOUR APP
14-day trial. No card. Results in under 60 seconds.