Install on a VM (Debian/Ubuntu)
This guide installs the controller on a plain VM (or bare-metal host) from the Tessera apt
repository. It runs as a systemd service, tessera-controller, backed by PostgreSQL.
For containers use the image registry.tessera.company/tessera/controller (Docker Compose /
Kubernetes); this page is the VM path.
Requirements
Section titled “Requirements”- Debian 12 or Ubuntu 22.04+ (amd64), root /
sudo. - PostgreSQL 16+ (local or managed).
- Ports:
8443for the web console + proxy (behind your firewall or a reverse proxy).
See System requirements for sizing.
1. PostgreSQL
Section titled “1. PostgreSQL”Install PostgreSQL 16 or newer — the distro’s default package may be older, so follow the
official PostgreSQL install guide for your OS. Then create
the database and user (generate a password with openssl rand -hex 16):
sudo -u postgres psql -c "CREATE USER tessera WITH PASSWORD 'CHANGE_ME';"sudo -u postgres psql -c "CREATE DATABASE tessera OWNER tessera;"Migrations apply automatically on first start.
2. Add the Tessera apt repository
Section titled “2. Add the Tessera apt repository”curl -fsSL https://packages.tessera.company/apt/tessera.gpg.asc \ | sudo gpg --dearmor -o /usr/share/keyrings/tessera.gpg
echo "deb [signed-by=/usr/share/keyrings/tessera.gpg] https://packages.tessera.company/apt stable main" \ | sudo tee /etc/apt/sources.list.d/tessera.list3. Install the controller
Section titled “3. Install the controller”sudo apt updatesudo apt install tessera-controllerapt asks for confirmation before installing — the controller is not installed silently.
On first install the encryption keys (TESSERA_ENC_KEY, TESSERA_JWT_SECRET) are generated
automatically into /etc/tessera/tessera.secret (root-only). You never set them by hand.
4. Configure
Section titled “4. Configure”Edit /etc/tessera/tessera.conf and set at least the database connection:
TESSERA_DATABASE_URL=postgres://tessera:CHANGE_ME@localhost/tessera?sslmode=disable# External URL clients use (include the scheme) — needed for OIDC redirects and links:TESSERA_PUBLIC_URL=https://tessera.example.comThe full list of options is in Configuration. Do not put
the encryption keys here — they live in tessera.secret.
5. Start the service
Section titled “5. Start the service”sudo systemctl enable --now tessera-controllersystemctl status tessera-controller --no-pagerjournalctl -u tessera-controller -n 30 --no-pagerYou should see database connected, migrations applied, and the server listening on :8443.
6. First login
Section titled “6. First login”Open https://<your-server>:8443. On a fresh database the controller bootstraps a default
admin — log in as admin / admin and change the password immediately.
The controller always serves HTTPS. In a dev/test setup it presents a self-signed certificate (your browser warns once). For production, front it with a reverse proxy that terminates TLS — see TLS behind nginx.
TLS behind nginx
Section titled “TLS behind nginx”The controller listens on HTTPS at :8443 (self-signed if no cert is set), so nginx proxies to
https://127.0.0.1:8443 with verification off, and WebSocket upgrade must be forwarded (the
/connect tunnel). Put this in the http block once:
map $http_upgrade $connection_upgrade { default upgrade; '' close; }Then the server block (Let’s Encrypt terminating TLS):
server { listen 80; server_name tessera.example.com; return 301 https://$host$request_uri; }
server { listen 443 ssl; server_name tessera.example.com;
ssl_certificate /etc/letsencrypt/live/tessera.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/tessera.example.com/privkey.pem;
proxy_ssl_verify off; # controller uses a self-signed cert internally proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; 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_read_timeout 3600s; # long-lived SSH / DB sessions
location /metrics { deny all; } # keep metrics internal location / { proxy_pass https://127.0.0.1:8443; }}Set TESSERA_PUBLIC_URL=https://tessera.example.com in tessera.conf so OIDC redirects and
links use the public URL.
Upgrading and backups
Section titled “Upgrading and backups”Upgrades are a planned action, never automatic — an upgrade restarts the controller and
drops active sessions. Back up tessera.secret, PostgreSQL, and /var/lib/tessera. The
what/why/how — including restore — is in Backups & upgrades.
Uninstall
Section titled “Uninstall”sudo systemctl disable --now tessera-controllersudo apt-get purge tessera-controller# leftovers not owned by the package (only for a full wipe — irreversible):sudo rm -f /etc/tessera/tessera.secret # encryption keys → creds become unrecoverablesudo rm -rf /var/lib/tessera # recordings + SSH host keysudo -u postgres psql -c "DROP DATABASE IF EXISTS tessera;"We would like to count visits with Google Analytics, which needs a cookie. Nothing is loaded and nothing is stored unless you accept. What this sets.