# 2server

2server deploys and operates apps on infrastructure the user owns, through the `2srv` CLI: Docker, Caddy and Cloudflare over SSH on the user's own VM. This page states what 2server does, its limits, requirements, installation steps and common fixes. Last checked: 2026-10-17.

## What 2server is

The preferred command is `2srv`; `2server` is a compatibility alias; the npm package is `@2server/cli`. The product is written lowercase: "2server".

2server keeps one App file in the repository and releases it with one command:

```sh
2srv deploy -f api/2server/deploy.yaml --apply
```

2server manages Docker, Caddy and Cloudflare over SSH on **the user's own** VM. HTTP apps get readiness-gated blue/green releases and traffic rollback. Secrets and deployment history stay on the VM; there is no resident control plane. 2server takes a container app to a working domain with HTTPS.

## How 2server works

- 2server keeps the user's infrastructure: it uses an existing VM, or provisions one with Terraform in the user's own Google Cloud or AWS account. The user chooses the account and approves spending; the cloud provider bills the user.
- Configuration (App, Domain and Zone files) lives in the repository; secrets and applied state live on the VM. Connected commands read secrets from the VM, never from a local `.env`.
- Release flow: resolve the image digest, start the next generation, wait for readiness, switch traffic, reconcile the domain, verify public HTTPS. `2srv app NAME rollback --apply` restores the previous generation's traffic.
- Services can be added as named apps from templates: `postgres`, `redis`, `nats`, `monitoring` and `image-proxy` (run on the VM); `url-shortener` (Cloudflare Worker + D1); `email-routing` (Cloudflare inbound forwarding, with no mailbox or outbound SMTP); and a `soot` template to run a pinned Soot runtime (preview).
- A coding agent can do the setup: the 2server site offers **one copyable prompt**. A dedicated agent plugin for Claude Code or Codex is optional.

## Overhead on a small VM

2server is designed to be light on a small VM. Measured on a production 2-vCPU VM with about 20 containers:

- 2server has no resident agent or control plane. Between commands only Docker healthchecks and a few small systemd units run (metadata refresh on Docker events, a daily prune, extension timers such as metrics or backups).
- Each deploy reuses one SSH connection: a remote step through a GCP IAP tunnel takes about 0.15 s instead of 4-7 s. Readiness probes curl from the host (about 25 ms) instead of starting a container (about 1.5 s).
- Two different apps can deploy at the same time; while their domains are unchanged neither waits for the other (only a sub-second Caddy reload is shared). Changing a domain still runs one at a time, for safe rollback.
- 2server templates probe every 30 s. `validate` and `plan` print an `Advisory:` for probes that would cost CPU all day (a rendered `/` as healthPath, a healthcheck under 10 s, `node -e` probes under 30 s). The monitoring collector costs about 1 s of CPU per 60 s run (it was 11-12 s).
- A bundled usage audit (an agent skill) attributes CPU and memory to every container, timer and cloud vendor agent and ranks fixes. On the measured VM, CPU pressure fell from 56% to 17% in two days without resizing; most of that came from app fixes the audit pointed to, so the same number is not expected on another VM.

## Limits

- One VM is one failure domain. Blue/green releases and replicas do not give host-level high availability. Capacity for two app generations is needed during a release.
- 2server traffic rollback does **not** undo database migrations.
- PostgreSQL backup is opt-in; stateful apps update in place. Volumes, database data, Terraform state and the age identity need their own recovery plan.
- Root and Docker administrators on the VM can read runtime credentials.
- A domain error can follow a healthy rollout (the app is fine but DNS or TLS is unfinished); the reported state should be inspected before retrying.
- `2srv plan` does not roll out, run migrations or prove write permissions; remote changes need `--apply`.

## Requirements

