Skip to content
h8d13 edited this page Jul 28, 2026 · 23 revisions

Step by step, deploy your own server.

It is very simple really:

Prerequisites:

git bash docker.io docker-compose

This can be installed on any linux server. Optionally install sqlite3 and binutils for debugging.

You can also achieve this with rootless-docker or podman equivalents.

Firewall

Recommended: install ufw and disable your VPS provider built-in firewall. Reason being that a lot of cheap VPS providers do not support HTTP/3-Quic protocol.

Setting up the firewall locally:

ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # SSH adjust if you moved sshd off 22
ufw allow 443 # caddy: https (tcp) + http/3 (udp)
ufw allow 80/tcp # caddy ACME http-01 + http->https redirect
ufw enable && ufw status

The catch is to not expose the CAESAR_PORT: "4991" as this is our reverse proxy through caddy.

You can test this by curl -v this port directly, it should hang at Trying...

Note: docker publishes ports through its own iptables chain that bypasses ufw. So ufw protects against accidental host listeners, not against the ports compose publishes. The real surface is docker-compose.yaml ports: blocks.


Get the source code

git clone --depth 1 https://github.com/h8d13/caesar
cd caesar

vCPUs depending on VPS

Docker uses ranges for mediasoup workers. On a cheap 4vCPUs server:

    ports:
      - "40000-40002:40000-40002/tcp"
      - "40000-40002:40000-40002/udp"
    environment:
      CAESAR_PORT: "4991"
      CAESAR_WEBRTC_WORKERS: "3"

Note: I left one vCPU but you could also try with 4 in config above. Adapt these ports according to number of CPUs (your hardware becomes the limit) if you modified docker-compose.yaml

See also net-buffers helper. This increases memory for media-soup in case you plan to run multiple screen-share/webcams at the same time.


Domains

Caddy: caddy/Caddyfile

For further config refer to Caddy documentation: https://caddyserver.com/docs/

If you have a domain + a VPS, you can point to it by adding a A record:

www IN A XX.XX.XX.XXX
@ IN A XX.XX.XX.XXX

CAESAR_SITE is one canonical host, not a list: it is also the WebAuthn RP ID (hardware 2FA / passkeys are bound to it), so the server refuses to boot on a value containing a space or a comma. Serve the www record by adding its own redirect block to caddy/Caddyfile:

www.example.com {
	redir https://example.com{uri} 301
}

Both records then work, certs are issued for both, and the RP ID stays example.com. Skip the www A record if you don't want the alias.

Wiring up to Caesar

Or edit it .env with editor of your choice.

echo 'CAESAR_SITE=sub.example.com' >> .env

This is sourced automatically by docker-compose and ignored in .gitignore.

It can be domains, IPs directly, Tailscale nodes, whatever. One host, no port: the port belongs to Caddy, which publishes 80/443 (host:port only works for the prod-dev profile on :8443).

Both containers read it, for different reasons: Caddy as the site address (cert name + which Host it answers), the server as the WebAuthn RP ID and expected origin.

Full env var reference: Configuration.

Starting the container

Once this is done you can simply run: ./up.sh this runs the prod variant on port 443. Access at: https://yourdomain.ext or with www depending on how you set it up.

Then docker logs caesar on first run will give you a unique one-time use UUID.

Login through the main entry page: First user is always allowed without an invite.

Go to DevTools > Console: useToken("UUID") this sets you as the server owner.

Keeping it updated

Simply: ./updown.sh && ./up.sh

Optionally remove the previous docker cache docker system prune

Discord Alternative per your rules. Fork of Sharkord.

Clone this wiki locally