Get started

Install Trinium in about ten minutes.

Everything happens on Linux, with commands you copy from this page. Your email holds the two things only you have: a registry token and a license key. No email yet? Start a free trial and we send you both.

01 · What you need

Linux, Docker and enough memory.

Operating systemAny Linux with Docker, and we recommend Ubuntu. macOS and Windows work for evaluation only, with Docker Desktop.
CPU architecturex86_64 / amd64. On AWS, choose an Intel or AMD instance type (for example m7i or m7a), not a Graviton one (for example m7g).
DockerDocker Engine 25 or newer, with Compose v2.20 or newer (docker compose, not docker-compose). Step 1 below covers it.
MemoryRecommended: 32 GB on the server that runs pipelines (in Option 3, the worker; the controller can be smaller), which is the size the engine is certified at. A smaller server also runs, with a smaller memory budget, but has not been tested. A larger server runs bigger pipelines faster. To run more pipelines at the same time, add servers. In the default demo install the database shares this machine too, so allow for it when you choose a server size.
DiskMinimum: 100 GB on the server that runs pipelines. For production environments a larger disk is highly recommended. A long pipeline run can spill tens of gigabytes to scratch while it runs.
NetworkOutbound HTTPS to pull the images. After that Trinium needs only whatever your pipelines connect to. Inbound, open the web port in your firewall (on AWS, the security group). It is 8080 unless you change TRINIUM_HTTP_PORT in .env. In Option 3 only the controller needs it open and the worker needs no inbound port, but both servers must reach your PostgreSQL and the systems your pipelines connect to: the worker runs the pipelines, and the controller tests connections and reads column lists while you build.
DatabaseOption 1 (demo) runs its own PostgreSQL on this server. Options 2 and 3 (production) use a PostgreSQL server of yours, like Amazon RDS: PostgreSQL 14 or newer and an empty database, and Trinium needs only its connection string.
CredentialsA Docker registry token and a Trinium license key. Both are in your email.

System requirements has the full list, and what changes when Trinium runs on more than one server.

02 · Install

Four steps, then sign in.

Choose where Trinium and its database run then run each block in order

Option 3Two servers and your PostgreSQL.

The worker is the larger server. It runs every pipeline and serves no web. The requirements above are its minimum, but we recommend a larger server to support longer running pipelines.

The controller is a smaller server. It serves the web UI, your schedules and backups. No pipelines. Only the controller needs the web port open.

Both connect to your PostgreSQL, like Amazon RDS, and coordinate through it. They never talk to each other. Do steps 1 to 4 on both servers. Step 2 says which .env goes on which, and step 4 says which to start first.

1

Install Docker

Skip this if the server already has it. Otherwise install Docker Engine with Docker’s own instructions for Ubuntu (other Linux distributions are listed there too). Then check both versions: Engine 25 or newer, shown under Server, and Compose v2.20 or newer.

your-server
sudo docker version
sudo docker compose version

Every docker command on this page starts with sudo, because Docker needs root on a fresh server. Keep it on all of them, so that the registry sign-in and the start in step 4 use the same account. On Docker Desktop (macOS or Windows), leave the sudo off.

2

Create a folder and your .env file

Paste this as it is. It makes a folder called trinium in your home folder, writes .env inside it and makes that file readable only by you. It also makes the two folders Trinium writes into, secrets (your master key) and backups, and hands them to the user Trinium runs as (uid 10001), closed to everyone else. Nothing in Trinium runs as root, so this is done once, here. That line keeps its sudo everywhere, Docker Desktop included: only an administrator can give a folder to another user.

.env · Option 1 · Demo
mkdir -p ~/trinium && cd ~/trinium
sudo mkdir -p secrets backups && sudo chown -R 10001:10001 secrets backups && sudo chmod 700 secrets backups
cat > .env <<'EOF'
TRINIUM_VERSION=1.1.17
LICENSE_KEY=
TRINIUM_HTTP_PORT=8080
COMPOSE_PROFILES=trinium
ADMIN_DEFAULT_PASS=
EOF
chmod 600 .env
.env · Option 2 · Production (minimum)
mkdir -p ~/trinium && cd ~/trinium
sudo mkdir -p secrets backups && sudo chown -R 10001:10001 secrets backups && sudo chmod 700 secrets backups
cat > .env <<'EOF'
TRINIUM_VERSION=1.1.17
LICENSE_KEY=
TRINIUM_HTTP_PORT=8080
COMPOSE_PROFILES=core
ADMIN_DEFAULT_PASS=
EOF
chmod 600 .env
.env · Option 3 · Controller server (the smaller one)
mkdir -p ~/trinium && cd ~/trinium
sudo mkdir -p secrets backups && sudo chown -R 10001:10001 secrets backups && sudo chmod 700 secrets backups
cat > .env <<'EOF'
TRINIUM_VERSION=1.1.17
LICENSE_KEY=
TRINIUM_HTTP_PORT=8080
COMPOSE_PROFILES=controller
ADMIN_DEFAULT_PASS=
EOF
chmod 600 .env
.env · Option 3 · Worker server (the larger one)
mkdir -p ~/trinium && cd ~/trinium
sudo mkdir -p secrets backups && sudo chown -R 10001:10001 secrets backups && sudo chmod 700 secrets backups
cat > .env <<'EOF'
TRINIUM_VERSION=1.1.17
LICENSE_KEY=
TRINIUM_HTTP_PORT=8080
COMPOSE_PROFILES=worker
ADMIN_DEFAULT_PASS=
EOF
chmod 600 .env

