How to Self-Host Element Web with Docker

What Is Element?

Element is the primary client for the Matrix protocol — an open standard for decentralized, end-to-end encrypted communication. Think of Matrix as the protocol (like email) and Element as the app (like Gmail). Element provides messaging, voice/video calls, file sharing, and room-based collaboration. Self-hosting Element gives you a branded web client pointing at your own Matrix homeserver. (element.io)

Element Web is just the client — you also need a Matrix homeserver like Synapse running for it to connect to. This guide covers the Element Web frontend.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • A running Matrix homeserver (Synapse setup guide)
  • 256 MB of free RAM
  • A domain name (recommended for HTTPS)

Docker Compose Configuration

Element Web is a static web application served by Nginx. The Docker setup is minimal — one container, no database.

Create a directory for Element:

mkdir -p ~/element && cd ~/element

Create config.json — this tells Element where your Matrix homeserver is:

{
  "default_server_config": {
    "m.homeserver": {
      "base_url": "https://matrix.yourdomain.com",
      "server_name": "yourdomain.com"
    },
    "m.identity_server": {
      "base_url": "https://vector.im"
    }
  },
  "brand": "Element",
  "default_theme": "dark",
  "room_directory": {
    "servers": [
      "yourdomain.com",
      "matrix.org"
    ]
  },
  "show_labs_settings": true
}

Change matrix.yourdomain.com and yourdomain.com to match your Matrix homeserver configuration.

Create docker-compose.yml:

services:
  element:
    image: vectorim/element-web:v1.12.10
    container_name: element
    ports:
      - "8080:80"
    volumes:
      - ./config.json:/app/config.json:ro    # Element configuration
    restart: unless-stopped

Start the container:

docker compose up -d

Access Element at http://your-server:8080.

Initial Setup

  1. Open Element Web in your browser
  2. The login screen should show your homeserver name (from config.json)
  3. Log in with your Matrix account credentials
  4. If you haven’t created an account yet, click “Create Account” (if registration is enabled on your homeserver)

Element Web connects to whatever homeserver you specify in config.json. Users can also manually change the homeserver on the login screen to connect to any Matrix server.

Configuration

Custom Branding

Customize the Element interface with your organization’s branding:

{
  "brand": "YourOrg Chat",
  "default_theme": "dark",
  "disable_login_language_selector": false,
  "disable_guests": true
}

Jitsi Video Calls

Element supports video conferencing through Jitsi. Configure a Jitsi instance for group calls:

{
  "jitsi": {
    "preferred_domain": "meet.yourdomain.com"
  },
  "jitsi_widget": {
    "skip_built_in_welcome_screen": true
  }
}

You can use the public meet.element.io instance or self-host Jitsi (Jitsi Meet guide).

Feature Flags

Enable experimental features through the labs settings:

{
  "show_labs_settings": true,
  "features": {
    "feature_thread": true,
    "feature_pinning": true,
    "feature_state_counters": true
  }
}

Room Directory

Configure which servers appear in the public room directory:

{
  "room_directory": {
    "servers": [
      "yourdomain.com",
      "matrix.org",
      "mozilla.org"
    ]
  }
}

Why Self-Host Element?

Self-hosting Element Web isn’t strictly necessary — you can use app.element.io (the public instance) to connect to your own homeserver. The reasons to self-host the client:

  • Branding — Custom login page, brand name, and theme for your organization
  • Default homeserver — Point the login screen at your homeserver, not matrix.org
  • Network control — Keep all traffic within your infrastructure
  • Feature control — Enable/disable specific features for your users
  • Compliance — Some organizations require all services to be self-hosted

Reverse Proxy

Element Web serves static files over HTTP on port 80. For production use, put it behind a reverse proxy with HTTPS:

For Caddy:

element.yourdomain.com {
    reverse_proxy element:80
}

For Nginx Proxy Manager, create a proxy host pointing to http://element:80.

Reverse Proxy Setup

Backup

Element Web is stateless — all data lives on the Matrix homeserver, not in the Element container. Back up:

  1. Your config.json file (the only customization)
  2. Your Matrix homeserver (where all messages, rooms, and accounts live)

There’s no database or user data to back up in the Element Web container itself.

Backup Strategy

Troubleshooting

”Unable to connect to homeserver”

Symptom: Element shows a connection error on the login page. Fix: Verify the base_url in config.json is reachable from the browser (not the server). If Element runs at element.example.com and Matrix at matrix.example.com, the browser needs to reach matrix.example.com — it’s a client-side connection, not server-to-server. Check CORS headers on your Matrix homeserver.

Login works but rooms don’t load

Symptom: Can log in but the room list is empty or rooms won’t open. Fix: Check the Matrix homeserver’s .well-known configuration. Element relies on /.well-known/matrix/client being served correctly at your domain root. Verify with curl https://yourdomain.com/.well-known/matrix/client.

Video calls not working

Symptom: Voice/video call buttons are grayed out or calls fail to connect. Fix: Ensure the Jitsi domain in config.json is reachable. For self-hosted Jitsi, verify HTTPS and WebRTC ports (10000/UDP) are accessible.

Config changes not applying

Symptom: Changed config.json but Element still shows old settings. Fix: The config file is loaded once when the container starts. Restart the container after changes: docker compose restart element. Also clear your browser cache — Element caches the config client-side.

Resource Requirements

  • RAM: ~30 MB (Nginx serving static files)
  • CPU: Negligible — static file serving only
  • Disk: ~60 MB for the application image

Element Web is one of the lightest self-hosted applications you can run. The heavy lifting happens on the Matrix homeserver, not the web client.

Verdict

Element Web is worth self-hosting if you’re running your own Matrix homeserver and want a branded, controlled client experience. The setup is trivial — one container, one config file, no database. For personal use, app.element.io works fine and connects to any homeserver. For organizations, self-hosting the client gives you branding and compliance control.

The real investment in a Matrix deployment is the homeserver (Synapse), not the client. Get the homeserver running first, then add a self-hosted Element Web as the final step.