{"id":22,"library":"flyctl","title":"Fly.io (flyctl + Machines API)","description":"Fly.io is a compute platform for deploying containerized apps globally. There is no official Fly.io Python SDK — interaction is via the flyctl CLI, fly.toml config file, and the Machines REST API. The unofficial fly-python-sdk on PyPI (pip install fly-python-sdk) is a third-party project last updated October 2023 and should not be relied upon.","status":"active","version":"flyctl — see fly version update for current (auto-updates by default)","language":"python","source_language":"en","source_url":"https://fly.io/docs/","tags":["platform","deployment","containers","serverless","cli","infra","cloud"],"install":[{"cmd":"curl -L https://fly.io/install.sh | sh","lang":"bash","label":"flyctl CLI (macOS/Linux)"},{"cmd":"brew install flyctl","lang":"bash","label":"flyctl CLI (Homebrew)"},{"cmd":"pip install fly-python-sdk","lang":"bash","label":"Unofficial Python SDK (third-party, unmaintained — avoid)"}],"dependencies":[],"imports":[{"note":"No official Python SDK exists. Use the Machines REST API directly with any HTTP client.","wrong":"import fly\nfly.machines.list(app_id)","symbol":"Machines API (Python)","correct":"import requests\n\nheaders = {\"Authorization\": f\"Bearer {FLY_API_TOKEN}\"}\nrequests.get(\"https://api.machines.dev/v1/apps/{app_id}/machines\", headers=headers)"}],"quickstart":{"code":"# Deploy a Python app:\n# 1. In your project directory:\nfly launch          # Scans project, creates fly.toml, provisions app\nfly deploy          # Builds image, deploys to Machines\n\n# Minimal fly.toml for a Python web app:\n# app = 'my-app'\n# primary_region = 'iad'\n#\n# [http_service]\n# internal_port = 8080\n# force_https = true\n# auto_stop_machines = 'suspend'\n# auto_start_machines = true\n# min_machines_running = 0\n#\n# [[vm]]\n# memory = '256mb'\n# cpu_kind = 'shared'\n# cpus = 1\n\n# Secrets (env vars):\nfly secrets set OPENAI_API_KEY=sk-...\n\n# Scale:\nfly scale count 2\nfly scale memory 512","lang":"bash","description":"Primary workflow is CLI-based. fly launch detects framework and generates fly.toml. fly deploy on every code change."},"warnings":[{"fix":"Use [http_service] for single-process HTTP apps. Use [[services]] only for TCP or multi-port configurations. Run fly config validate to check.","message":"Apps V1 (Nomad-based) was fully removed March 2023. All apps migrated to V2 (Machines). Old fly.toml files using legacy [[services]] format may need updating to [http_service] for simple HTTP apps.","severity":"breaking","affected_versions":"V1 apps (pre-2023)"},{"fix":"Replace auto_stop_machines = true with auto_stop_machines = 'stop' or 'suspend'.","message":"auto_stop_machines previously accepted boolean true/false. Now requires string values: 'off', 'stop', or 'suspend'. Boolean true still maps to 'stop' but causes a deprecation warning and will eventually break.","severity":"breaking","affected_versions":"fly.toml configs written before mid-2024"},{"fix":"Use auto_stop_machines = 'suspend' + min_machines_running = 0 to minimize cost on low-traffic apps. Stopped/suspended machines only billed for storage (~$0.15/GB/month).","message":"Free tier removed for new organizations created after October 7, 2024. New accounts are pay-as-you-go only. Existing users keep legacy free allowances unless they switch plans.","severity":"breaking","affected_versions":"New accounts post-October 2024"},{"fix":"Run fly scale count 1 after first deploy, or set min_machines_running = 0 with auto_stop_machines = 'suspend'.","message":"fly launch creates two Machines by default on first deploy if [http_service] is configured (redundancy by default). This doubles cost unexpectedly for hobby projects.","severity":"gotcha","affected_versions":"all"},{"fix":"Bind your server to 0.0.0.0. E.g. uvicorn app:app --host 0.0.0.0 --port 8080","message":"Apps must listen on 0.0.0.0:<internal_port>, not 127.0.0.1 or localhost. Listening on localhost causes 'app is not listening on the expected address' deploy warning and the app is unreachable.","severity":"gotcha","affected_versions":"all"},{"fix":"Verify requirements before relying on suspend for fast cold-start. Check fly machine status <id> to confirm state transitions.","message":"Machine suspend (auto_stop_machines = 'suspend') requires ≤2GB RAM, no swap configured, no GPU, and no schedule. Machines not meeting requirements silently fall back to 'stop' behavior.","severity":"gotcha","affected_versions":"all"},{"fix":"Always run fly deploy after any fly.toml change. Use fly config show to inspect deployed config.","message":"fly.toml changes do not take effect until fly deploy is run. Saving fly.toml does not trigger a redeploy. Dashboard view of fly.toml may lag behind actual deployed config.","severity":"gotcha","affected_versions":"all"},{"fix":"In GitHub Actions use superfly/flyctl-actions@v1 pinned to a specific version. Disable autoupdate in production environments with fly settings autoupdate disable.","message":"flyctl auto-updates by default. New flyctl versions occasionally change behavior or add new fly.toml schema fields that conflict with old configs. Pinning flyctl version in CI is recommended.","severity":"gotcha","affected_versions":"all"},{"fix":"Ensure the Python version used in your deployment environment (e.g., specified in `fly.toml` buildpack, or your Dockerfile's `FROM` image) meets the minimum `Requires-Python` version of your dependencies. For example, if a dependency requires `Python >=3.11`, use `python:3.11-slim` or newer.","message":"Python packages in `requirements.txt` or `pyproject.toml` may specify a minimum Python version. If the deployment environment (e.g., `fly.toml` buildpack settings, Dockerfile base image) uses an older Python version, package installation will fail with 'Requires-Python' errors.","severity":"breaking","affected_versions":"all"},{"fix":"For the 'root' user warning, ensure pip is run within a virtual environment or specify a non-root user in your Dockerfile (e.g., using a `USER` instruction). For the pip update notice, run `pip install --upgrade pip` to update pip.","message":"Test output shows pip warnings regarding running as the 'root' user and an available update. Running pip as root can cause permission issues, and an outdated pip might lead to unexpected behavior or missed features.","severity":"gotcha","affected_versions":"all"}],"env_vars":{"optional":[{"name":"FLY_APP_NAME","note":"Available inside running Machines. Also FLY_REGION, FLY_MACHINE_ID, FLY_ALLOC_ID."}],"required":[{"name":"FLY_API_TOKEN","note":"Required for CI/CD. Generate with: flyctl tokens create deploy -x 999999h"}]},"last_verified":"2026-05-12T04:37:30.517Z","next_check":"2026-04-01T00:00:00.000Z","problems":[{"fix":"Ensure flyctl is installed correctly for your operating system (e.g., via Homebrew on macOS, or the install script which adds it to your shell's rc file). Verify your shell's PATH environment variable includes the directory where flyctl is located (e.g., ~/.fly/bin).","cause":"The flyctl executable is not in your system's PATH, or the installation was incomplete.","error":"flyctl: command not found"},{"fix":"Specify the app name using `flyctl <command> -a <app_name>` or ensure you are running the command in a directory containing your `fly.toml` file. If launching a new app, use `flyctl launch`.","cause":"flyctl could not determine which application to operate on because the app name was not specified via the `-a` flag, the `FLY_APP` environment variable, or a `fly.toml` file in the current or parent directory.","error":"Error Could not find App"},{"fix":"Ensure you are logged into Fly.io (`flyctl auth login`) and, if using Docker images from a private registry, authenticate Docker (`flyctl auth docker`). Update `flyctl` to the latest version (`flyctl version update`) as older versions might have authentication issues.","cause":"Flyctl or the remote builder failed to authenticate with a Docker registry (often for a private image) or the Fly.io registry itself. This can also manifest as `401 Unauthorized`.","error":"Error: failed to fetch an image or build from source: Authentication required to access image \"docker.io/<image_name>:latest\""},{"fix":"Run `flyctl doctor` to diagnose network issues, especially WireGuard connectivity. Try `flyctl wireguard reset` to recreate your WireGuard peer, and if UDP is blocked, enable WebSockets with `flyctl wireguard websockets enable` followed by `flyctl agent restart`. Restarting your computer can also resolve transient network problems.","cause":"This often indicates a problem with WireGuard or network connectivity between your local machine (or the remote builder) and Fly.io's services, preventing image building or deployment. Another related error is `Error: ping gateway: no response from gateway received`.","error":"Error: failed to fetch an image or build from source: error connecting to docker: failed building options: failed probing \"personal\": context deadline exceeded"},{"fix":"Check your application's logs using `flyctl logs` for crashes or startup errors. Ensure your application is configured to listen on `0.0.0.0` on the `internal_port` specified in your `fly.toml`. Increase health check grace periods if your app has a slow startup.","cause":"The Fly.io proxy successfully reached your machine, but your application did not respond correctly or in time. This is often caused by the app crashing, listening on the wrong port (e.g., `127.0.0.1` or `localhost` instead of `0.0.0.0`), or not being ready within the health check grace period.","error":"502 Bad Gateway"}],"ecosystem":"pypi","meta_description":null,"install_score":0,"install_tag":"stale","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null}]},"quickstart_checks":{"last_tested":"2026-05-11","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}