Manual Deploy Walkthrough

Walkthrough

elements man deploy/walkthrough Read as markdown

From zero to a deployed app on a fresh machine.

Walkthrough: From Zero to Deployed

The most common path: a single Digital Ocean droplet. Adapt for AWS, Linode, Hetzner, or any provider that gives you Ubuntu over SSH.

Each step here costs money or modifies infrastructure. Confirm with the user before running anything destructive.

1. Machine

Create an Ubuntu Linux box at your provider, on the latest Ubuntu release it offers. Note the public and private IPs. Make sure your SSH key is authorized on the machine and that you can ssh ubuntu@<public-ip> (or root@, depending on the provider).

Any size works, including a small droplet.

2. Database

Nothing to provision. Elements brings up the bundled Postgres cluster on the box during the first deploy. The scaffolded production.env already sets DB_HOST=127.0.0.1, so the app talks to that local cluster out of the box.

For a hosted database, or one shared cluster that several machines use, provision it now and copy its connection params into production.env. Every machine that points at the same cluster runs every feature across all of them.

3. Domain

You can reach the app two ways. With no domain, the app is available directly at http://<public-ip> over plain HTTP. With a domain, Elements provisions SSL automatically and serves the app at https://<your-domain>.

To use a domain, register one with any registrar (Namecheap, Cloudflare Registrar, Porkbun, Hover, etc.) and point an A record at the machine's public IP.

DNS record
A example.com <public-ip>

For a single-machine deploy that is all you need. With multiple machines in the environment, you can point DNS at any one of them or list several records for DNS-level round-robin and failover. Every machine in the cluster runs its own load balancer and round-robins requests to the other machines, so traffic gets distributed across all of them even with one DNS record.

You configure the domain in step 4 under deploy.domain, as one host (domain: "example.com") or a list (domain: ["example.com", "www.example.com"]). When domain is set, Elements issues and renews SSL certificates for those hosts automatically via Let's Encrypt. You do not need to provision certificates yourself, set up a renewal cron, or configure HTTPS anywhere else.

4. Config

config.jsoc
{ database: { name: "my_app", host: env("DB_HOST", "127.0.0.1"), port: env<number>("DB_PORT", 5433), user: env("DB_USER", "postgres"), password: env("DB_PASSWORD", ""), }, session: { expires: "30d", }, deploy: { domain: "example.com", ssh: { user: "ubuntu", identityFile: "~/.ssh/id_ed25519" }, env: { production: { machines: [ { name: "production0", publicIp: "<public-ip-from-step-1>", privateIp: "<private-ip-from-step-1>" }, ], }, }, }, }

config/env/production.env (gitignored):

config/env/production.env
DB_HOST=127.0.0.1

That is the production database configuration for the bundled cluster. If you provisioned a hosted database in step 2, set DB_HOST, DB_USER, and DB_PASSWORD to its values instead.

5. Deploy

Terminal
elements deploy

The first deploy provisions the machine: installs Elements, creates the system user, sets up systemd, brings up the Postgres cluster, installs the license, configures the built-in load balancer, and provisions SSL via Let's Encrypt. Subsequent deploys transfer only what changed. The local project server speaks directly to the deploy machine's project server over the SSH tunnel using a peer-to-peer protocol, and only the files that changed are transferred. An incremental build runs on the deployment machine, and typical incremental deploys complete in under a second.

6. Verify

The deploy verifies itself. It exits non-zero and prints diagnostics if any phase failed, and an empty diagnostics array means the release is live. Open https://example.com in a browser to see it.

Terminal
elements db -remote=production # psql against the production db

There is no health check to run afterward and no machine to log into. See What Deploy Does for the diagnostics and how to read them.