Self-Hosted Discord Alternative: Haven
I'm not the gamer I once was, but I still manage the odd evening game. Now as before a voice chat option when gaming with friends is a necessity. While a few more modern games (and now Steam) have voice chat built into them, I generally prefer having an independent solution for this. I also mainly play old titles in any case.
I've used a variety of things for this in the past, including Ventrilo, the until-recently home of this in Discord, and I'm currently hosting Teamspeak. In the case of Discord - which I've ceased using - I tend not to use 90% of it's 'features' (many of which are to me more in the realms of social media) and instead I'm simply after some basic chat (+GIFs) and voice chat capability, screen sharing is a bonus. With Discord (among other things) moving to implement age verification, many others also seem to be intending to leave; this serves as a bit of a template for one option: host a server for your family/friends/community/group.
Looking for Open and Self-Hosted Alternatives
The first alternative I've looked at is Teamspeak, a free (but not open source) voice chat application, which as noted above I'm currently hosting on my Proxmox server. In general, this works fine for my typical use case over a local connection (playing a game with my partner, who's in another room). However, in order to invite other friends to this server, I'd need to open respective ports on my router in order for them to access the server (and probably would need a static IP). With a hosted virtual private server (VPS) this is probably something I'd go for (there are providers which specifically host Teamspeak servers if that's what you're after).
The second option I looked at for Teamspeak is using a kind of tunnel service (first Tailscale funnel and secondly Cloudflare tunnel; I use Tailscale already and have at least one domain managed in Cloudflare). However - this quickly runs into a roadblock which wasn't initially apparent (to my uninitiated self), in that Teamspeak communicates over UDP, TCP and HTTP - tunelling generally only works for HTTP/HTTPS traffic (at least without other work/conversion) - so that plan was dead in the water.
Mumble is another open source (one-up on Teamspeak) and fairly minimal text + voice chat option here, but similarly to Teamspeak it also uses UDP so doesn't fit the requirements for use via a tunnelling service.
So, looking for a voice chat application I could self host which communicates over HTTP/HTTPS, I found Haven. Generally it has the look and feel of a slightly less flashy version of Discord (this is a plus) while also retaining most of the functionality (and 100% of what I need from it). As a client, the application is accessible directly in your browser, but as a bonus for those who want it has both desktop and Android client applications.
Haven: Getting Started
Haven is MIT-licensed on GitHub, and the server component has multiple documented installation methods for Linux systems, including:
- The the preferred method via Docker compose (this is arguably easier to update)
- Running a server directly on a host
Accessing your Server: Networking Requirements
In terms of the networking setup to share your server with friends, Haven has multiple options. The first two don't require any manual intervention on your part, and will work with either installation method:
- Use it locally, with IP addresses within your home network - works for who you live with and maybe your neighbour which has your WiFi password
- Use the built-in Cloudflare or Localtunnel options - these will give you (likely randomly generated) externally accessible URLs which 'just work'. If your server is intended to be ephemeral, or you're happy to ship around a URL to friends whenever you want to jump into a game - this might work pretty well for you.
The third set of options does require some extra work, but will give you a persistent URL to access Haven at, and is possible to configure via a range of services:
- With Cloudflare tunnel, if you have a domain with them
- With Tailscale funnel, although arguably less straightforward to setup
- With Localtunnel, if you pay for the non-free tier (from US$5/month).
We'll look at using a tunnel via Cloudflare below, and link it to the domain which this blog is hosted on.
While this is largely focused on using your own hardware (particularly if you have an old computer lying around and a need for these kinds of basic services) - but f you're happy to pay for it, a Virtual Private Server (VSP) is also a good option - you'll likely get relatively predictable monthly pricing, and this can be simpler and in some ways more secure than hosting something on your own machine. You won't necessarily need a domain (although you could map a domain to your VPS if you wanted) and while the networking setup likely requires a little configuration it's probably a well documented thing for whatever service you're looking at using. Note above the limitations of having simultaneous usage of HTTP/HTTPS, TCP and UDP in an application would be possible in this scenario (you could host Teamspeak or Mumble if voice chat is the core part you're after) - and you could also just use a provider which hosts specific services for you, as I'd mentioned above for Teamspeak.
Installation
In this instance I'm going to start with a Debian 12 LXC image, running on Proxmox. We can quickly update it after starting:
apt update && apt upgrade -y
Note: I don't use
sudohere as I'm running asrootfor the majority of important tasks within the container, but on your device or in your container you might need it.
In either scenario, we'll use the git repository as a starting point:
git clone https://github.com/ancsemi/Haven.git
cd HavenOption 1: Docker
Haven hosts a docker-compose.yml
in their repository, and a pre-built image is available
to save building the repository from source; this image is used by default.
To get setup with Docker, we can first install the Docker engine (if you don't already have Docker in your environment):
Docker Installation
We'll follow the Docker instructions on doing
this in a Debian-based system using apt
but I've added the (March 2026) commands for doing this below.
The first step is to remove any existing Docker components:
apt remove $(dpkg --get-selections docker.io docker-compose docker-doc podman-docker containerd runc | cut -f1)
After that we add Docker's GPG key:
apt install curl -y
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
And from here modify the apt sources to add the Docker repository:
tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
Now we can install the Docker packages:
apt update
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
And check the status of Docker with (Ctrl+C /:q to exit):
systemctl status dockerFrom here, assuming we're in the Haven repository, we can use Docker compose to pull the images and start the container in detached mode:
docker compose up -d
I've added the default YAML compose file below for reference, if you're curious:
docker-compose.yml
# ── Haven Docker Compose ─────────────────────────────────
# Quick start: docker compose up -d
# Stop: docker compose down
# View logs: docker compose logs -f haven
# Update: docker compose pull && docker compose up -d --force-recreate
# Shell: docker compose exec haven sh
# ─────────────────────────────────────────────────────────
services:
haven:
image: ghcr.io/ancsemi/haven:latest
# build: . # Uncomment to build from source instead of using the pre-built image
container_name: haven
ports:
- "${PORT:-3000}:${PORT:-3000}" # Main HTTPS port
- "${REDIRECT_PORT:-3001}:${REDIRECT_PORT:-3001}" # HTTP → HTTPS redirect
volumes:
- haven_data:/data
# ── Or use a local folder instead (good for NAS / Synology): ──
# - ./haven-data:/data
environment:
- PORT=${PORT:-3000}
- HOST=0.0.0.0
# - SERVER_NAME=My Haven # Name shown in the UI
# - ADMIN_USERNAME=admin # First account to register becomes admin
# - GIPHY_API_KEY= # Optional: enable GIF search
# - VAPID_EMAIL=mailto:you@example # Optional: email for push notifications
# - TURN_URL=turn:your-server:3478 # Optional: TURN relay for voice over internet
# - TURN_SECRET=your-secret # Shared secret (coturn --use-auth-secret)
# Uncomment to load settings from a .env file:
# env_file: .env
restart: unless-stopped
volumes:
haven_data:After this completes, your service should now be running on https://<LOCAL_IP_ADDRESS>:3000.
To check the IP address of your machine, you can use the following to list all of your network
interfaces:
ip a
If you know you have e.g. an ethernet interface on eth0, you can use:
ip a show eth0
You can take the address (an IPv4 address will look something like 192.168.0.127) you can visit
e.g. https://192.168.0.127:3000 to access your Haven server; note you'll probably have a
'Be careful. Something doesn’t look right.' kind of warning message
the first time you access this, you can click 'Advanced' -> 'Proceed'.
You should now see a login/register page for Haven. You can register with the username
admin in order to have access to server admin functions (you can change the display name
later). If you don't need a persistent tunnel for external access, you're now done, congrats!
Have a look through setting up your server, and if you're going to use the built-in tunnel
functionality, at least consider whitelisting the usernames who are able to register.
Updating
In terms of updating, it's typically going to look like:
docker compose pull
docker compose up -d --force-recreateOption 2: Server Directly on the Host
If you're running this in a Linux Container (LXC), you already have one level of isolation on your host, and you don't necessarily need to use Docker. Similarly, if this e.g. the only thing running on a small machine, you could install it directly on the host.
To use the server, the main thing we'll need is
apt install nodejs npm
To run the server, from the repository we've cloned above, we can use the start scripts provided:
chmod +x start.sh && ./start.sh
This will run until killed, so any other things we want running will need to run another way.
Tunnel Setup
Once this is up and looks OK locally, we can add the route in Cloudflare
by configuring your tunnel in the ... menu, and then clicking Add Route in the Routes diagram.
You'll need to select your subdomain (I used hvn), and add the service URL (Haven uses
https://localhost:3000).
We will need to create a tunnel on Cloudflare, and get a tunnel token. Once you've created your tunnel, you can extract the token from one of the installation options which Cloudflare gives you (copy paste and take the long text token at the end).
1One of the key things here which otherwise tripped me up was that the setup for Haven requires a configuration change in Cloudflare Zero Trust to turn off TLS verification (you might need to make an Org to get in; the basics of this are still free-tier). For Docker, I'd tried using
--no-tls-verifyin the run command andNO_TLS_VERIFY=truein the environment but neither helped, and I was relegated to the Cloudflare dashboard.
You'll need to select your tunnel in the page linked above, select the 'published application routes' tab, and then click on the '⋮' menu, select 'Edit', go down to 'Additional application settings', select 'TLS' and turn on 'No TLS Verify'. Save this, and with luck you can access your server via your subdomain added earlier (e.g. https://hvn.fluids.rocks).
If you want to see what this might look like with Tailscale funnel (would require a Tailscale account but otherwise free and doesn't require you to own a domain, let alone one in Cloudflare), let me know and I'll see what I can put together!
Tunnel on the Host
To use cloudflared with an installation of Haven on the host,
we can pull down the binary from GitHub:
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared
We can verify this is installed:
cloudflared --version
You can run the binary itself to create a tunnel (e.g. without a token this would create an anonymous/ randomized url), but we'll set it up as a service using our tunnel token:
cloudflared service install <TUNNEL_TOKEN>
Once installed, we can start the cloudflared service:
systemctl start cloudflared
If any of the configuration (IP addresses, the TLS settings etc) changes, it's best to restart the service:
systemctl restart cloudflared
From here, we would then run the server:
chmod +x start.sh && ./start.shTunnel in Docker
If you want to use Docker but want a peristent tunnel URL, we can modify the
docker-compose.yml file to add a cloudflared service which provides the
tunnel to the networks. This requires:
- A Cloudflare account
- A domain managed by Cloudflare which you can attach this to (i.e., the persistent part)
Before we do anything else, we can quickly take down our Docker services:
docker compose down
We'll insert our tunnel token in place of <TUNNEL_TOKEN> in the below YAML file:
docker-compose-cloudflared.yml
# ── Haven Docker Compose ─────────────────────────────────
# Quick start: docker compose up -f docker-compose-cloudflared.yml -d
# Stop: docker compose down
# View logs: docker compose logs -f haven
# Update: docker compose -f docker-compose-cloudflared.yml pull && docker compose up -f docker-compose-cloudflared.yml -d --force-recreate
# Shell: docker compose exec haven sh
# ─────────────────────────────────────────────────────────
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
- TUNNEL_TOKEN=<TUNNEL_TOKEN>
ports:
- "${PORT:-3000}:${PORT:-3000}" # Main HTTPS port
- "${REDIRECT_PORT:-3001}:${REDIRECT_PORT:-3001}" # HTTP → HTTPS redirect
haven:
image: ghcr.io/ancsemi/haven:latest
# build: . # Uncomment to build from source instead of using the pre-built image
container_name: haven
#ports:
# - "${PORT:-3000}:${PORT:-3000}" # Main HTTPS port
# - "${REDIRECT_PORT:-3001}:${REDIRECT_PORT:-3001}" # HTTP → HTTPS redirect
volumes:
- haven_data:/data
# ── Or use a local folder instead (good for NAS / Synology): ──
# - ./haven-data:/data
environment:
- PORT=${PORT:-3000}
- HOST=0.0.0.0
# - FORCE_HTTP=true
# - SERVER_NAME=My Haven # Name shown in the UI
# - ADMIN_USERNAME=admin # First account to register becomes admin
# - GIPHY_API_KEY= # Optional: enable GIF search
# - VAPID_EMAIL=mailto:you@example # Optional: email for push notifications
# - TURN_URL=turn:your-server:3478 # Optional: TURN relay for voice over internet
# - TURN_SECRET=your-secret # Shared secret (coturn --use-auth-secret)
# Uncomment to load settings from a .env file:
# env_file: .env
restart: unless-stopped
network_mode: service:cloudflared
volumes:
haven_data:In this file we've added a bit of network configuration:
for the cloudflared service we've mapped the ports 3000 and 3001
(used by Haven) and in the haven service used network_mode: service:cloudflared.
The port mapping allows local IP access (if you don't need it, you can remove this),
and the network_mode: service:cloudflared ensures that Haven can use our tunnel.
Note that we're not mapping ports in the haven service here (the port mapping
has just moved up).
There may be some secret sauce which means we don't need to do the
no-tls-verifyfaff above1, but I haven't found it yet (tried thePORTvariable, but I had no luck with this so far) .
We can copy the contents of the file above, and paste it to a file called
docker-compose-cloudflared.yml:
nano docker-compose-cloudflared.yml
From here, we can start up our modified services:
docker compose -f docker-compose-cloudflared.yml up -d --force-recreate
Before we go any further, if you've kept the port mapping it's best to check that you can access your service at your local IP address (e.g. https://192.168.0.127:3000, but using the IP address of your machine). If there's an issue already here, we might not succeed in the tunnel bit.
Whitelisting Users in Haven
By default, your Haven instance will allow registrations from anyone who accesses the server. This may not be what you're after. If you have a group of friends you're looking to host a server for, you can do a call around and get a list of usernames to whitelist in Haven, which marginally improves your security situation (random folks who find your server won't be able to sign up without using one of these usernames).
If you're logged in as the/an admin user, the configuration for this is currently under Settings -> Whitelist. You'll need to both i) turn on whitelisting with the 'enabled' toggle and ii) add the users you're allowing to sign up.
You can also use invite codes, and set channels to invite-only/private, if you're planning to use multiple for different purposes/allow different folk to do and see different things.