Running Xentium in production
Most servers should use the installer: see Installing Xentium on a server.
It sets all of this up for you, and the xentium command keeps it running and up to date.
This page covers running Xentium from a git clone, which is what you want when you deploy your own build, or when you are working on core and need production behaviour.
What runs
Section titled “What runs”| Process | Command | What it does |
|---|---|---|
| API | node dist/server.js (in apps/api) |
the HTTP API and the built web app. One port, no separate static server. |
| Worker | node dist/worker.js (in apps/api) |
background jobs: email, scheduled publishing, update checks, clean-ups. |
Both read the same .env and run the same build, so always deploy and restart them
together. Next to them you need PostgreSQL 17 and Redis 7.
git clone https://github.com/slaxxer/xentium.git /srv/xentiumcd /srv/xentiumcorepack enablepnpm install --frozen-lockfilepnpm db:generatepnpm turbo run buildApply database migrations with prisma migrate deploy. Don’t use pnpm db:migrate
on a server: that’s migrate dev, which can offer to reset your database.
systemd
Section titled “systemd”Use one unit per process. The worker’s unit is the same apart from dist/worker.js and
its name.
[Unit]Description=Xentium APIAfter=network.target postgresql.service redis-server.serviceWants=postgresql.service redis-server.service
[Service]Type=simpleUser=xentiumWorkingDirectory=/srv/xentium/apps/apiExecStart=/usr/bin/node dist/server.jsRestart=alwaysRestartSec=5NoNewPrivileges=true
[Install]WantedBy=multi-user.targetSend everything to the API; it serves the web app itself.
server { server_name community.example.com; client_max_body_size 20m;
location / { proxy_pass http://127.0.0.1:4000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300s; proxy_buffering off; # keeps the live style updates (SSE) flowing }}Then run certbot --nginx -d community.example.com for HTTPS.
First run
Section titled “First run”Open the site and go through the install wizard. It checks the database, creates the
site and the first admin, generates every secret and writes .env, then locks itself
when it’s done. Installing from source explains what it asks for.
Things that look broken but aren’t
Section titled “Things that look broken but aren’t”NODE_ENVdefaults toproduction. You have to opt in to development mode, so a server that forgets to set it is safe rather than chatty.- Mail settings live in the ACP (System → Email), not in
.env, so you can change them without redeploying.