Before you start
Use one persistent /data directory for the Epicenter database, identity key, and local attachment data. Back it up. Losing server-identity.key changes the host’s identity; losing the database loses the Epicenter’s stored history.
For a public Internet deployment, put HTTPS and WebSocket termination in front of the HTTP port and set --public-address to the public multiaddr. For example, a domain served on port 443 is /dns4/epicenter.example.com/tcp/443. The health endpoint is /health.
Railway: Epicenter only
Railway is a good fit for an Epicenter’s HTTP and WebSocket surface. It is not a supported home for the libp2p relay: its TCP proxy address and port are allocated only after deployment, while a relay needs a stable public address that can be configured and advertised from startup.
- Create a service from the Tremor repository. Keep the root directory at the repository root so the Docker build can include the workspace.
- Set the Dockerfile path to
crates/tremor-server/Dockerfile. - Attach a persistent volume at
/data, generate a public domain, and leave Railway’s sleeping/serverless option off. - Set the healthcheck path to
/health. - Use the service’s assigned
PORTin the start command. After the first deploy, replace the example domain with the generated Railway domain or your custom domain.
tremor-server --role epicenter --mode private --port "$PORT" \
--db-path /data/epicenter.db \
--identity-file /data/server-identity.key \
--bootstrap-url https://bootstrap.example.com \
--public-address /dns4/epicenter.example.com/tcp/443
Choose --mode public only when you want the Epicenter advertised in the Bootstrap discovery listing. Private is the default and remains adoptable by its connection details; it is simply not browseable in the public listing.
--role all or --relay-port on Railway. Put the optional relay on a VPS or bare-metal box instead.Docker and Compose
The repository includes a Compose example for a single-node all-in-one deployment and split services at crates/tremor-server/docker-compose.yml. Build from the repository root, because the server Dockerfile copies both tremor-server and tremor-core.
git clone https://github.com/darrynhoskingluna/tremor.git
cd tremor
docker compose -f crates/tremor-server/docker-compose.yml up -d tremor-all
curl -fsS http://127.0.0.1:9090/health
For a public Epicenter, make a local copy of that Compose file and add the stable public multiaddr to the Epicenter command. Keep the /data volume intact across recreates and upgrades.
--public-address /dns4/epicenter.example.com/tcp/443
The tremor-all service exposes HTTP on 9090 and relay TCP on 4002. If you only need the Epicenter, use the split profile and run the Bootstrap service it references, or deploy the Epicenter against an existing Bootstrap URL with --bootstrap-url.
Bare metal with systemd
For a direct VPS install, place a released tremor-server binary at /usr/local/bin/tremor-server, create a dedicated unprivileged tremor user, and give it a durable data directory.
sudo useradd --system --home /var/lib/tremor --shell /usr/sbin/nologin tremor
sudo install -d -o tremor -g tremor /var/lib/tremor
Create /etc/systemd/system/tremor-epicenter.service:
[Unit]
Description=Tremor Epicenter
After=network-online.target
Wants=network-online.target
[Service]
User=tremor
Group=tremor
WorkingDirectory=/var/lib/tremor
ExecStart=/usr/local/bin/tremor-server --role epicenter --mode private --port 9090 --db-path /var/lib/tremor/epicenter.db --identity-file /var/lib/tremor/server-identity.key --bootstrap-url https://bootstrap.example.com --public-address /dns4/epicenter.example.com/tcp/443
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now tremor-epicenter
curl -fsS http://127.0.0.1:9090/health
sudo journalctl -u tremor-epicenter -f
Replace bootstrap.example.com with the Bootstrap host for your deployment. Terminate TLS in a reverse proxy; Caddy forwards WebSocket upgrades automatically:
epicenter.example.com {
reverse_proxy 127.0.0.1:9090
}
Allow HTTPS and, when running a relay, TCP 4002 in both the host firewall and your VPS provider’s firewall. Keep port 9090 and any database port private behind the proxy.
Optional: run a libp2p relay separately
A relay helps peers behind NATs connect to The Grid. It is not required to host an Epicenter, has no Epicenter database, and is best run on a VPS or bare-metal host with a stable public TCP port. Keep its identity key persistent too.
tremor-server --role relay --relay-port 4002 \
--identity-file /var/lib/tremor/relay-identity.key \
--bootstrap-url https://bootstrap.example.com \
--public-address /dns4/relay.example.com/tcp/4002
Open TCP 4002 and use the externally reachable DNS name and port in --public-address. Supplying --bootstrap-url lets the relay register itself for discovery; without it, the relay runs but is not advertised through Bootstrap.
To keep the relay running under systemd, use a separate unit with the same dedicated user and durable directory:
[Service]
User=tremor
Group=tremor
WorkingDirectory=/var/lib/tremor
ExecStart=/usr/local/bin/tremor-server --role relay --relay-port 4002 --identity-file /var/lib/tremor/relay-identity.key --bootstrap-url https://bootstrap.example.com --public-address /dns4/relay.example.com/tcp/4002
Restart=on-failure
[Install]
WantedBy=multi-user.target
Verify and adopt
- Check the local health endpoint:
curl -fsS http://127.0.0.1:9090/health. - Check the same endpoint through the public HTTPS domain.
- Use the Tremor hosting flow to verify the reachable Epicenter and adopt it for your community. Do not publish a connection string until the public health check succeeds.
| Keep persistent | Why |
|---|---|
epicenter.db | Epicenter, MLS Delivery Service, and mailbox state when using SQLite. |
server-identity.key | Stable identity for the Epicenter or all-in-one host. |
relay-identity.key | Stable relay identity when relay runs separately. |
| Attachment storage | Local attachment blobs when using the local blob store. |