Continuwuity for Docker

Preparation

Choose an image

The following OCI images are available for Continuwuity:

If you want a specific version or commit hash, you can browse for them here.

Images are also mirrored to these locations automatically, on a schedule:

Prerequisites

Continuwuity requires HTTPS for Matrix federation. You'll need:

  • A domain name pointing to your server's IP address - we will be using example.com in this guide.

  • A reverse proxy with SSL/TLS certificates (Traefik, Caddy, nginx, etc.) - see Docker Compose for complete examples.

  • Port :443 (for Client-Server traffic) and :8448 (for federation traffic) opened on your server's firewall.

    • Alternatively, if you want both client and federation traffic on :443, you can configure CONTINUWUITY_WELL_KNOWN following some of the examples below.
Split-domain setups

For more setups with .well-known delegation and split-domain deployments, consult the Delegation/Split-domain page.

Docker Compose

Docker Compose is the recommended deployment method for Continuwuity containers. The following environment variables will be set:

  • CONTINUWUITY_SERVER_NAME - Your Matrix server's domain name. This CANNOT be changed later without a data wipe.
  • CONTINUWUITY_DATABASE_PATH - Where to store your database. This must match the docker volume mount.
  • CONTINUWUITY_ADDRESS - Bind address (for Docker, use 0.0.0.0 to listen on all interfaces).

Alternatively, you can specify a path to mount the configuration file using the CONTINUWUITY_CONFIG environment variable.

See the reference configuration page for all config options, and the Configuration page on how to convert them into Environment Variables.

Choose Your Reverse Proxy

These examples include reverse proxy configurations for Matrix federation, which will route your Matrix domain (and optionally .well-known paths) to Continuwuity.

Docker DNS Performance

Docker's default DNS resolver are known to cause timeout issues for Matrix federation. To bypass it and use a more performant resolver, mount a custom /etc/resolv.conf config file into the Continuwuity container.

docker-compose.yml
services:
  homeserver:
    # ...
    volumes:
      - ./continuwuity-resolv.conf:/etc/resolv.conf
continuwuity-resolv.conf
nameserver 1.0.0.1
nameserver 1.1.1.1

Consult the DNS tuning guide (recommended) for full solutions to this issue.

Caddy (using Caddyfile)

docker-compose.with-caddy.yml (view raw)
services:
    caddy:
        image: docker.io/caddy:latest
        ports:
            - 80:80
            - 443:443
            - 8448:8448
        networks:
            - caddy
        volumes:
            - ./data:/data
        restart: unless-stopped
        configs:
            - source: Caddyfile
              target: /etc/caddy/Caddyfile

    homeserver:
        image: forgejo.ellis.link/continuwuation/continuwuity:latest
        restart: unless-stopped
        command: /sbin/conduwuit
        volumes:
            - db:/var/lib/continuwuity
            - ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
            #- ./continuwuity.toml:/etc/continuwuity.toml
        environment:
            CONTINUWUITY_SERVER_NAME: example.com
            CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
            CONTINUWUITY_ADDRESS: 0.0.0.0
            CONTINUWUITY_PORT: 8008
            #CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above

            ## (Optional) Serve .well-known files to tell others to reach Continuwuity on port :443
            ## If you do this, remove all routes to port :8448 from the compose and Caddyfile
            # CONTINUWUITY_WELL_KNOWN: |
            #     {
            #     client=https://example.com,
            #     server=example.com:443
            #     }


        networks:
            - caddy

networks:
    caddy:

volumes:
    db:

configs:
    dynamic.yml:
        content: |
            https://example.com, https://example.com:8448 {
                reverse_proxy http://homeserver:8008
            }

Caddy (using labels)

docker-compose.with-caddy-labels.yml (view raw)
services:
    caddy:
    # This compose file uses caddy-docker-proxy as the reverse proxy for Continuwuity!
    # For more info, visit https://github.com/lucaslorentz/caddy-docker-proxy
        image: lucaslorentz/caddy-docker-proxy:ci-alpine
        ports:
            - 80:80
            - 443:443
        environment:
            - CADDY_INGRESS_NETWORKS=caddy
        networks:
            - caddy
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
            - ./data:/data
        restart: unless-stopped

    homeserver:
        image: forgejo.ellis.link/continuwuation/continuwuity:latest
        restart: unless-stopped
        command: /sbin/conduwuit
        volumes:
            - db:/var/lib/continuwuity
            - ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
            #- ./continuwuity.toml:/etc/continuwuity.toml
        environment:
            CONTINUWUITY_SERVER_NAME: example.com
            CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
            CONTINUWUITY_ADDRESS: 0.0.0.0
            CONTINUWUITY_PORT: 8008
            #CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above

            # Serve .well-known files to tell others to reach Continuwuity on port :443
            CONTINUWUITY_WELL_KNOWN: |
                {
                client=https://example.com,
                server=example.com:443
                }

        networks:
            - caddy
        labels:
            caddy: example.com
            caddy.reverse_proxy: "{{upstreams 8008}}"
volumes:
    db:

networks:
    caddy:

Traefik (for existing setup)

