Delegation/split-domain deployment

Matrix allows clients and servers to discover a homeserver's "true" destination via .well-known delegation. This is especially useful if you would like to:

  • Serve Continuwuity on a subdomain while having only the base domain for your usernames
  • Use a port other than :8448 for server-to-server connections

This guide will show you how to have @user:example.com usernames while serving Continuwuity on https://matrix.example.com. It assumes you are using port 443 for both client-to-server connections and server-to-server federation.

Configuration

First, ensure you have set up A/AAAA records for matrix.example.com and example.com pointing to your IP.

Then, ensure that the server_name field matches your intended username suffix. If this is not the case, you MUST wipe the database directory and reinstall Continuwuity with your desired server_name.

Then, in the [global.well_known] section of your config file, add the following fields:

[global.well_known]

# defaults to port :443 if not specified
client = "https://matrix.example.com"

# port number MUST be specified
server = "matrix.example.com:443"

# (optional) customize your support contacts
# Defaults to members of the admin room if unset
#support_page =
#support_role = "m.role.admin"
#support_email =
#support_mxid = "@user:example.com"

Alternatively if you are using Docker, you can set the CONTINUWUITY_WELL_KNOWN environment variable as below:

services:
  continuwuity:
    ...
    environment:
      CONTINUWUITY_WELL_KNOWN: |
        {
        client=https://matrix.example.com,
        server=matrix.example.com:443
        }

      # You can also configure individual `.well-knowns` like this
      # CONTINUWUITY_WELL_KNOWN__CLIENT: https://matrix.example.com
      # CONTINUWUITY_WELL_KNOWN__SERVER: matrix.example.com:443

Reverse proxying well-known files to Continuwuity

After doing the steps above, Continuwuity will serve these 3 JSON files:

  • /.well-known/matrix/client: for Client-Server discovery
  • /.well-known/matrix/server: for Server-Server (federation) discovery
  • /.well-known/matrix/support: admin contact details (strongly recommended to have)

To enable full discovery, you will need to reverse proxy these paths from the base domain back to Continuwuity.

For Caddy
matrix.example.com:443 {
  reverse_proxy 127.0.0.1:8008
}

example.com:443 {
  reverse_proxy /.well-known/matrix* 127.0.0.1:8008
}
For Traefik (via Docker labels)
services:
  continuwuity:
    ...
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.continuwuity.rule=(Host(`matrix.example.com`) || (Host(`example.com`) && PathPrefix(`/.well-known/matrix`)))"
      - "traefik.http.routers.continuwuity.service=continuwuity"
      - "traefik.http.services.continuwuity.loadbalancer.server.port=8008"

Restart Continuwuity and your reverse proxy. Once that's done, visit these routes and check that the responses match the examples below:

https://example.com/.well-known/matrix/server
{ "m.server": "matrix.example.com:443" }
https://example.com/.well-known/matrix/client
{
  "m.homeserver": {
    "base_url": "https://matrix.example.com/"
  }
}

Serving well-known files manually

Instead of configuring [global.well_known] options and reverse proxying well-known URIs, you can serve these files directly as static JSON that match the ones above. This is useful if your base domain points to a different physical server, and reverse proxying isn't feasible.

Example Caddyfile for the base domain
https://example.com {

    respond /.well-known/matrix/server 200 {
        body `{"m.server":"matrix.example.com:443"}`
    }

    handle /.well-known/matrix/client {
    header Access-Control-Allow-Origin *
    respond <<JSON
    {
        "m.homeserver": {
            "base_url": "https://matrix.example.com/"
        }
    }
    JSON
    }
}

Remember to set the Access-Control-Allow-Origin: * header in your /.well-known/matrix/client path for web clients to work.

Troubleshooting

Check with the Matrix Connectivity Tester to see that it's working.

Cannot log in with web clients

Make sure there is an Access-Control-Allow-Origin: * header in your /.well-known/matrix/client path. While Continuwuity serves this header by default, it may be dropped by reverse proxies or other middlewares.

Issues with alternative setups

As Matrix clients prioritize well-known URIs for their destination, this can lead to issues with alternative methods of accessing the server that doesn't use a publicly routeable IP and domain name. You will probably find yourself connecting to non-existent/undesired URLs in certain cases like:

  • Accessing to the server via localhost IPs (e.g. for testing purposes)
  • Accessing the server from behind a VPN, or from alternative networks (such as from an onionsite)

In these scenarios, further configurations would be needed. Refer to the Related Documentation section for resolution steps and see how they could apply to your use case.


Warning

The following methods are not recommended due to increased complexity with little benefits. If you have already set up .well-known delegation as above, you can safely skip this part.

The following methods uses SRV DNS records and only work with federation traffic. They are only included for completeness.

Using only SRV records

If you can't set up /.well-known/matrix/server on :443 for some reason, you can set up a SRV record (via your DNS provider) as below:

  • Service and name: _matrix-fed._tcp.example.com.
  • Priority: 10 (can be any number)
  • Weight: 10 (can be any number)
  • Port: 443
  • Target: matrix.example.com.

On the target's IP at port 443, you must configure a valid route and cert for your server name, example.com. Therefore, this method only works to redirect traffic into the right IP/port combo, and can not delegate your federation to a different domain.

Using SRV records + .well-known

You can also set up /.well-known/matrix/server with a delegated domain but no ports:

[global.well_known]
server = "matrix.example.com"

Then, set up a SRV record (via your DNS provider) to announce the port number as below:

  • Service and name: _matrix-fed._tcp.matrix.example.com.
  • Priority: 10 (can be any number)
  • Weight: 10 (can be any number)
  • Port: 443
  • Target: matrix.example.com.

On the target's IP at port 443, you'll need to provide a valid route and cert for matrix.example.com. It provides the same feature as pure .well-known delegation, albeit with more parts to handle.

Using SRV records as a fallback for .well-known delegation

Assume your delegation is as below:

[global.well_known]
server = "example.com:443"

If your Continuwuity instance becomes temporarily unreachable, other servers will not be able to find your /.well-known/matrix/server file, and defaults to using server_name:8448. This incorrect cache can persist for a long time, and would hinder re-federation when your server eventually comes back online.

If you want other servers to default to using port :443 even when it is offline, you could set up a SRV record (via your DNS provider) as follows:

  • Service and name: _matrix-fed._tcp.example.com.
  • Priority: 10 (can be any number)
  • Weight: 10 (can be any number)
  • Port: 443
  • Target: example.com.

On the target's IP at port 443, you'll need to provide a valid route and cert for example.com.


See the following Matrix Specs for full details on client/server resolution mechanisms: