Installation
Cargo installs on a single Linux server with one script. The installer checks dependencies, prompts for your domains, generates secrets, and starts the three-container stack.
Prerequisites
- An Ubuntu/Debian Linux host with
sudoaccess (the installer sets up Docker Engine and the compose plugin) - Ports 80 and 443 open
- For a production install, DNS records pointing at the host:
<platform-domain>→ server IP (where the Cargo UI lives, e.g.cargo.example.com)*.<apps-domain>→ server IP (wildcard for app subdomains, e.g.*.apps.example.com)
No domain is required. Leave the platform domain empty and the installer sets up a local install on localhost / the server’s IP — see below.
Quick install
curl -fsSL https://usecargo.vercel.app/install.sh | sh
The bootstrap installs any missing prerequisites, clones Cargo to /opt/cargo,
then runs the deploy installer. Set CARGO_INSTALL_DIR to choose a different
location. If you already have a Cargo checkout, run ./deploy/install.sh from
its root instead.
The installer runs four phases, in order:
- Dependency checks — verifies
dockeris installed, the compose plugin is present, and the daemon is reachable. - Prompts — asks for your platform domain. Give one and it also asks for the apps-domain suffix, Let’s Encrypt email, and an optional DNS provider for wildcard certificates (empty = per-domain HTTP-01). Leave it empty for a local install and the rest is inferred.
- Secrets — generates
CARGO_MASTER_KEY(64 hex chars) andCARGO_DB_PASSWORDinto a mode-0600.envfile, then prints the DNS records you should verify. - Launch — creates the shared
cargo-proxynetwork if it doesn’t exist, then runsdocker compose up -dwith the right overlay file for your mode.
Back up CARGO_MASTER_KEY from .env somewhere safe.
Environment variables and credentials are encrypted with it and are
unrecoverable without it.
Once the stack is up, open https://<platform-domain> and register — the
first account becomes the instance admin.
Install modes
Which compose overlay runs is decided by what you answered:
| Mode | You entered | Stack | Certificates |
|---|---|---|---|
| Local | Nothing, localhost, or an IP |
docker-compose.yml |
None — plain HTTP on port 80, self-signed HTTPS on 443 |
| HTTP-01 | A domain, no DNS provider | + docker-compose.tls.yml |
One Let’s Encrypt cert per domain, on first request |
| Wildcard DNS-01 | A domain and a DNS provider | + docker-compose.dns01.yml |
One cert covering *.<apps-suffix> |
Local install
Leave the platform domain empty and the installer detects the server’s
primary IPv4 (falling back to localhost), defaults the apps suffix to
apps.localhost, and skips Let’s Encrypt entirely. No DNS records, no email,
no certificates.
Open http://localhost or http://<server-ip> and register. Apps are served
at https://<name>.apps.localhost with Traefik’s self-signed certificate —
your browser will warn, which is expected.
This is the fastest way to try Cargo, and a legitimate way to run it behind an existing reverse proxy or on a private network. Move to a domain install when you want real certificates.
Non-interactive installs
Set the prompt answers in the environment instead of answering interactively. With none of them set you get a local install.
| Variable | Required | Purpose |
|---|---|---|
CARGO_PLATFORM_DOMAIN |
For a domain install | Where the Cargo UI lives, e.g. cargo.example.com |
CARGO_APPS_SUFFIX |
For a domain install | Apps get <name>.<suffix>, e.g. apps.example.com |
CARGO_ACME_EMAIL |
For a domain install | Let’s Encrypt account email |
CARGO_DNS_PROVIDER |
No | Traefik DNS provider name (e.g. cloudflare) for wildcard certs |
When CARGO_DNS_PROVIDER is set, add the provider’s credential environment
variables to .env as well (e.g. CF_DNS_API_TOKEN for Cloudflare) — see
Domains & SSL. Every other setting has a sane default;
the full list is in Configuration.
Resource ceilings
Per-app memory/CPU/PID limits are advisory defaults. Instance admins can cap how far a tenant raises their own limits:
| Variable | Purpose |
|---|---|
CARGO_MAX_MEM_LIMIT |
Absolute ceiling for per-app mem_limit |
CARGO_MAX_CPU_LIMIT |
Absolute ceiling for per-app cpus |
CARGO_MAX_PIDS_LIMIT |
Absolute ceiling for per-app pids_limit |
Without these, a tenant could set mem_limit to an arbitrarily large value.
On a shared instance, set them to protect the host.
Git-clone host screening
Cargo validates repository URLs against server-side request forgery. Only
https://, ssh://, and git@host:path transports are accepted; hosts
that resolve to loopback, RFC1918, link-local, or cloud-metadata addresses
are refused.
If your git server is self-hosted on a private network:
CARGO_ALLOW_PRIVATE_GIT_HOSTS=true
This widens where clones may go, never which transports.
Installer flags
| Flag | Effect |
|---|---|
--force |
Overwrite an existing .env (this changes secrets!) |
--no-up |
Write .env and stop — start later with docker compose up -d |
Manual alternative
Copy deploy/.env.example to .env and fill it in (every key is documented
there and in Configuration), then:
chmod 600 .env
docker network create cargo-proxy # shared app/proxy network, once per host
docker compose up -d # add your TLS overlay's -f flag for production