docker-compose.for-traefik.yml (view raw)
# Continuwuity - Behind Traefik Reverse Proxy

services:
  homeserver:
    image: forgejo.ellis.link/continuwuation/continuwuity:latest
    restart: unless-stopped
    command: /sbin/conduwuit
    volumes:
      - db:/var/lib/continuwuity
      - ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
      #- ./continuwuity.toml:/etc/continuwuity.toml
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.continuwuity.rule=(Host(`example.com`))"
      - "traefik.http.routers.continuwuity.entrypoints=websecure" # your HTTPS entry point
      - "traefik.http.routers.continuwuity.tls=true"
      - "traefik.http.routers.continuwuity.service=continuwuity"
      - "traefik.http.services.continuwuity.loadbalancer.server.port=8008"
      # possibly, depending on your config:
      # - "traefik.http.routers.continuwuity.tls.certresolver=letsencrypt"
    environment:
      CONTINUWUITY_SERVER_NAME: example.com
      CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
      CONTINUWUITY_ADDRESS: 0.0.0.0
      CONTINUWUITY_PORT: 8008 # This must match with traefik's loadbalancer label
      #CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above

      # Serve .well-known files to tell others to reach Continuwuity on port :443
      CONTINUWUITY_WELL_KNOWN: |
        {
        client=https://example.com,
        server=example.com:443
        }

volumes:
  db:

networks:
  # This is the network Traefik listens to, if your network has a different
  # name, don't forget to change it here and in the docker-compose.override.yml
  proxy:
    external: true

Traefik included

docker-compose.with-traefik.yml (view raw)
# Continuwuity - Behind Traefik Reverse Proxy

services:
  homeserver:
    image: forgejo.ellis.link/continuwuation/continuwuity:latest
    restart: unless-stopped
    command: /sbin/conduwuit
    volumes:
      - db:/var/lib/continuwuity
      - ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
      #- ./continuwuity.toml:/etc/continuwuity.toml
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.continuwuity.rule=(Host(`example.com`))"
      - "traefik.http.routers.continuwuity.entrypoints=websecure"
      - "traefik.http.routers.continuwuity.tls.certresolver=letsencrypt"
      - "traefik.http.services.continuwuity.loadbalancer.server.port=8008"
    environment:
      CONTINUWUITY_SERVER_NAME: example.com
      CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
      CONTINUWUITY_ADDRESS: 0.0.0.0
      CONTINUWUITY_PORT: 8008 # This must match with traefik's loadbalancer label
      #CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above

      # Serve .well-known files to tell others to reach Continuwuity on port :443
      CONTINUWUITY_WELL_KNOWN: |
        {
          client=https://example.com,
          server=example.com:443
        }

  traefik:
    image: "traefik:latest"
    container_name: "traefik"
    restart: "unless-stopped"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:z"
      - "acme:/etc/traefik/acme"
    labels:
      - "traefik.enable=true"

      # middleware redirect
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      # global redirect to https
      - "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.redirs.entrypoints=web"
      - "traefik.http.routers.redirs.middlewares=redirect-to-https"

    environment:
      TRAEFIK_LOG_LEVEL: DEBUG
      TRAEFIK_ENTRYPOINTS_WEB: true
      TRAEFIK_ENTRYPOINTS_WEB_ADDRESS: ":80"
      TRAEFIK_ENTRYPOINTS_WEB_HTTP_REDIRECTIONS_ENTRYPOINT_TO: websecure

      TRAEFIK_ENTRYPOINTS_WEBSECURE: true
      TRAEFIK_ENTRYPOINTS_WEBSECURE_ADDRESS: ":443"
      TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_TLS_CERTRESOLVER: letsencrypt

      TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT: true
      # CHANGE THIS to desired email for ACME
      TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_EMAIL: [email protected]
      TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE: true
      TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_HTTPCHALLENGE_ENTRYPOINT: web
      TRAEFIK_CERTIFICATESRESOLVERS_LETSENCRYPT_ACME_STORAGE: "/etc/traefik/acme/acme.json"

      # Since Traefik 3.6.3, paths with certain "encoded characters" are now blocked by default; we need a couple, or else things *will* break
      TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSLASH: true
      TRAEFIK_ENTRYPOINTS_WEBSECURE_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDHASH: true

      TRAEFIK_PROVIDERS_DOCKER: true
      TRAEFIK_PROVIDERS_DOCKER_ENDPOINT: "unix:///var/run/docker.sock"
      TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT: false

volumes:
  db:
  acme:

networks:
  proxy:

Traefik (as override file)

docker-compose.override.yml (view raw)
# Continuwuity - Traefik Reverse Proxy Labels

