Setup
elements man deploy/setup Read as markdownWhat the deploy machine needs, the database that runs on it, and the config that describes both.
Prerequisites
- An Ubuntu box with SSH access, on the latest Ubuntu release your provider offers. A new machine is the usual starting point. Any size works, including a small Digital Ocean droplet.
- A domain name pointed at the machine's public IP, if you want HTTPS. Optional.
Without a domain the app is reachable directly at
http://<public-ip>over plain HTTP.
The database comes with Elements. On first deploy, Elements installs and starts
the bundled Postgres cluster on the machine (data directory /elements/db), so
you do not provision a database separately. To use a hosted Postgres, or one
shared cluster for several machines, set DB_HOST in the environment's env
file.
You give Elements the public and private IPs of the machine and SSH credentials. Elements takes care of the rest, including provisioning, the system user, systemd, the Postgres cluster, the load balancer, automatic SSL, and the deploy itself.
Database on the Deploy Machine
By default the deploy machine runs the same bundled Postgres cluster as
development. The per-machine elements-machine daemon manages it on the box,
shared across projects, restarted before the project server, with its data under
/elements/db. On production, migrations are forward-only.
The scaffolded config.jsoc sets host: env("DB_HOST", "127.0.0.1"), and the
scaffolded production.env sets DB_HOST=127.0.0.1, so a production deploy
talks to the bundled cluster on the box with no extra configuration:
config/env/production.envDB_HOST=127.0.0.1
To use a remote or hosted Postgres (Digital Ocean Managed DB, AWS RDS,
Neon, Supabase, Railway, Crunchy Bridge, …), point DB_HOST (and DB_PORT,
DB_USER, DB_PASSWORD, and the app-user variants) at that server. Use
Postgres 16 or newer.
That connection is encrypted with TLS. For verified TLS (verify-full, what
HIPAA deployments use), commit your provider's CA certificate to the project
and point DB_SSL_ROOT_CERT at it:
config/env/production.envDB_HOST=mydb.abc123.us-east-1.rds.amazonaws.com DB_SSL_ROOT_CERT=config/certs/db-ca.pem
The certificate deploys with the project, and every machine verifies the
server against it. See elements man database.
Several Machines
To run several machines, point every machine's DB_HOST at one shared Postgres
cluster, on a machine of your own or at a hosted provider. Every feature then
works across all of them with no other change: live tables, channels, sessions,
jobs, and cron. A write on any app server reaches watching browsers on every
app server, because broadcasts travel through the shared database, and each
cron tick runs on one machine. Elements creates the app and test databases on
the shared cluster at the first build.
Uploaded files go in Postgres, where every machine reads them, or in S3 or any
object store. See elements man recipes/file-upload.
The Config
config.jsoc{ deploy: { domain: "example.com", // or ["example.com", "www.example.com"] ssl: true, // default true when domain is set ssh: { user: "ubuntu", identityFile: "~/.ssh/id_ed25519", }, env: { production: { machines: [ { name: "production0", publicIp: "203.0.113.10", privateIp: "10.0.0.10" }, ], }, staging: { domain: "staging.example.com", machines: [ { name: "staging0", publicIp: "203.0.113.20", privateIp: "10.0.0.20" }, ], }, }, }, }
domain takes one host or a list of them, and every host in it goes into the
TLS certificate.
Machine names are zero-indexed: the first machine in an environment is
production0, the second production1, and so on. publicIp is where Elements
connects, and is required. privateIp is for machine-to-machine traffic in a
multi-box cluster; leave it out for a single machine or if you don't have it.
Run:
Terminalelements deploy # default: production elements deploy staging # named environment