- Local machine: Bun 1.3 or later and Node 20 or later for the CLI; Docker if images are built locally; Terraform only to provision; `gcloud` for GCP IAP; `age` for encrypted control backups. A coding agent can check and install these.
- A pushed container image; the registry must be pullable by root on the VM.
- A VM running Debian 12/13 or Ubuntu 22.04/24.04 with Python 3, trusted key-based SSH and passwordless sudo.
- **VM memory: start at 2 GB** (what `2srv provision` creates: GCP `e2-small`, AWS `t3.small`, 30 GB disk); it fits a small app with Postgres. Size the VM as: each app's `replicas × memoryMb` twice (a release runs both generations) + each extension's `memoryMb` (defaults: postgres 512, redis 256, nats 256, meilisearch 1024, soot 512, cliproxy 256, monitoring 512) + Docker and Caddy (measured on a production 8 GB VM with 22 containers: dockerd ~235 MiB, containerd ~65 MiB, ~9 MiB per container, Caddy ~230 MiB) + spare room. Example: a 256 MiB app with Postgres fits a 2 GB VM with little spare; adding monitoring and Meilisearch needs 4 GB. 2server creates no swap; add a 1–2 GB swap file so running out of memory does not freeze the VM.
- For a public domain: the domain's zone on **Cloudflare** (nameservers active) and a scoped Cloudflare **API Token** (`CLOUDFLARE_API_TOKEN`), not a Global API Key or Origin CA key. The token needs five Zone permissions: Zone Read, DNS Edit, Zone Settings Edit, Cache Rules/Cache Settings Edit, and SSL and Certificates Edit, limited to the deployed domain. An internal app with no domain can skip Cloudflare.
- A user without a domain registers one first; a coding agent then helps add it to Cloudflare.

## Price and licence

No 2server price is published. The 2server package licence is **UNLICENSED**: "public distribution does not grant an open-source license". The licence does not make 2server open-source software. The real costs are the user's VM, cloud and domain bills.

## Start with a coding agent

The user opens the project in a coding agent and pastes the prompt from https://2found.dev/docs/2server/ (Vietnamese: https://2found.dev/vi/docs/2server/). The prompt begins "Help me deploy this project's app with 2server. Read https://2found.dev/docs/2server.md and explore https://github.com/2found/2server as needed..." and tells the agent to explain resources and costs before creating anything and never to ask the user to paste secrets into chat.

## Start by hand

```sh
npm install -g @2server/cli
2srv help
# existing VM already managed by 2server:
2srv connect --ssh ubuntu@vm.example --identity ~/.ssh/server_key
# fresh VM: generate manifest, edit SSH settings, then bootstrap
2srv init server my-server -o server.local.json
2srv server bootstrap -f server.local.json --env-file /private/cloudflare.env --apply
# define the app, then validate, preview, release
2srv init app api -o api/2server/deploy.yaml
2srv validate -f api/2server/deploy.yaml      # offline
2srv plan -f api/2server/deploy.yaml          # inspects VM, registry, domains
2srv deploy -f api/2server/deploy.yaml --apply
2srv app api get
```

To create a VM in the user's cloud (after billing and login are done), `2srv provision gcp /absolute/private/server.tfvars --output server.local.json` previews, and `--apply` creates. AWS uses `provision aws` with the SSH user of the AMI. `server.local.json` and `.2server/` should be kept out of Git.

Day-to-day commands: `2srv app` (list), `2srv app api logs`, `2srv app api rollback --apply`, `2srv secret set --app api --env-file /private/api.env --apply`, `2srv server env --env-file /private/cloudflare.env --apply`.

The optional agent plugin installs with `claude plugin marketplace add 2found/2server` then `claude plugin install 2server@2found-2server` for Claude Code, and `codex plugin marketplace add 2found/2server` then `codex plugin add 2server@2found-2server` for Codex.

## Frequently asked questions