Then open .env file nano .env or vi .env and paste your Trinium license key after LICENSE_KEY=. It is the only value you fill in.

Option 1COMPOSE_PROFILES=trinium runs Trinium and its database on this one server.

Option 2COMPOSE_PROFILES=core runs Trinium on this server, with no database of its own.

Option 3COMPOSE_PROFILES=controller on the controller runs the web UI only. COMPOSE_PROFILES=worker on the worker runs the engine.

Options 2 and 3Then tell Trinium where your database is. Its connection string is the only thing Trinium needs, and it goes in one file, secrets/db.key. This creates that file, readable only by Trinium, and opens it. On Option 3, do this on both servers, with the same connection string.

secrets/db.key · Options 2 and 3
sudo touch secrets/db.key && sudo chown 10001:10001 secrets/db.key && sudo chmod 600 secrets/db.key && sudo nano secrets/db.key

Paste the connection string on one line, in this form, and save. The database can be anywhere this server can reach: Amazon RDS or any other PostgreSQL server.

connection string
postgres://user:password@your-database-host:5432/database-name
3

Create compose.yaml

Paste this block as it is, in the same folder. One paste writes the whole compose file.

compose.yaml · 1.1.17
cat > compose.yaml <<'EOF'
name: trinium

services:
  postgres:
    container_name: postgres-db
    image: postgres:16-alpine
    profiles: ["trinium"]
    environment:
      POSTGRES_USER: trinium
      POSTGRES_DB: trinium
      POSTGRES_PASSWORD: trinium-local-db-only
    volumes: ["pgdata:/var/lib/postgresql/data"]
    mem_limit: 2g
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U trinium -d trinium"]
      interval: 5s
      timeout: 3s
      retries: 10
    logging: # Caps log files at 50 MB per service. See INSTALL.md §12.
      driver: json-file
      options: { max-size: "10m", max-file: "5" }
    restart: unless-stopped

  trinium:
    container_name: trinium
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    image: triniumio/trinium:${TRINIUM_VERSION:?set TRINIUM_VERSION in .env}
    profiles: ["trinium"]
    ports: ["${TRINIUM_HTTP_PORT:-8080}:${TRINIUM_HTTP_PORT:-8080}"]
    environment:
      MODE: AllInOne
      PORT: ${TRINIUM_HTTP_PORT:-8080}
      DATABASE_URL: postgres://trinium:trinium-local-db-only@postgres:5432/trinium
      TRINIUM_KEY_DIR: /trinium/secrets
      ADMIN_DEFAULT_PASS: ${ADMIN_DEFAULT_PASS:-}
      LICENSE_KEY: ${LICENSE_KEY:-}
      TRINIUM_FILE_DIR: /trinium/data
      TRINIUM_TLS_DIR: /trinium/tls
      TRINIUM_BACKUP_DIR: /trinium/backups
      TRINIUM_WORK_DIR: /trinium/scratch/work
      TRINIUM_SPILL_DIR: /trinium/scratch/spill
      TRINIUM_MEMORY_BUDGET_MB: ${TRINIUM_MEMORY_BUDGET_MB:-} # Optional cap on engines memory budget, in MB.
      TRINIUM_DB_RESERVE_MB: 2048 # matches the postgres service's mem_limit above

    volumes:
      - "filedata:/trinium/data"
      - "scratch:/trinium/scratch"
      - "./tls:/trinium/tls:ro" # HTTPS. Put cert.pem + key.pem in ./tls to serve TLS
      - "./secrets:/trinium/secrets" #Master key + db connection string
      - "./backups:/trinium/backups" # Local backups. Mount another disk here to keep them elsewhere
    init: true # Runs tini as PID 1
    depends_on:
      postgres:
        condition: service_healthy
    logging: # Caps log files at 50 MB per service. See INSTALL.md §12.
      driver: json-file
      options: { max-size: "10m", max-file: "5" }
    restart: unless-stopped

  core:
    container_name: trinium
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    image: triniumio/trinium:${TRINIUM_VERSION:?set TRINIUM_VERSION in .env}
    profiles: ["core"]
    ports: ["${TRINIUM_HTTP_PORT:-8080}:${TRINIUM_HTTP_PORT:-8080}"]
    environment:
      MODE: AllInOne
      PORT: ${TRINIUM_HTTP_PORT:-8080}
      TRINIUM_KEY_DIR: /trinium/secrets
      ADMIN_DEFAULT_PASS: ${ADMIN_DEFAULT_PASS:-}
      LICENSE_KEY: ${LICENSE_KEY:-}
      TRINIUM_FILE_DIR: /trinium/data
      TRINIUM_TLS_DIR: /trinium/tls
      TRINIUM_BACKUP_DIR: /trinium/backups
      TRINIUM_WORK_DIR: /trinium/scratch/work
      TRINIUM_SPILL_DIR: /trinium/scratch/spill
      TRINIUM_MEMORY_BUDGET_MB: ${TRINIUM_MEMORY_BUDGET_MB:-} # Optional cap on engines memory budget, in MB.

    volumes:
      - "filedata:/trinium/data"
      - "scratch:/trinium/scratch"
      - "./tls:/trinium/tls:ro"
      - "./secrets:/trinium/secrets" # Master key + db.key. Read-write: Trinium creates the key.
      - "./backups:/trinium/backups" # Local backups. Mount another disk here to keep them elsewhere
    init: true
    logging: # Caps log files at 50 MB per service. See INSTALL.md §12.
      driver: json-file
      options: { max-size: "10m", max-file: "5" }
    restart: unless-stopped

  controller:
    container_name: trinium-controller
    image: triniumio/trinium:${TRINIUM_VERSION:?set TRINIUM_VERSION in .env}
    profiles: ["controller"]
    ports: ["${TRINIUM_HTTP_PORT:-8080}:${TRINIUM_HTTP_PORT:-8080}"]
    environment:
      MODE: Controller
      PORT: ${TRINIUM_HTTP_PORT:-8080}
      TRINIUM_KEY_DIR: /trinium/secrets
      ADMIN_DEFAULT_PASS: ${ADMIN_DEFAULT_PASS:-}
      LICENSE_KEY: ${LICENSE_KEY:-}
      TRINIUM_FILE_DIR: /trinium/data
      TRINIUM_TLS_DIR: /trinium/tls
      TRINIUM_BACKUP_DIR: /trinium/backups
    volumes:
      - "filedata:/trinium/data"
      - "./tls:/trinium/tls:ro"
      - "./secrets:/trinium/secrets"
      - "./backups:/trinium/backups" # Local backups. Mount another disk here to keep them elsewhere
    logging: # Caps log files at 50 MB per service. See INSTALL.md §12.
      driver: json-file
      options: { max-size: "10m", max-file: "5" }
    restart: unless-stopped
    init: true

  worker:
    container_name: trinium-engine
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    image: triniumio/trinium:${TRINIUM_VERSION:?set TRINIUM_VERSION in .env}
    profiles: ["worker"]
    environment:
      MODE: Worker
      TRINIUM_KEY_DIR: /trinium/secrets
      LICENSE_KEY: ${LICENSE_KEY:-}
      TRINIUM_FILE_DIR: /trinium/data
      TRINIUM_WORK_DIR: /trinium/scratch/work
      TRINIUM_SPILL_DIR: /trinium/scratch/spill
      TRINIUM_MEMORY_BUDGET_MB: ${TRINIUM_MEMORY_BUDGET_MB:-}
    volumes:
      - "filedata:/trinium/data"
      - "scratch:/trinium/scratch"
      - "./secrets:/trinium/secrets"
    logging: # Caps log files at 50 MB per service. See INSTALL.md §12.
      driver: json-file
      options: { max-size: "10m", max-file: "5" }
    restart: unless-stopped
    init: true

