You are not logged in.
So I want to set up a self-hosted video chat to not be dependent on Discord.
I am already hosting multiple bare-metal services without problems.
For starters a Caddy instance, behind which are a bunch of application servers such as Paperless-NGX, Etebase, Jellyfin, Navidrome. Then also some self-contained things like a ProFTPD instance and Syncthing.
As a half-assed security measure I keep everything out of the line-of-fire by not hosting them on the default ports and (where applicable) hosting them on hard-to-guess subdomains, so they cannot easily be detected by port scanners.
Unfortunately it appears that I have found my match with this video chat thing.
The FOSS solutions of good repute that I know of, e. g. Jitsi, seem like complexity behemoths with multiple cooperating services and heavy requirements regarding internet connectivity:
No NAT supported (?)
Must use default ports to work
Require an ungodly amount of ports forwarded exclusively to them
Require an external TURN server (which is a complex beast and needs to be secured against unauthorized use)
Cannot handle public IP address changes by themselves
(...)
It is enough to make your head spin. Like, what the hell.
What I have is the run-of-the-mill consumer internet connection of the self-hosting aficionado:
VDSL broadband (40 MBit/s up and 100 MBit/s down, maybe upgrade to 300-up 600-down fiber soon)
1 full IPv4 address with NAT in my router (no CGNAT or other funny business)
Full IPv6 connectivity
Forced reconnect after 24 hours that changes all public IP addresses
A capable server with a private IPv4 and a public IPv6 address
The ability to forward ports to the server's internal IPv4 address
The ability to open the router's firewall's ports towards the server's public IPv6 address
A dynamic DNS record with the router's public IPv4 address and the server's public IPv6 address that updates itself after a reconnect
A Let's Encrypt certificate for the domain name and any of its subdomains with automatic renewal
A Caddy reverse proxy on the server, as mentioned
What do I want? Nothing that I perceive to be over the top:
Video chat for 3..4, maybe sometimes 6..7 people
TLS between clients and the server
A browser-based client so no apps can get bit rot
Local, manual user and group management
Hosting on both IPv4 and IPv6
Hosting on a subdomain
Hosting on a non-standard port
Hosting on a sane number of forwarded ports
No containers, must be bare-metal; I need to understand and control what is happening
No 3rd party services (you know, "self hosting")
What I do not need:
Federation
User registration from outside
End-to-end encryption
Client-to-client (P2P) video connections (everything can bounce off the server for all I care)
Reasonable stuff. Imagine Mumble but with video and a web client.
I have found Galène [1] [2], supposedly a no-frills battle-hardenend FOSS video chat server that has its roots in French academia during Covid.
It fits the scope well and does not even require a reverse proxy; you run a self-contained executable that has access to some Let's Encrypt certificate and you open some ports for it, and that should be that.
I got Galène to run its web frontend on a custom subdomain on a custom port with the Let's Encrypt certificate and everything, and I can log in with my users no problem. It is lightning fast.
What does *not* work though is video chat with anybody from outside my LAN. For example, from my smartphone over mobile internet.
When I try that, the Galène server spits out a bunch of log text about how its built-in TURN server tries and fails to broker a video connection between the local and the remote client using something called Interactive Connectivity Establishment (ICE).
So okay, this did not work. But that is what the built-in TURN server is for, no? To relay the video? That is why the server has open ports after all.
But the relay never gets going. Maybe because this built-in TURN server only supports IPv4 for whatever reason.
I have forwarded the UDP and TCP ports 14400..14499 for Galène, and I am starting Galène like this:
/usr/bin/galene -static /usr/share/galene/static -http :14400 -turn vchat.my.domain.net:14401 -udp-range 14402-14499In Galène's data/config.json is also:
"proxyURL": "https://vchat.my.domain.net:14400/"Has anybody gotten to make Galène work properly in an environment like mine, or for that matter another FOSS video chat server?
If so, how did you do it?
[1] https://galene.org/
[2] https://aur.archlinux.org/packages/galene
Offline
matrix supports video chats
Offline
matrix supports video chats
So I have heard, but hosting a Matrix server looks like another such complexity behemoth, possibly even worse than Jitsi.
The field reports that I have found do not instill confidence. [1]
Offline
its actually really easy when i did it
Offline
all these video chat services are going to require the WAN ip address thats just how it works, i hate using docker and always try to run and configure my services by myself but in the case of jitsi as you say its a config nightmare so i use docker-compose in this case.
i will try to explain how i get this done but im not sharing my scripts as they are very old from when i knew very little and they are ugly as hell lol.
-i have a DUC (dynamic update client) running that updates my domain DNS at regular intervals and im guessing you must too as you have a dynamic wan ip like i do (although mine can stay the same for months)
-i have a script that checks this ip from the DUC log and saves it to a file if and when it changes and triggers a restart of the jitsi-docker-compose service
-my custom jitsi-docker-compose service runs a script that updates the jtisi .env file with the current ip and also checks for internet connectivity before starting jitsi
-jitsi has port 10000 forwarded, thats it, everything else runs through nginx reverse proxy
from what i gather video chat isnt simple hence the 'behemoth' solutions...
Offline
I've heard of MiroTalk, it has P2P and SFU variants, though I never tried self-hosting it.
Last edited by Beemo (2026-01-04 06:43:46)
Offline
I have been researching Galène, and by extension coturn, and have got to a sane starting point that somewhat works.
Meanwhile I have read that Discord is going public, and we all know what that will mean for user experience, i. e. they're going to milk their cow like there is no tomorrow. So that makes the whole thing somewhat more pressing.
Alright here goes, long post, I'll just throw out what I got for now quick and dirty, testers and feedback are very much welcome.
What we have for a single public IPv4 address and many public IPv6 addresses, i. e. a typical consumer broadband/fiber IPv4 and IPv6 dual stack, with dynamically changing public IP addresses
Rationale: If I have VDSL or better I should damn well be able to host a video chat for a single-digit number of people with a setup that can be understood and maintained by a layman, you can't tell me that this is not technically feasible in 2026
Seems to work sometimes (sometimes the video starts, sometimes it stays black) but might be tweakable towards working reliably
Topology: Internet ↔ WAN router (public IPv4) ↔ server (private IPv4, public IPv6)
Both Galène and coturn are running on this same server
Public IP addresses change every 24 hours
A managed dynamic DNS entry is available that always points to the current public router IPv4 and server IPv6 address
coturn needes literal public IP addresses in its configuration file; we use a management application "coturn-babysitter" that re-writes coturn's configuration and reloads coturn when the IP addresses have changed
A TLS certificate is available for the domain name (e. g. from Let's Encrypt)
Hosting on non-default ports for reduced discoverability by bad actors because the internet is a scary place
Port forwarding only with 1:1 port mappings, i. e. public port == private port
Port forwarding/opening for Galène and coturn, for both IPv4 and IPv6
TCP UDP 18200 Galene 1 port for the Galène web interface
TCP UDP 18201:18204 Coturn 4 coturn primary ports
___ UDP 26500:26999 Galene_media 500 Galène file sharing ports
___ UDP 54500:55999 Coturn_relay 1500 coturn relay ports
Galène command line invocation:
/usr/bin/galene -static /usr/share/galene/static -http :18200 -udp-range 26500-26999 -turn ""
For now we are exposing Galène directly to the internet, i. e. without having it behind a reverse proxy; this is also the recommended mode of operation by the author
Once stuff works well we can try putting it behind a reverse proxy if we want
Local user galene's home dir is "/var/lib/galene/"; wherein there is a "data/" directory. In there:
Symlinks to TLS certificate
cert.pem → /path/to/certbot/config/live/vchat.the.domain.name/fullchain.pem
key.pem → /path/to/certbot/config/live/vchat.the.domain.name/privkey.pem
Take care that the .pem files are accessible and readable by the galene user
config.json
{
"proxyURL": "https://vchat.the.domain.name:18200/",
"writableGroups": true,
"users": {
"your-admin": {
"password": {
"type": "bcrypt",
"key": "XXXXXXXXXXX..."
},
"permissions": "admin"
}
}
}"key" is the administrator account's bcrypt-encrypted passphrase
ice-servers.json
[
{
"urls": [
"turns:vchat.the.domain.name:18203",
"turns:vchat.the.domain.name:18203?transport=tcp"
],
"username": "galene",
"credential": "YYYYYYYYY....",
"credentialType": "hmac-sha1"
}
]ICE = Interactive Connectivity Establishment, the functionality that is provided by coturn, which in theory should enable people to see each other's video feed
"credential" is a static random string that is also set in the coturn configuration as static-auth-secret=…; This is how Galène authorizes users at coturn using something called "TURN REST API"
"username" is irrelevant and can be chosen as desired
Coturn command line invocation:
/usr/bin/turnserver -c /etc/turnserver/turnserver.conf -v
/etc/turnserver/turnserver.conf
listening-port=18201
alt-listening-port=18202
tls-listening-port=18203
alt-tls-listening-port=18204
min-port=54500
max-port=55999
use-auth-secret
static-auth-secret=YYYYYYYYY....
realm=vchat.the.domain.name:18200
total-quota=2000
cert=/path/to/certbot/config/live/vchat.the.domain.name/fullchain.pem
pkey=/path/to/certbot/config/live/vchat.the.domain.name/privkey.pem
no-stdout-log
log-file=syslog
no-software-attribute
pidfile=/run/turnserver/turnserver.pid
allocation-default-address-family="keep"
no-cli
allowed-peer-ip=192.168.0.10
#### COTURN-BABYSITTER CUTOFF MARKER ####
# Everything below this cutoff marker will be replaced by coturn-babysitter
listening-ip=192.168.0.10
listening-ip=2003:d8:671c:9900:cc:e0ff:fe39:c3e6
external-ip=154.87.6.204/192.168.0.10static-auth-secret=… must be the same as the "credential" in Galène's ice-servers.json for the "TURN REST API" ad-hoc user authentication; this kind of authentication means that coturn does not need to know about Galène's users, and therefore we can run coturn in a stateless mode without a user database
192.168.0.10 is the server's static private IPv4 address
154.87.6.204 is the router's current public IPv4 address and is injected by coturn-babysitter
2003:d8:671c:9900:cc:e0ff:fe39:c3e6 is the server's current public IPv6 address and is injected by coturn-babysitter
The cert= and pkey= TLS .pem files must be read-accessible by the coturn user
Maintains the dynamic IP addresses in coturn's configuration
Full disclosure, I wrote that one, it's in the AUR
Is set up as a one-shot service that is run every 2 minutes from a systemd timer
Coturn-babysitter command line invocation:
/usr/bin/coturn-babysitter --domain-name vchat.the.domain.name --reload
Requires read-write access to /etc/turnserver/turnserver.conf
Requires write access to /etc/turnserver/turnserver.conf.cb-bak
/etc/systemd/system/coturn-babysitter.d/custom.conf
[Service]
ExecStart=
ExecStart=/usr/bin/coturn-babysitter \
--domain-name vchat.the.domain.name \
--reload/etc/coturn-babysitter/turnserver.conf.template
listening-ip=192.168.0.10
listening-ip=_COTURN_BABYSITTER_PUBLIC_IPV6_ADDR_
external-ip=_COTURN_BABYSITTER_PUBLIC_IPV4_ADDR_/192.168.0.10Last edited by eomanis (2026-01-14 01:04:10)
Offline