Everything you need to go from code to live URL.
One command, no dependencies. Works on macOS and Linux (amd64 and arm64).
$ curl -fsSL https://impossible-api.fly.dev/install | sh
The binary installs to ~/.local/bin/ifhost. Make sure that directory is in your PATH.
# Add to ~/.zshrc or ~/.bashrc if needed
export PATH="$HOME/.local/bin:$PATH"
$ ifhost login Open this URL in your browser: https://github.com/login/device Enter code: ABCD-1234 Waiting for authorization... Logged in as yourname (you@email.com)
$ ifhost login --token imp_your_token_here
Or set the environment variable:
export IMPOSSIBLE_API_TOKEN=imp_your_token_here
You can log in to multiple accounts. Each login is saved as a profile.
# Log in to a second account $ ifhost login Logged in as work@company.com # Switch between accounts $ ifhost login --switch Accounts: * [1] you@email.com [2] work@company.com Enter number: 2 Switched to: work@company.com
$ ifhost logout Logged out: work@company.com Switched to: you@email.com
Removes the active account. If other profiles remain, switches to the next one.
~/.impossible/credentials.json. Supports multiple profiles with one active. The IMPOSSIBLE_API_TOKEN env var overrides the file (useful for CI).Two modes: deploy a Dockerfile, or skip Docker entirely and install the project at runtime via an interactive console. Both start with ifhost init.
Generates impossible.toml in the current directory. Required before the first deploy.
$ ifhost init --app my-app --port 3000 --memory 512 Created impossible.toml: app: my-app port: 3000 memory: 512 MB cpus: 1 (shared) autostop: true min_machines: 0 Next: ifhost deploy
All flags are optional — run ifhost init with no args and it prompts for the app name (agents should pass full flags to skip prompts):
$ ifhost init --help
--app App name (becomes <name>.fly.dev)
--port Port the app listens on
--memory RAM in MB (256, 512, 1024, 2048, 4096)
--cpus CPU count (1, 2, 4, 8)
--cpu-kind shared or performance
--cmd Startup command override
--autostop true | false (false = always-on)
--min-machines Minimum always-running (1 = no cold starts)
--storage local (auto-create /data volume; omit for stateless apps)
You have (or can write) a Dockerfile. Put it at the project root.
# Example: Node.js
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
$ ifhost deploy Created app 'my-app' Packaging source for 'my-app'... Uploading source (42 KB)... Deploying... Deployed! Your app is live at: https://my-app.fly.dev
On first deploy the app is created automatically. Subsequent deploys update the running container.
For projects with a shell installer, curl | sh script, or any daemon you'd normally SSH into a VPS to set up (AI agents, Telegram/Discord bots, scrapers, research tools). Boot a generic shell VM, then drive install through the console.
$ ifhost init --app my-bot --memory 1024 --min-machines 1 $ ifhost machines secrets set API_KEY=sk-... BOT_TOKEN=... $ ifhost deploy --runner # boots generic Debian VM $ ifhost machines console start -- bash Console session started: ifhost-01k... Machine: abc123def456 $ SESSION=ifhost-01k... $ ifhost machines console input $SESSION "curl -LsSf https://astral.sh/uv/install.sh | sh && echo __done__" $ ifhost machines console input $SESSION --key Enter $ ifhost machines console output $SESSION # poll until __done__
Once installed, start the daemon in a named tmux session so it survives the console disconnect:
$ ifhost machines console input $SESSION \
"tmux new-session -d -s app 'cd /data/src && exec ./run 2>&1 | tee /data/app.log'"
Full interactive console reference: advanced docs.
ifhost init --port 3000) or at deploy (ifhost deploy --port 3000). Dockerfile EXPOSE is used as a fallback.$ ifhost status Logged in as: you@email.com Plan: pro Projects (2): my-app URL: https://my-app.fly.dev Status: deployed Region: iad Running: d8967e0f Standby: a1b2c3d4 api-backend URL: https://api-backend.fly.dev Status: deployed Region: sin Running: e3f4a5b6
Shows your login, plan, and every project grouped with its URL, status, region, and current machine IDs. No --app needed.
ifhost status --json is the fastest way to discover machine IDs for machines exec --machine <id> or machines console start. Pipe to jq.All app-specific commands live under ifhost machines.
$ ifhost machines --app my-app Machines for 'my-app' (2): 1 running, 1 stopped Running: d8967e0f sweet-surf-1234 started iad shared/1 256MB created 2d ago Standby: a1b2c3d4 proud-moon-5678 stopped iad shared/1 256MB created 2d ago
Grouped by state (Running vs Standby), with machine name and age so you can tell replicas apart. Use any listed ID with --machine <id> on exec, or target all at once with start / stop / restart.
$ ifhost machines stop --app my-app # Stop all (no cost while stopped) $ ifhost machines start --app my-app # Start them back up $ ifhost machines restart --app my-app # Restart with fresh env/secrets
Non-sensitive config — injected into your container's environment at runtime.
# Set one or more (auto-restarts the app) $ ifhost machines env set NODE_ENV=production PORT=3000 --app my-app Set 2 environment variable(s) # List all $ ifhost machines env list --app my-app NODE_ENV=production PORT=3000 # Inline during deploy (repeatable) $ ifhost deploy --app my-app --env NODE_ENV=production --env PORT=3000
For sensitive values (API keys, database URLs, tokens). Values are never returned in API responses or logs — only the keys can be listed.
# Set secrets (auto-restarts the app) $ ifhost machines secrets set DATABASE_URL=postgres://user:pass@host/db API_KEY=sk-xxx --app my-app Set 2 secret(s) # List (keys only — values never shown) $ ifhost machines secrets list --app my-app API_KEY DATABASE_URL # Inline during deploy $ ifhost deploy --app my-app --secret STRIPE_KEY=sk_live_xxx
impossible.toml [env] (committed to git), Dockerfile ENV (baked into image), or unquoted CLI flags visible in shell history.$ ifhost machines domains add myapp.example.com --app my-app Domain added: myapp.example.com TLS status: Awaiting certificates Add this DNS record: CNAME myapp.example.com → my-app.fly.dev # List domains $ ifhost machines domains list --app my-app my-app.fly.dev [active] myapp.example.com [active] (custom) # Remove $ ifhost machines domains rm myapp.example.com --app my-app
TLS certificates are provisioned automatically via Let's Encrypt after you add the CNAME record.
$ ifhost machines scale 3 --app my-app # Run 3 machines $ ifhost machines scale 1 --app my-app # Scale back to 1 $ ifhost machines --app my-app # See all machines
By default, apps run on 1 machine with scale-to-zero (stops when idle, starts on next request). To auto-scale under load:
$ ifhost machines autoscale set --min 1 --max 5 --target 25 --app my-app
This means:
$ ifhost machines autoscale off --app my-app # Disable, back to 1 machine
ifhost machines scale takes effect immediately.Volumes provide a local disk that survives redeploys, attached to one machine:
$ ifhost machines volumes create data --mount /data --size 5 --app my-app Created volume 'data' (5GB) mounted at /data $ ifhost machines volumes list --app my-app data 5GB /data iad $ ifhost machines volumes rm data --app my-app
| Use case | Recommended |
|---|---|
| SQLite database (single machine) | Volume |
| Local config / state for one machine | Volume |
| User uploads, images, files | External S3 (Tigris, Cloudflare R2, AWS S3) — bring your own bucket and credentials |
| Postgres / MySQL | Managed DB (Supabase, Neon) |
| Cache / Redis | Managed Redis (Upstash) |
Default: live stream (like tail -f), runs until Ctrl+C. Add --since or --lines to fetch historical logs and exit immediately. Filters work in both modes.
# Live tail — runs forever $ ifhost machines logs --app my-app # Last hour, then exit $ ifhost machines logs --app my-app --since 1h # Last 50 lines, then exit $ ifhost machines logs --app my-app --lines 50 # Filter by substring (streaming or historical) $ ifhost machines logs --app my-app --grep "ERROR" # Filter by level (error = error/fatal/panic lines) $ ifhost machines logs --app my-app --level error # Combined filters + historical window $ ifhost machines logs --app my-app --grep "GET" --lines 50 # Structured JSON, one object per line (for jq) $ ifhost machines logs --app my-app --json
Run any command inside your running container. Useful for debugging, inspecting files, running migrations, or checking configuration.
$ ifhost machines exec --app my-app -- ls /data $ ifhost machines exec --app my-app -- env $ ifhost machines exec --app my-app -- cat /etc/nginx/nginx.conf $ ifhost machines exec --app my-app -- python manage.py migrate $ ifhost machines exec --app my-app -- sh -c "du -sh /data/*" # Multi-machine apps: target a specific machine by ID $ ifhost machines --app my-app # list machines with their IDs $ ifhost machines exec --app my-app --machine 32d41... -- ps -ef
exec to inspect the running container, check env vars, debug issues, or run one-off commands. The command runs inside the Docker image — available tools depend on the base image (e.g., node: has Node + npm, python: has Python + pip, alpine has sh + basic utils). Without --machine, exec picks the first running machine; pin to a specific one to verify a particular replica (e.g., after a rolling deploy).ifhost machines start$ ifhost machines destroy --app my-app --yes # Permanently delete app and all resources
Create an impossible.toml in your project root to avoid passing --app every time and customize defaults.
app = "my-app" region = "iad" [build] dockerfile = "Dockerfile" [service] internal_port = 3000 autostop = true min_machines = 0 [resources] cpu_kind = "shared" # "shared" or "performance" cpus = 1 # 1, 2, 4, 8, 16 memory_mb = 256 # 256, 512, 1024, 2048, ... [env] NODE_ENV = "production" # Non-sensitive only!
With this file in your repo, deploys are just:
$ ifhost deploy
$ ifhost version ifhost build: 20260416-024938 Up to date.
Compares your local build with the latest on the server. If outdated:
$ ifhost version ifhost build: 20260101-000000 Update available: 20260101-000000 → 20260416-024938 Run 'ifhost update' to install.
$ ifhost update Checking for updates... Updated: /Users/you/.local/bin/ifhost
Downloads the latest binary for your OS/arch and replaces the current one in-place.
ifhost status also shows your CLI version and a hint if an update is available — no need to check manually.ifhost is designed to be used by AI coding agents. Key features:
--json flag on every command — structured output to stdout, logs to stderr--yes flag — skip all confirmation promptsIMPOSSIBLE_API_TOKEN env var — no interactive login needed# Agent workflow: deploy and get URL as JSON $ ifhost deploy --app my-app --json {"id":"01ABC...","status":"live","url":"https://my-app.fly.dev","machines":1} # Check account status $ ifhost status --json {"email":"you@email.com","plan":"free","apps":[{"name":"my-app","status":"deployed",...}]}
For the complete API reference (all endpoints, request/response shapes), see /llm.txt.