volumes:
  pgdata: # the database
  filedata: # uploaded files + run outputs (the "Local drive")
  scratch: # staged remote files + engine spill
EOF
4

Sign in to the registry and start Trinium

Put the Docker registry token from your email in place of <your-token>. You do this once per server.

Start the controller first.

your-server
echo "<your-token>" | sudo docker login --username triniumio --password-stdin

Then start it:

your-server
sudo docker compose up -d

The first start pulls the images, which takes a few minutes.

Option 3Start the controller first. On its first start it creates the database tables and your master key, secrets/master.key. On the controller print this master key because we need to copy it to the worker:

controller · Option 3
sudo cat secrets/master.key

On the worker run the command below. This creates the same file, readable only by Trinium, and opens it. Paste the line we copied from the master.key file from the controller above. Save it this file. Finally run sudo docker compose up -d on the worker.

worker · Option 3
sudo touch secrets/master.key && sudo chown 10001:10001 secrets/master.key && sudo chmod 600 secrets/master.key && sudo nano secrets/master.key
5

Sign in

Open your server’s IP address and the port from .env in a browser, for example http://203.0.113.10:8080 (on AWS, the instance’s public IPv4 address). Sign in with the username admin and the password admin.

Then change that password straight away, before anything else. The next section says why.

Option 3Open the controller’s address. Once the worker has started, it is listed under Settings → Servers. Before anyone uploads a file, switch Settings → File storage to S3 or Azure Blob: each server has its own disk, so a file uploaded through the controller is invisible to the worker.