services:
  homeserver:
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"  # Change this to the name of your Traefik docker proxy network

      - "traefik.http.routers.to-continuwuity.rule=Host(`example.com`)"  # Change to the address on which Continuwuity is hosted
      - "traefik.http.routers.to-continuwuity.tls=true"
      - "traefik.http.routers.to-continuwuity.tls.certresolver=letsencrypt"
      - "traefik.http.routers.to-continuwuity.middlewares=cors-headers@docker"

      # This must match with CONTINUWUITY_PORT (default: 8008)
      - "traefik.http.services.to_continuwuity.loadbalancer.server.port=8008"

      - "traefik.http.middlewares.cors-headers.headers.accessControlAllowOriginList=*"
      - "traefik.http.middlewares.cors-headers.headers.accessControlAllowHeaders=Origin, X-Requested-With, Content-Type, Accept, Authorization"
      - "traefik.http.middlewares.cors-headers.headers.accessControlAllowMethods=GET, POST, PUT, DELETE, OPTIONS"

      # If you want to have your account on <DOMAIN>, but host Continuwuity on a subdomain,
      # you can let it only handle the well known file on that domain instead
      #- "traefik.http.routers.to-matrix-wellknown.rule=Host(`example.com`) && PathPrefix(`/.well-known/matrix`)"
      #- "traefik.http.routers.to-matrix-wellknown.tls=true"
      #- "traefik.http.routers.to-matrix-wellknown.tls.certresolver=letsencrypt"
      #- "traefik.http.routers.to-matrix-wellknown.middlewares=cors-headers@docker"

For other reverse proxies

docker-compose.yml (view raw)
# Continuwuity

services:
    homeserver:
        image: forgejo.ellis.link/continuwuation/continuwuity:latest
        restart: unless-stopped
        command: /sbin/conduwuit
        ports:
            - 127.0.0.1:8008:8008
        volumes:
            - db:/var/lib/continuwuity
            - ./continuwuity-resolv.conf:/etc/resolv.conf # use custom resolvers rather than Docker's
            #- ./continuwuity.toml:/etc/continuwuity.toml
        environment:
            CONTINUWUITY_SERVER_NAME: example.com # EDIT THIS
            CONTINUWUITY_DATABASE_PATH: /var/lib/continuwuity
            CONTINUWUITY_ADDRESS: 0.0.0.0
            CONTINUWUITY_PORT: 8008
            #CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above

            ## (Optional) Serve .well-known files to tell others to reach Continuwuity on port :443
            ## If you do this, remove all routes to port :8448 on your reverse proxy
            # CONTINUWUITY_WELL_KNOWN: |
            #     {
            #     client=https://example.com,
            #     server=example.com:443
            #     }


volumes:
    db:

You will then need to point your reverse proxy towards Continuwuity at 127.0.0.1:8008. See the Other reverse proxies section of the Generic page for further routing details.

Starting Your Server

  1. Choose your compose file from the above, and rename it to docker-compose.yml. Replace example.com with your homeserver's domain name, and edit other values as you see fit.

  2. If using the override file, rename it to docker-compose.override.yml and edit your values.

  3. Start the server:

    docker compose up -d
  4. Check your server logs for a registration token:

    docker-compose logs continuwuity 2>&1

    You'll see output as below.

    In order to use your new homeserver, you need to create its
    first user account.
    Open your Matrix client of choice and register an account
    on example.com using registration token x5keUZ811RqvLsNa .
    Pick your own username and password!
  5. Log in to your server with any Matrix client, and register for an account with the registration token from step 4. You'll automatically be invited to the admin room where you can manage your server.

See the generic deployment guide for more deployment options.

Testing

Test that your setup works by following these instructions

Other deployment methods

Docker - Quick Run

For testing only

The instructions below are only meant for a quick demo of Continuwuity. For production deployment, we recommend using Docker Compose

Get a working Continuwuity server with an admin user in four steps:

  1. Pull the image

    docker pull forgejo.ellis.link/continuwuation/continuwuity:latest
  2. Start the server for the first time. Replace example.com with your actual server name.

    docker run -d \
      -p 8008:8008 \
      -v continuwuity_db:/var/lib/continuwuity \
      -e CONTINUWUITY_SERVER_NAME="example.com" \
      -e CONTINUWUITY_DATABASE_PATH="/var/lib/continuwuity" \
      -e CONTINUWUITY_ADDRESS="0.0.0.0" \
      -e CONTINUWUITY_ALLOW_REGISTRATION="false" \
      --name continuwuity \
      forgejo.ellis.link/continuwuation/continuwuity:latest \
      /sbin/conduwuit
  3. Fetch the one-time initial registration token

    docker logs continuwuity 2>&1

    You'll see output as below.

    In order to use your new homeserver, you need to create its
    first user account.
    Open your Matrix client of choice and register an account
    on example.com using registration token x5keUZ811RqvLsNa .
    Pick your own username and password!
  4. Configure your reverse proxy to forward HTTPS traffic to Continuwuity at port 8008. See Docker Compose for examples.

Once configured, log in to your server with any Matrix client, and register for an account with the registration token from step 3. You'll automatically be invited to the admin room where you can manage your server.

(Optional) Building Custom Images

For information on building your own Continuwuity Docker images, see the Building Docker Images section in the development documentation.

Next steps

  • For smooth federation, set up a caching resolver according to the DNS tuning guide (recommended)
  • To set up Audio/Video communication, see the Calls page.
  • If you want to set up an appservice, take a look at the Appservice Guide.