How to self host snikket (xmpp) on docker compose
Snikket is a Prosody IM server with a suite of plugins out of the box. It's easy to install XMPP server with plugins already enabled such as upload files, group chats and voice/video calls using TURN!
It's easy to host it but before I start I will assume that:
* You are running debian 11
* You already have a VPS: https://blog.esmailelbob.xyz/how-to-get-a-vps
* Your linux distro is up-to-date (sudo apt update && sudo apt upgrade
)
* You have a domain name: https://blog.esmailelbob.xyz/how-to-get-a-domain-name
* Have sudo access or root account
* Already installed docker and docker-compose: https://blog.esmailelbob.xyz/how-to-install-docker-and-docker-compose
* Already installed Nginx: https://blog.esmailelbob.xyz/how-to-install-and-configure-nginx-96yp
* Already have a reverse proxy conf file: https://blog.esmailelbob.xyz/how-to-use-reverse-proxy-with-nginx
* Already have certbot to issue cert: https://blog.esmailelbob.xyz/how-to-use-certbot-with-nginx-to-make-your-website-get
System Requirements
RAM: 1GB
Changes in DNS (domain side)
You need to add 3 entries. main snikket domain, share.[main snikket domain] and groups.[main snikket domain]. add them as either A entry or CNAME entry it dose not matter!
snikket docker-compose file and snikket.conf
We need a docker-compose.yml
file and snikket.conf
file so we can configure snikket. So we can start snikket, for me I use this file:
version: "3.3"
services:
snikket_proxy:
container_name: snikket-proxy
image: snikket/snikket-web-proxy:beta
env_file: snikket.conf
network_mode: host
volumes:
- ./SNIKKET_DATA:/snikket
- ./SNIKKET_DATA:/var/www/html/.well-known/acme-challenge
restart: "unless-stopped"
snikket_certs:
container_name: snikket-certs
image: snikket/snikket-cert-manager:beta
env_file: snikket.conf
volumes:
- ./SNIKKET_DATA:/snikket
- ./SNIKKET_DATA:/var/www/.well-known/acme-challenge
restart: "unless-stopped"
snikket_portal:
container_name: snikket-portal
image: snikket/snikket-web-portal:beta
network_mode: host
env_file: snikket.conf
restart: "unless-stopped"
snikket_server:
container_name: snikket
image: snikket/snikket-server:beta
network_mode: host
volumes:
- ./SNIKKET_DATA:/snikket
env_file: snikket.conf
restart: "unless-stopped"
volumes:
acme_challenges:
snikket_data:
Optional stuff to change: ./SNIKKET_DATA: Here will be there all of our snikket data, users, avatars and chat and so on.
Snikket.conf
file:
# The primary domain of your Snikket instance
SNIKKET_DOMAIN=esmailelbob.xyz
# An email address where the admin can be contacted
# (also used to register your Let's Encrypt account to obtain certificates)
SNIKKET_ADMIN_EMAIL=esmail@esmailelbob.xyz
# TURNSERVER PORTS
SNIKKET_TWEAK_TURNSERVER_MIN_PORT=49152
SNIKKET_TWEAK_TURNSERVER_MAX_PORT=65535
# SNIKKET PORTS
SNIKKET_TWEAK_HTTP_PORT=5080
SNIKKET_TWEAK_HTTPS_PORT=5443
SNIKKET_DOMAIN: Your XMPP domain, EX: xmpp.esmailelbob.xyz. But in my case I wanted to make it root domain (esmailelbob.xyz) so I had to sacrifice and use lang.esmailelbob.xyz as my main domain :) SNIKKETADMINEMAIL: If you are going to use this for personal use, it does not matter to write real email. Snikket sends a welcome message for registered users and tell them if you want to contact admin use this email SNIKKETTWEAKTURNSERVERMINPORT and SNIKKETTWEAKTURNSERVERMAXPORT: These are the ports for TURN servers for making video/voice calls SNIKKETTWEAKHTTP_PORT and SNIKKETTWEAKHTTPS_PORT: These are the ports for http and https for snikket, we will use HTTP port for nginx anyways so it does not really matter
Spin it up!
Now here we arrived for the tricky part...Because snikket is easy to use, it leaves us without so much customization in hand so if you are like me running snikket behind reverse proxy and will use certbot to issue certificates then you need to first create a dummy website – *create a dummy website block that listens on port 80 and server any static html page* – using same domain you used for snikket and issue certificate by certbot, why? because snikket has built in certbot in docker and it fails to look up your website IF your website does not have https (I know it's confusing, you need certbot to make certbot work or in other words you need https so you can issue https) so yes first create any dummy nginx block for same domain(s) (for all of three snikket domains, as we need 3 sub domains, share.[snikket domain], groups.[snikket domain] and [main snikket domain]) as snikket and run certbot on host/VPS not inside docker (as you do normal with any other domain) and issue the certificates then in nginx prepare the server blocks for snikket and last thing we need is to run snikket's docker compose.
Nginx and reverse proxy
Now after we make sure it's running well. We need to serve it over the internet (called reverse proxy) so without much talk, here is our server block for snikket:
server {
# Accept HTTP connections
listen 80;
listen [::]:80;
server_name [snikket domain];
server_name groups.[snikket domain];
server_name share.[snikket domain];
location / {
proxy_pass http://localhost:5080/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# A bit of headroom over the 16MB accepted by Prosody.
client_max_body_size 20M;
}
}
server {
# Accept HTTPS connections
listen [::]:443 ssl ;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/[snikket domain].xyz/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/[snikket domain].xyz/privkey.pem; # managed by Certbot
server_name [snikket domain];
location / {
proxy_pass https://localhost:5443/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# REMOVE THIS IF YOU CHANGE `localhost` TO ANYTHING ELSE ABOVE
proxy_ssl_verify off;
proxy_set_header X-Forwarded-Proto https;
proxy_ssl_server_name on;
# A bit of headroom over the 16MB accepted by Prosody.
client_max_body_size 20M;
}
# Uncommnet this if you are like me want to sacrifice your root domain for snikket and use another sub domain for your website and other stuff
#return 301 https://lang.esmailelbob.xyz;
}
server {
# Accept HTTPS connections
listen [::]:443 ssl ;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/groups.[snikket domain]/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/groups.[snikket domain]/privkey.pem; # managed by Certbot
server_name groups.[snikket domain];
location / {
proxy_pass https://localhost:5443/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# REMOVE THIS IF YOU CHANGE `localhost` TO ANYTHING ELSE ABOVE
proxy_ssl_verify off;
proxy_set_header X-Forwarded-Proto https;
proxy_ssl_server_name on;
# A bit of headroom over the 16MB accepted by Prosody.
client_max_body_size 20M;
}
}
server {
# Accept HTTPS connections
listen [::]:443 ssl ;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/share.[snikket domain]/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/share.[snikket domain]/privkey.pem; # managed by Certbot
server_name share.[snikket domain];
location / {
proxy_pass https://localhost:5443/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# REMOVE THIS IF YOU CHANGE `localhost` TO ANYTHING ELSE ABOVE
proxy_ssl_verify off;
proxy_set_header X-Forwarded-Proto https;
proxy_ssl_server_name on;
# A bit of headroom over the 16MB accepted by Prosody.
client_max_body_size 20M;
}
}
[snikket domain]: replace this with your snikket domain name proxy_pass: the IP and port of our running docker image
I split server blocks as nginx can not match domain with certificate so yup for each sub domain you literally need to create whole new server block :)
Docker's turn
After that we need to run our container so just run:
docker-compose up -d
the -d
option does not let docker post logs of running application but if you want to see logs you can run:
sudo docker-compose logs -f -t
To check if there any weird behaviors or errors
Update it
Of course after some time the image will be outdated and you need to update and what I love about docker that it's easy to update, really just to do it run:
docker-compose down && docker-compose pull && docker-compose up -d
What it does is: 1) Stops the container, 2) Pull last update (download last update) and 3) Re-run the container back!
Firewall
If you use firewall (ufw for example) You need to open: TCP ports 80 443 5222 5269 5000 UDP ports 49152-65535 (this taken from my config snikket.conf – the turn server ports) TCP & UDP ports 3478 3479 5349 5350
For more info get back to: https://github.com/snikket-im/snikket-server/blob/master/docs/advanced/firewall.md#ports
SOURCES:
For more in depth, you can read same resources I have read while trying to setup my snikket server: * https://snikket.org/service/quickstart/ * https://github.com/snikket-im/snikket-server/blob/master/docs/advanced/reverse_proxy.md * https://github.com/snikket-im/snikket-server/blob/master/docs/advanced/firewall.md