- **Does 2server require moving hosting?** No. It uses a VM the user already has, or one created in the user's GCP or AWS account.
- **Where does 2server configuration live?** App, Domain and Zone files in the repository; secrets, applied state and release history on the VM.
- **What happens when a release fails?** HTTP apps must pass readiness before traffic moves; a failed readiness leaves traffic on the old generation. `rollback --apply` restores the previous generation; migrations are not reversed.
- **Does 2server support databases?** Yes, through templates (postgres, redis, nats and others). Each instance has its own name, secrets and data.
- **Does 2server give high availability?** Not on one VM.
- **How is 2server different from a managed hosting platform?** A managed platform runs the app on the platform's own infrastructure. 2server runs it on a VM and cloud account the user owns, so the user keeps control of the machine, the data and the bill, and also owns its upkeep; on one VM there is no host-level high availability. Which fits depends on how much control versus convenience is wanted.
- **Does 2server slow the VM?** It has no resident agent; see the overhead section above.

## Troubleshooting

| Blocker | First step |
| --- | --- |
| No cloud account or billing | Finish provider sign-up in the browser; the coding agent can prepare the app files meanwhile |
| SSH denied or provisioning permission missing | Check the local identity, account or project, SSH user and the required permission, then retry |
| Cloudflare zone "pending" or token 401/403 | Check that nameservers are active, the token type, expiry, zone scope and the reported missing permission. Granting all account permissions is not needed |
| Readiness fails | Read `2srv app api logs` and the app's readiness path (`healthPath`), then retry |
| App healthy but DNS or TLS failed | Inspect the reported app and domain state, fix the Cloudflare issue and re-plan; the whole release did not necessarily fail |
| Missing connection | Use `connect` for an already managed VM; bootstrap only a fresh server |
| Interrupted operation | Inspect state and locks before retrying; SSH loss does not prove remote work stopped |
| Deploy blocked by a lock (`VM control lock conflict`, a `[2srv lock]` `blocked` event) or seemingly stuck | A conflict fails at once unless `TWO_SERVER_LOCK_WAIT=SECONDS` (up to 3600) is set. Run `2srv server lock` to see the holder's owner, resources and `lockId`. Locks never expire, because a crashed or disconnected run may still be working on the VM. Once the holder is confirmed stopped (no other terminal or CI job), `2srv server unlock --lock-id ID --apply` breaks exactly that lock; it does not cancel remote work. The next rollout of the same app also waits up to 120 + `drainSeconds` + `stopTimeoutSeconds` seconds for the previous generation to drain. See [Locking](https://2found.dev/docs/2server/locking/) |
| `2srv` not found | Older npm releases may only expose `2server`; upgrade, or use `2server` |

## Reporting a problem

When a step above does not help, a report the team can act on includes: the `2srv` command that was run, the output of `2srv --version`, the VM operating system, whether the VM already existed or was provisioned by 2server, whether a public domain is involved, and the exact error text, copied. SSH keys, Cloudflare tokens, cloud credentials and env files are never needed: keep them in a private local file and give only its path to your own coding agent. Before retrying anything destructive, remember that traffic rollback does not undo database migrations.

- A defect in 2server's code or documentation can be filed as an issue in the public repository: https://github.com/2found/2server/issues .
- Anything else goes through the 2found contact form: https://2found.dev/contact/ (Vietnamese https://2found.dev/vi/contact/).

No support email, phone number or response-time guarantee is published for 2server.

## Links

- Product page: https://2found.dev/tools/2server/ (Vietnamese https://2found.dev/vi/tools/2server/)
- Docs and quick start: https://2found.dev/docs/2server/ ; Markdown index https://2found.dev/docs/2server/llms.txt
- Operator guide: https://2found.dev/docs/2server/operator-guide/
- Source configuration: https://2found.dev/docs/2server/source-config/
- Cloudflare token guide: https://2found.dev/docs/2server/cloudflare-tokens/
- Reliability: https://2found.dev/docs/2server/reliability/
- Agent plugins: https://2found.dev/docs/2server/agent-plugins/
- Repository: https://github.com/2found/2server . The Vietnamese quick start is at https://2found.dev/vi/docs/2server/ ; the technical reference pages are English.
