diff --git a/synapse/config/server.py b/synapse/config/server.py
index a387fd9310..7bc0030a9e 100644
--- a/synapse/config/server.py
+++ b/synapse/config/server.py
@@ -16,6 +16,7 @@ import itertools
import logging
import os.path
import re
+import urllib.parse
from textwrap import indent
from typing import Any, Dict, Iterable, List, Optional, Set, Tuple, Union
@@ -264,10 +265,44 @@ class ServerConfig(Config):
self.use_frozen_dicts = config.get("use_frozen_dicts", False)
self.serve_server_wellknown = config.get("serve_server_wellknown", False)
- self.public_baseurl = config.get("public_baseurl")
- if self.public_baseurl is not None:
- if self.public_baseurl[-1] != "/":
- self.public_baseurl += "/"
+ # Whether we should serve a "client well-known":
+ # (a) at .well-known/matrix/client on our client HTTP listener
+ # (b) in the response to /login
+ #
+ # ... which together help ensure that clients use our public_baseurl instead of
+ # whatever they were told by the user.
+ #
+ # For the sake of backwards compatibility with existing installations, this is
+ # True if public_baseurl is specified explicitly, and otherwise False. (The
+ # reasoning here is that we have no way of knowing that the default
+ # public_baseurl is actually correct for existing installations - many things
+ # will not work correctly, but that's (probably?) better than sending clients
+ # to a completely broken URL.
+ self.serve_client_wellknown = False
+
+ public_baseurl = config.get("public_baseurl")
+ if public_baseurl is None:
+ public_baseurl = f"https://{self.server_name}/"
+ logger.info("Using default public_baseurl %s", public_baseurl)
+ else:
+ self.serve_client_wellknown = True
+ if public_baseurl[-1] != "/":
+ public_baseurl += "/"
+ self.public_baseurl = public_baseurl
+
+ # check that public_baseurl is valid
+ try:
+ splits = urllib.parse.urlsplit(self.public_baseurl)
+ except Exception as e:
+ raise ConfigError(f"Unable to parse URL: {e}", ("public_baseurl",))
+ if splits.scheme not in ("https", "http"):
+ raise ConfigError(
+ f"Invalid scheme '{splits.scheme}': only https and http are supported"
+ )
+ if splits.query or splits.fragment:
+ raise ConfigError(
+ "public_baseurl cannot contain query parameters or a #-fragment"
+ )
# Whether to enable user presence.
presence_config = config.get("presence") or {}
@@ -773,6 +808,8 @@ class ServerConfig(Config):
# Otherwise, it should be the URL to reach Synapse's client HTTP listener (see
# 'listeners' below).
#
+ # Defaults to 'https://<server_name>/'.
+ #
#public_baseurl: https://example.com/
# Uncomment the following to tell other servers to send federation traffic on
|