This guide walks you through setting up Element Server Suite (ESS) Community on Hetzner Cloud. By the end of this guide, you will be able to use Element to its full extent on the platform of your choice.
Element is an open-source, decentralized, end-to-end encrypted, cross-platform messaging application built on the Matrix protocol. It is available natively for Windows, macOS, Linux, Android, and iOS, and also offers a web client for any browser.
Element combines many of the features we love from other messaging apps: the privacy and anonymity of Signal; servers (called spaces), chat and voice channels, including video and screen sharing, and fine-grained permissions similar to Discord; and polls and live-location sharing like WhatsApp.
This guide is aimed at beginners and non-tech-savvy users who want a robust and ready-to-use solution for a small community quickly. If needed, adjusting the configuration later is straightforward and non-destructive.
You will need approximately $15 per month, an account at Hetzner, and a domain purchased from a registrar of your choice (e.g., Cloudflare). For beginners, completing this guide is expected to take between 1–3 hours.
This guide was written in early 2026. Since I do not regularly set up Element, parts of it may become outdated over time. It is tailored to macOS, so you may need to slightly adjust command-line interface (CLI) operations if you are using Linux, and more significantly if you are using Windows.
The official, up-to-date documentation can be found here: ess-helm, hetzner-k3s.
Don't hesitate to open an issue on GitHub, and I will gladly try to help you.
Open an issue on GitHub and let me know where you struggled, or fork this repository, make improvements directly, and submit a pull request.
Before following the installation instructions, you will need to complete the following:
- Have a macOS device with brew installed.
- Create an account on Hetzner and create a new project.
- Generate and save a Read & Write API token by following this guide.
- Buy a domain at a domain name registrar of your choice (this guide uses Cloudflare).
- Follow this guide to create an SSH key if you don't already have one.
First, you are going to create the configuration files needed, then you'll be setting up Kubernetes, and finally, you are going to install the Element Server Suite.
Chose a permanent folder where you will store every configuration. For the entire guide, you will always work in this folder.
-
Download cluster.yaml. Replace
<your token>with the Hetzner API token you've generated before.If you wish to further configure k3s settings (e.g., adjust server location), follow this guide for a complete example with all options.
-
Download hostnames.yaml. Replace each
<domain>with your domain name (e.g., example.com). -
Download tls.yaml
-
Download mas.yaml.
-
Download synapse.yaml.
Find all available configuration options here, if you wish to customize Synapse.
Should you wish to use a different configuration which automatically spawns between 1–3 Kubernetes nodes exclusively responsible for heavy WebRTC (used for video calls), you need to replace cluster.yaml with cluster and download rtc.yaml additionally. (Warning: Dependent on the workload, this will lead to additional costs of about 11$–33$ per month)
For this step, you'll have to open your terminal at the same directory where you have stored your configurations. Use this terminal session for the entirety of the remaining guide.
-
Install
hetzner-k3s,kubectlandhelm:brew install vitobotta/tap/hetzner_k3s brew install kubectl brew install helm
-
Create your Kubernetes cluster on Hetzner. This will take about 2–3 minutes.
hetzner-k3s create --config cluster.yaml
If you did not adjust
masters_poolorworker_node_poolsincluster.yaml, this action will result in created services which are billed hourely when used and sum up to about 15$ per month. -
Once finished, set up an environment variable:
export KUBECONFIG=./kubeconfigBe advised that this environment variable will have to be set every time you open a new terminal session.
-
Verify that your Kubernetes cluster has successfully been created and is running:
kubectl get nodes
Make sure it says
Readyunder the status value.
Without closing your terminal, open your browser of choice.
-
Go to Hetzner Console, then open your project, and finally chose Servers in the left-hand bar. Copy the value under Public IP (e.g., 42.161.13.12).
-
Create six DNS records of type A. Follow this guide if you have bought your domain at Cloudflare. No matter of your domain name registrar, the DNS record table should ultimately look akin to this:
Type Name IP Proxy status A <domain><Public IP>DNS only A account. <domain><Public IP>DNS only A admin. <domain><Public IP>DNS only A chat. <domain><Public IP>DNS only A matrix. <domain><Public IP>DNS only A mrtc. <domain><Public IP>DNS only Make sure to replace
<Public IP>with the value from Hetzner Console and<domain>with your domain name (e.g., example.com). Also make sure that you set the proxy status for each record toDNS onlyto avoid using a reverse proxy.
Return to your terminal. Periodically run the following command until it returns the public IP address of your Kubernetes cluster (replace <domain> with your domain name):
dig +short A chat.<domain>It may take some time for the DNS to propagate your records. We hereby make sure that your Kubernetes cluster can be reached via your domain before continuing.
-
Install cert-manager using Helm:
helm install \ cert-manager oci://quay.io/jetstack/charts/cert-manager \ --version v1.17.0 \ --namespace cert-manager \ --create-namespace \ --set crds.enabled=true
Find the latest version of cert-manager here.
-
Verify that cert-manager is running:
kubectl get pods -n cert-manager
Make sure that all pods are in the
Runningstate. -
Create the Let's Encrypt issuer:
kubectl apply -f - <<EOF apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-prod-private-key solvers: - http01: ingress: class: traefik EOF
-
Verify that the issuer has been created:
kubectl get clusterissuer letsencrypt-prod
Make sure that the issuer is ready.
-
Create the
essnamespace:kubectl create namespace ess
-
Install ESS using Helm:
helm upgrade --install \ --namespace "ess" \ ess \ oci://ghcr.io/element-hq/ess-helm/matrix-stack \ -f hostnames.yaml \ -f tls.yaml \ -f synapse.yaml \ -f mas.yaml \ --waitAdd optional additional configuration files by appending
-f <file>to the command. The same command is also used to update ESS after changes to configuration files.If you use the autoscale-configuration, make sure to add
-f rtc.yamladditionally to the command. -
Create your first user:
kubectl exec -n ess -it \ deploy/ess-matrix-authentication-service \ -- mas-cli manage register-userEnter your desired username, password and make this user an admin. Then select
Create user, else the user creation fails. -
Either download the desktop or mobile app or navigate to
https://app.<domain>. Enjoy Element! -
To add your friends, instead of manually creating users through the CLI, go to the admin panel at
https://admin.<domain>/registration-tokens/and generate a registration token so your friends can sign up themselves.