03 · Living with it

Secure it first. Then upgrades, backups, TLS and growth.

Do these two things first

Change the admin password.

A fresh install seeds that account so you can get straight in. It is the super admin, and the one account that can never be locked out of the instance, not even by a misconfigured single sign-on provider. Change its password before the server is reachable from anywhere you do not control, and create a normal account for day-to-day use. ADMIN_DEFAULT_PASS in .env stays blank; it exists only to get you back in if you are ever locked out.

Back up your master key somewhere off this server.

Trinium creates it on first start. It encrypts the database credentials, API keys and cloud secrets you save inside Trinium, and it encrypts your backups. Lose it and those credentials become unreadable to anyone, including us, and only a portable backup can still be restored. The file is secrets/master.key, in the trinium folder beside your compose.yaml; copy it somewhere else. It belongs to Trinium’s own user, so on Linux reading it needs sudo. Trinium keeps a reminder in the app until an administrator confirms it is done.

Moving to a new server later means copying that one file across first. Trinium refuses to start against a database it did not encrypt rather than generating a second key over your data, so a forgotten key is a clear message and never a silent loss.

Upgrading

Come back to this page and paste step 3 again, because it always holds the current version’s compose file. Set TRINIUM_VERSION in .env to the version step 2 shows, then run sudo docker compose pull and sudo docker compose up -d. Your pipelines and run history stay where they are, and any database changes are applied at startup.

Paste the compose file too, not just the version. The compose file and the image are a matched pair. Some releases add things that live in the compose file rather than the image, and an image-only upgrade starts fine and then behaves subtly differently.

On Option 3, upgrade both servers, the controller first. A worker on a newer version than the controller refuses to start until the controller has been upgraded.

Changing edition or renewing

Paste the new key into LICENSE_KEY on every server and run sudo docker compose up -d. There is no second image and no migration, because both editions are the same binary and the key decides what is available.

Backups

Configured inside the app under Settings → Backup. A local backup is a file in the backups folder beside your compose.yaml (on Option 3, the controller’s); on Enterprise it can go to cloud storage instead. A backup either carries your credentials and is encrypted with your master key, or you choose portable when you take it and it carries neither, so it restores onto any server with no key at all. You do not need pg_dump, because Trinium backs itself up.

Turning on HTTPS

Put your cert.pem and key.pem in a sub folder called tls under the main Trinium folder we created above, owned by Trinium’s user so it can read the key: sudo mkdir -p tls && sudo cp your-cert.pem tls/cert.pem && sudo cp your-key.pem tls/key.pem, then sudo chown -R 10001:10001 tls && sudo chmod 700 tls && sudo chmod 600 tls/key.pem. On Option 3, this is the controller. Set TRINIUM_HTTP_PORT=443 in .env and redeploy with sudo docker compose up -d. There is no setting to flip. The certificate is the switch and a renewed one is picked up without a restart.

Already terminate TLS at a proxy, load balancer or ingress? Leave the folder empty and keep doing that. Trinium sets no cookies and reads no forwarded headers, so it needs no special configuration behind one.

Adding a second server requires shared file storage. Each server has its own local disk, so a file uploaded on one is invisible to another. Before you scale out, switch Settings → File storage to S3 or Azure Blob. This is a requirement, not an optimization. Scaling out has the steps.
Everything after the install is in the docs. Install and administration covers configuration, upgrades, backups, more servers, disk space, shipping logs to your collector and troubleshooting.

Stuck? Ask the people who built it.

Tell us which step and what the server printed, and you will get a technical answer.