Appearance
Home Server & Raspberry Pi
Running a node on hardware you own, rather than a VPS you rent.
It works, and it is the most sovereign version of self-hosting. There is one honest catch, and this page leads with it rather than burying it.
The catch: voice needs UDP that reaches your house
A Dissent node needs three things from the outside world:
| Needs | Carried by | |
|---|---|---|
| Chat, API, WebSocket, the web client | TCP 443 | Anything that can serve HTTPS |
| Voice/video signalling | TCP 443 | Same |
| Voice/video media | UDP 7882–7899 | Only a real UDP path to your machine |
The convenient answers to "how do I get a hostname and a certificate without touching my router" — Cloudflare Tunnel and Tailscale Funnel — carry no public UDP. Cloudflare Tunnel proxies HTTP(S); Tailscale Funnel is TCP/HTTPS on a fixed set of ports. Both give you a working node with working chat, and neither will carry a voice call from a stranger's browser.
Do not skip this paragraph
It is possible to stand up a tunnel-fronted node, watch chat work perfectly, and discover the gap only when your community tries its first voice call. The signalling connects — it is HTTPS — so the client sits in the channel and never gets audio. That failure looks like a bug and is a topology limit.
Pick a route
1. Port forwarding — full function
You control your router and your ISP gives you a public IP.
Forward to the machine running the node:
| Port | Protocol |
|---|---|
| 80 | TCP |
| 443 | TCP + UDP |
| 7882–7899 | UDP |
| 7881 | TCP |
Media used to need a 101-port range (50100–50200) and now goes through a single port, 7882; 7883–7899 is the built-in TURN relay. If you are following an older guide or already forwarded 50100–50200, you can delete that rule.
Then point a hostname at your IP. If your IP changes, use dynamic DNS — see the note on free hostnames below. Everything works, including voice.
2. Cloudflare Tunnel or Tailscale Funnel — chat only
No router access needed, works behind CGNAT, gives you a hostname and TLS for free.
- Chat, DMs, presence, plugins, file uploads: fine
- Voice and video: will not connect
A reasonable choice for a text-first community. Not a choice you want to discover after inviting people who expect voice.
3. Behind CGNAT and you want voice
Your ISP does not give you a reachable address, so there is nothing to forward. The remaining options are:
- A relay you rent. A tiny VPS running TURN, with your node at home. You are paying for a server again, so weigh it against just running the node there.
- Ask your ISP for a public IPv4. Many will, sometimes for a small fee.
- IPv6. If your ISP gives you real IPv6 and your users have it too, media can flow directly. In practice not all of them will.
Free hostnames — what is actually safe
sslip.io and nip.io are not safe for a node you care about
These services resolve 1.2.3.4.sslip.io to 1.2.3.4 with no registration — genuinely dependency-free, which is why they are tempting.
The certificate is the problem. Let's Encrypt caps issuance at 50 certificates per registered domain per 7 days, and it is explicit that this "is a global limit, and all new order requests, regardless of which account submits them, count towards this limit." Registered domains are identified using the Public Suffix List.
Verified against the live list on 2026-08-14: sslip.io and nip.io are not on the Public Suffix List. So every user of those services worldwide shares one 50-certificates-per-week budget. Your renewal competes with strangers, and when it loses, your node's TLS expires.
Options that do not have this problem, because they are on the Public Suffix List — each subdomain counts as its own registered domain with its own quota:
| Notes | |
|---|---|
| A domain you own | The unambiguous answer. ~$10/year, no shared quota, and you can move it later — your node's identity is its key, not its hostname |
DuckDNS (*.duckdns.org) | Free dynamic DNS, on the PSL. setup.sh sets this up for you — see below. Pairs well with route 1 |
Tailscale (*.ts.net) | On the PSL. Funnel still carries no UDP — see route 2 |
Raspberry Pi
A Pi 4 or Pi 5 with 4 GB of RAM runs a small community node.
Everything in the stack has arm64 support: caddy:2-alpine, postgres:16-alpine, redis:7-alpine and livekit/livekit-server all publish arm64 images, and the node itself is built from source by Compose, so it compiles for whatever architecture the Pi is.
Two things that matter more on a Pi than on a VPS:
Do not run Postgres on the SD card. Write endurance is the failure mode, and the failure is your community's entire history. Boot from — or at least mount the Postgres volume on — an SSD over USB 3.
Watch memory. The defaults in docker-compose.prod.yml target a 2 GB machine (api 512m, postgres 512m, redis 128m, livekit 256m). On a 4 GB Pi you can raise them; on a 2 GB Pi 4, leave them alone and expect voice to be the first thing that suffers.
Expect the first docker compose up -d --build to take a while — it is compiling Go on a Pi.
Before you invite anyone
Whichever route you took, prove the two things this page is about:
- Voice. Join a voice channel from a device on a different network — not your own Wi-Fi. Two clients on your LAN can succeed while the outside world cannot reach you at all.
- Backups. Your house is one power supply and one flood away from being the only copy. See Backups & Restore, and put the archive somewhere that is not the same building.
The free-hostname path in setup.sh
If you do not own a domain, setup.sh offers to use DuckDNS and then keeps the record current for you.
You do three things first, and they cannot be automated — DuckDNS has an API for updating a subdomain but none for creating one:
- Open duckdns.org and sign in.
- Create a subdomain.
- Copy the token from the top of the page.
setup.sh asks for the subdomain and the token, then makes a single request that proves the token, proves the subdomain exists, and points it at your machine. If your address later changes, a small ddns service re-points it every five minutes.
Other providers on the Public Suffix List work the same way and can be added to the table in internal/ddns — dedyn.io (deSEC), dynv6.net, freemyip.com, and the No-IP family (ddns.net, hopto.org, zapto.org, myftp.org). afraid.org, mooo.com and dynu.com are not on the list and carry the same shared-quota problem as sslip.io.
Your DuckDNS token is a credential
It grants control of that subdomain, and control of a name is enough to obtain a certificate for it. setup.sh writes it to .env at mode 600 and the updater never logs it. Treat it like a password.
This is a dependency, and worth understanding
If DuckDNS disappears, your node loses its name — not its data, not its identity, and not its federation trust, which is keyed to your node's public key rather than its hostname. You would point a new name at the same machine.
It is your own account with a third party. Dissent has no relationship with it and no traffic passes through it. Bringing your own domain avoids the dependency entirely.