Use PostgreSQL
Set DATABASE_URL to a PostgreSQL database, and the server keeps its ledger there instead of in a SQLite file. Use PostgreSQL when:
- you want your database service to take the backups;
- the container should keep nothing of its own;
- several servers share one ledger.
The runtime is tested on PostgreSQL 18. The image needs nothing more for it, since its PostgreSQL driver is pure JavaScript.
Get a database
| Option | What it is |
|---|---|
| Beside the runtime, with Compose | Run with PostgreSQL has a Compose file that starts postgres:18 with its data on a volume. It suits one machine |
| A managed service | Amazon RDS or Aurora PostgreSQL, Google Cloud SQL for PostgreSQL, Azure Database for PostgreSQL, or another provider's PostgreSQL 18. The provider takes backups, applies patches and can fail over |
| A server you run | Any PostgreSQL 18 server the containers can reach |
For a managed service or a server you run, create a database and a user for the runtime as below.
Create the database and its user
The server creates its tables in the database's public schema at every start, and migrates them there after an upgrade. Its user needs CREATE on that schema every time, not only the first. A user that owns the database has it:
CREATE ROLE auto_runtime LOGIN PASSWORD '<a long random password>';
CREATE DATABASE auto_runtime OWNER auto_runtime;Run these as an administrator, such as the master user of a managed database. With a user that may only read and write the tables, the server fails to start with permission denied for schema public.
Connect
The URL holds the database's password, so it is a secret:
- Put it with the other secrets in the container's environment, such as
auto-runtime.env. - Never put it in the configuration file, which refuses a
database_urlkey.
Each docker run on this page starts a container named auto-runtime and is an alternative to the others. Run them in the folder from Run with Docker. Its .env names the release to run, such as IMAGE=onauto/runtime:0.9.1, and its auto-runtime.env holds PUBLIC_URL, without which the container stops at start, and SECRETS_KEY, which a ledger in PostgreSQL needs. If a container named auto-runtime exists, stop and remove it first with docker stop auto-runtime && docker rm auto-runtime. Then:
echo 'DATABASE_URL=postgresql://auto_runtime:<password>@db.example.com:5432/auto_runtime?sslmode=verify-full' >> auto-runtime.env
. ./.env
docker run --detach --name auto-runtime --restart unless-stopped \
--publish 127.0.0.1:5555:5555 --env-file auto-runtime.env "$IMAGE"--publish 127.0.0.1:5555:5555 keeps the port on this machine, as in Run with Docker. To reach the runtime from other machines, follow Put HTTPS in front.
With DATABASE_URL the container needs no volume. At start:
- The server logs that the ledger is kept in PostgreSQL, naming the database and its host, never the URL.
- A database it cannot reach stops it, naming the host and port.
- Setting
LEDGER_FILEas well stops it, since the ledger can be in only one place. - Without
SECRETS_KEYit stops, naming the setting.
SECRETS_KEY is the key the secrets kept in the database are sealed under. Every server that shares the database takes the same key, as Keep the secrets key describes.
TLS
For a database across a network, end the URL with ?sslmode=verify-full. The connection is then encrypted, and the database's certificate and host name are checked against the certificate authorities Node trusts.
When your provider signs with its own certificate authority, mount its certificate bundle in the container and name it with NODE_EXTRA_CA_CERTS. Start the container with this command in place of the one above:
. ./.env
docker run --detach --name auto-runtime --restart unless-stopped \
--publish 127.0.0.1:5555:5555 --env-file auto-runtime.env \
--volume "$PWD/provider-ca.pem:/etc/auto-runtime/provider-ca.pem:ro" \
--env NODE_EXTRA_CA_CERTS=/etc/auto-runtime/provider-ca.pem \
"$IMAGE"sslmode | What happens |
|---|---|
verify-full | Encrypted, with the certificate and host name checked. Write this one |
require, prefer, verify-ca | Treated as verify-full by the driver, which also prints a multi-line security warning the first time it connects |
no-verify | Encrypted without checking the certificate, so a machine in between can read the connection. Use it only for a test |
Without a password, on Amazon RDS
A database of Amazon RDS or Aurora PostgreSQL can authenticate its user with IAM instead of a password. No database password then exists anywhere: the server signs a token for each connection it opens, from the identity the container runs as.
- Turn IAM database authentication on for the instance or the cluster.
- Grant the database user the
rds_iamrole, in addition to owning its database:GRANT rds_iam TO auto_runtime;. A user with that role signs in with a token. - Give the identity the container runs as
rds-db:connecton that user. That identity is, for example, the role of its task or of its instance. The resource isarn:aws:rds-db:<region>:<account>:dbuser:<the instance's or cluster's resource id>/auto_runtime. - Set
DATABASE_URLwithout a password, andDATABASE_CREDENTIALS=aws-iam. Neither is a secret, so both may go in the container's environment. - Keep TLS on. The certificate authorities of Amazon RDS are not among those Node trusts. Mount their bundle,
global-bundle.pem, in the container and name it withNODE_EXTRA_CA_CERTS.
echo 'DATABASE_URL=postgresql://auto_runtime@ledger.c9akciq32.eu-west-1.rds.amazonaws.com:5432/auto_runtime' >> auto-runtime.env
echo 'DATABASE_CREDENTIALS=aws-iam' >> auto-runtime.env
echo 'NODE_EXTRA_CA_CERTS=/etc/auto-runtime/rds-global-bundle.pem' >> auto-runtime.env
. ./.env
docker run --detach --name auto-runtime --restart unless-stopped \
--publish 127.0.0.1:5555:5555 --env-file auto-runtime.env \
--volume "$PWD/global-bundle.pem:/etc/auto-runtime/rds-global-bundle.pem:ro" "$IMAGE"How the server signs a token
- It signs a new token each time it opens a connection, for the host, the port and the user of
DATABASE_URL. - A token is valid for 15 minutes.
- It uses the credentials of the AWS default credential chain, as the Bedrock provider and the object store do. With
NODE_USE_ENV_PROXY=1set, it reaches AWS through the outbound proxy. - It signs for the region in the host name, such as
eu-west-1above. For a host name without a region, it signs forAWS_REGION. - The connection always uses TLS and checks the database's certificate and host name, as
sslmode=verify-fulldoes, with or withoutsslmodein the URL. - At start the server logs the user and the region it signs for, never a token.
What stops the start
With DATABASE_CREDENTIALS=aws-iam, the server stops at start, naming the setting and never a value, when:
- the URL holds a password;
- the URL names no user;
- the URL gives an
sslmodeother thanverify-full; - the URL gives a TLS option such as
sslrootcert(put the certificate authority inNODE_EXTRA_CA_CERTSinstead), or any other option; - neither the host name nor
AWS_REGIONnames a region.
Two other failures:
- When the server cannot sign a token because the chain finds no credentials, it stops at start with the chain's error.
- When the database refuses a token, because the user lacks
rds_iamor the identity lacksrds-db:connect, the connection fails with the database's error.
Several servers on one database
Several servers may share the database, but only one of them runs the workflows at a time; the others stand by. Choose one server or a standby sets out when that helps and how to route requests. How several servers share the workflows describes the claim, which the database's clock judges. To upgrade them, follow Upgrade several servers.
Back up
The ledger and the workflows are in the same database. Its backups hold everything the runtime keeps, except content kept on object storage.
- On a managed service, use your provider's automated backups and point-in-time recovery.
- On a server you run, use
pg_dump. - Test a restore before you rely on it.