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://host.impossi.build/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>.host.impossi.build)
--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.host.impossi.build
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 Apps (2): my-app URL: https://my-app.host.impossi.build Status: deployed Region: iad Running: d8967e0f Standby: a1b2c3d4 api-backend URL: https://api-backend.host.impossi.build Status: deployed Region: sin Running: e3f4a5b6
Shows your login, plan, and every app 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.host.impossi.build # List domains $ ifhost machines domains list --app my-app my-app.host.impossi.build [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
Config-only commands like autoscale set or a memory/cpu PATCH update the stored spec but do not touch running machines — your pool is charged at the new value while machines run the old one. ifhost apply rolls the live spec (memory, cpus, env, secrets) to every machine without rebuilding the image.
$ ifhost machines autoscale set --min 1 --max 5 --app my-app # updates config only $ ifhost apply --app my-app # pushes it to running machines
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.host.impossi.build","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.