diff --git a/changelog.d/10180.doc b/changelog.d/10180.doc
new file mode 100644
index 0000000000000000000000000000000000000000..1568450198c07c35ebe4db1ab7c569eb9305f083
--- /dev/null
+++ b/changelog.d/10180.doc
@@ -0,0 +1 @@
+Fix broken links in documentation.
\ No newline at end of file
diff --git a/docs/admin_api/README.rst b/docs/admin_api/README.rst
index 37cee87d32e003c29e1b777b0bd1d3f6495eebae..8d6e76580aff99f0c5eb38cc44996e5b0fba1e9f 100644
--- a/docs/admin_api/README.rst
+++ b/docs/admin_api/README.rst
@@ -2,7 +2,7 @@ Admin APIs
 ==========
 
 **Note**: The latest documentation can be viewed `here <https://matrix-org.github.io/synapse>`_.
-See `docs/README.md <../docs/README.md>`_ for more information.
+See `docs/README.md <../README.md>`_ for more information.
 
 **Please update links to point to the website instead.** Existing files in this directory
 are preserved to maintain historical links, but may be moved in the future.
@@ -10,5 +10,5 @@ are preserved to maintain historical links, but may be moved in the future.
 This directory includes documentation for the various synapse specific admin
 APIs available. Updates to the existing Admin API documentation should still
 be made to these files, but any new documentation files should instead be placed under
-`docs/usage/administration/admin_api <../docs/usage/administration/admin_api>`_.
+`docs/usage/administration/admin_api <../usage/administration/admin_api>`_.
 
diff --git a/docs/admin_api/delete_group.md b/docs/admin_api/delete_group.md
index 9c335ff759a5e2a06bf782d3f83c2789ef5d3558..2e0a1d24741fc64a7d74c0a1c033ebe934454a61 100644
--- a/docs/admin_api/delete_group.md
+++ b/docs/admin_api/delete_group.md
@@ -11,4 +11,4 @@ POST /_synapse/admin/v1/delete_group/<group_id>
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: see [Admin API](../../usage/administration/admin_api).
+server admin: see [Admin API](../usage/administration/admin_api).
diff --git a/docs/admin_api/event_reports.md b/docs/admin_api/event_reports.md
index 186139185e5d0f776f0571c00d5f4900c4e5e524..3abb06099c8096e25b59d85488899508325849c0 100644
--- a/docs/admin_api/event_reports.md
+++ b/docs/admin_api/event_reports.md
@@ -7,7 +7,7 @@ The api is:
 GET /_synapse/admin/v1/event_reports?from=0&limit=10
 ```
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: see [Admin API](../../usage/administration/admin_api).
+server admin: see [Admin API](../usage/administration/admin_api).
 
 It returns a JSON body like the following:
 
@@ -95,7 +95,7 @@ The api is:
 GET /_synapse/admin/v1/event_reports/<report_id>
 ```
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: see [Admin API](../../usage/administration/admin_api).
+server admin: see [Admin API](../usage/administration/admin_api).
 
 It returns a JSON body like the following:
 
diff --git a/docs/admin_api/media_admin_api.md b/docs/admin_api/media_admin_api.md
index 9ab5269881548634f7e51a20a811479255932d35..b033fc03efd0c46dcb4c9e903e93f6fd6737a3e4 100644
--- a/docs/admin_api/media_admin_api.md
+++ b/docs/admin_api/media_admin_api.md
@@ -28,7 +28,7 @@ The API is:
 GET /_synapse/admin/v1/room/<room_id>/media
 ```
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: see [Admin API](../../usage/administration/admin_api).
+server admin: see [Admin API](../usage/administration/admin_api).
 
 The API returns a JSON body like the following:
 ```json
@@ -311,7 +311,7 @@ The following fields are returned in the JSON response body:
 * `deleted`: integer - The number of media items successfully deleted
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: see [Admin API](../../usage/administration/admin_api).
+server admin: see [Admin API](../usage/administration/admin_api).
 
 If the user re-requests purged remote media, synapse will re-request the media
 from the originating server.
diff --git a/docs/admin_api/purge_history_api.md b/docs/admin_api/purge_history_api.md
index 25decc3e61073bd2f336a9a65128faf041e9ad77..13b991eacf35658954a1cecb3106706cdcc68d66 100644
--- a/docs/admin_api/purge_history_api.md
+++ b/docs/admin_api/purge_history_api.md
@@ -17,7 +17,7 @@ POST /_synapse/admin/v1/purge_history/<room_id>[/<event_id>]
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 By default, events sent by local users are not deleted, as they may represent
 the only copies of this content in existence. (Events sent by remote users are
diff --git a/docs/admin_api/room_membership.md b/docs/admin_api/room_membership.md
index ed40366099af948b3397930b0e56e65e4a8b6d85..8a5ce191df2e6543f99ffe476733fb7e0c9e8be1 100644
--- a/docs/admin_api/room_membership.md
+++ b/docs/admin_api/room_membership.md
@@ -24,7 +24,7 @@ POST /_synapse/admin/v1/join/<room_id_or_alias>
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: see [Admin API](../../usage/administration/admin_api).
+server admin: see [Admin API](../usage/administration/admin_api).
 
 Response:
 
diff --git a/docs/admin_api/rooms.md b/docs/admin_api/rooms.md
index dc007fa00e82136e205eaad2915b9d24c6f88bb0..bb7828a52529823ea5ab5c8f7437b5b909bb9fb2 100644
--- a/docs/admin_api/rooms.md
+++ b/docs/admin_api/rooms.md
@@ -443,7 +443,7 @@ with a body of:
 ```
 
 To use it, you will need to authenticate by providing an ``access_token`` for a
-server admin: see [Admin API](../../usage/administration/admin_api).
+server admin: see [Admin API](../usage/administration/admin_api).
 
 A response body like the following is returned:
 
diff --git a/docs/admin_api/statistics.md b/docs/admin_api/statistics.md
index d93d52a3ac154e4421b6ee60e56f2afb75b3f61d..1901f1eea025d2ae404d5813949f244fff47519d 100644
--- a/docs/admin_api/statistics.md
+++ b/docs/admin_api/statistics.md
@@ -10,7 +10,7 @@ GET /_synapse/admin/v1/statistics/users/media
 ```
 
 To use it, you will need to authenticate by providing an `access_token`
-for a server admin: see [Admin API](../../usage/administration/admin_api).
+for a server admin: see [Admin API](../usage/administration/admin_api).
 
 A response body like the following is returned:
 
diff --git a/docs/admin_api/user_admin_api.md b/docs/admin_api/user_admin_api.md
index c835e4a0cdbc6cb12ff593159d85e60b490b56a2..ef1e735e33fb3a4b9faa2ee4bf490a4a61591175 100644
--- a/docs/admin_api/user_admin_api.md
+++ b/docs/admin_api/user_admin_api.md
@@ -11,7 +11,7 @@ GET /_synapse/admin/v2/users/<user_id>
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 It returns a JSON body like the following:
 
@@ -78,7 +78,7 @@ with a body of:
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 URL parameters:
 
@@ -119,7 +119,7 @@ GET /_synapse/admin/v2/users?from=0&limit=10&guests=false
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -237,7 +237,7 @@ See also: [Client Server
 API Whois](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-admin-whois-userid).
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 It returns a JSON body like the following:
 
@@ -294,7 +294,7 @@ with a body of:
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 The erase parameter is optional and defaults to `false`.
 An empty body may be passed for backwards compatibility.
@@ -339,7 +339,7 @@ with a body of:
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 The parameter `new_password` is required.
 The parameter `logout_devices` is optional and defaults to `true`.
@@ -354,7 +354,7 @@ GET /_synapse/admin/v1/users/<user_id>/admin
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -384,7 +384,7 @@ with a body of:
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 
 ## List room memberships of a user
@@ -398,7 +398,7 @@ GET /_synapse/admin/v1/users/<user_id>/joined_rooms
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -443,7 +443,7 @@ GET /_synapse/admin/v1/users/<user_id>/media
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -591,7 +591,7 @@ GET /_synapse/admin/v2/users/<user_id>/devices
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -659,7 +659,7 @@ POST /_synapse/admin/v2/users/<user_id>/delete_devices
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 An empty JSON dict is returned.
 
@@ -683,7 +683,7 @@ GET /_synapse/admin/v2/users/<user_id>/devices/<device_id>
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -731,7 +731,7 @@ PUT /_synapse/admin/v2/users/<user_id>/devices/<device_id>
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 An empty JSON dict is returned.
 
@@ -760,7 +760,7 @@ DELETE /_synapse/admin/v2/users/<user_id>/devices/<device_id>
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 An empty JSON dict is returned.
 
@@ -781,7 +781,7 @@ GET /_synapse/admin/v1/users/<user_id>/pushers
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -872,7 +872,7 @@ POST /_synapse/admin/v1/users/<user_id>/shadow_ban
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 An empty JSON dict is returned.
 
@@ -897,7 +897,7 @@ GET /_synapse/admin/v1/users/<user_id>/override_ratelimit
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -939,7 +939,7 @@ POST /_synapse/admin/v1/users/<user_id>/override_ratelimit
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 A response body like the following is returned:
 
@@ -984,7 +984,7 @@ DELETE /_synapse/admin/v1/users/<user_id>/override_ratelimit
 ```
 
 To use it, you will need to authenticate by providing an `access_token` for a
-server admin: [Admin API](../../usage/administration/admin_api)
+server admin: [Admin API](../usage/administration/admin_api)
 
 An empty JSON dict is returned.
 
diff --git a/docs/consent_tracking.md b/docs/consent_tracking.md
index c586b5f0b67cf84448e8c0ec17a8118e7c312372..3f997e590308f9aeecf63b8edb053feb37ce195c 100644
--- a/docs/consent_tracking.md
+++ b/docs/consent_tracking.md
@@ -24,8 +24,8 @@ To enable this, first create templates for the policy and success pages.
 These should be stored on the local filesystem.
 
 These templates use the [Jinja2](http://jinja.pocoo.org) templating language,
-and [docs/privacy_policy_templates](privacy_policy_templates) gives
-examples of the sort of thing that can be done.
+and [docs/privacy_policy_templates](https://github.com/matrix-org/synapse/tree/develop/docs/privacy_policy_templates/)
+gives examples of the sort of thing that can be done.
 
 Note that the templates must be stored under a name giving the language of the
 template - currently this must always be `en` (for "English");
diff --git a/docs/federate.md b/docs/federate.md
index b15cd724d1f6f9d40033d1901fb48a5d1c8b131b..89c2b196385ed2bf08a2fbaae3f9c850e122c6bf 100644
--- a/docs/federate.md
+++ b/docs/federate.md
@@ -14,7 +14,7 @@ you set the `server_name` to match your machine's public DNS hostname.
 
 For this default configuration to work, you will need to listen for TLS
 connections on port 8448. The preferred way to do that is by using a
-reverse proxy: see [reverse_proxy.md](<reverse_proxy.md>) for instructions
+reverse proxy: see [reverse_proxy.md](reverse_proxy.md) for instructions
 on how to correctly set one up.
 
 In some cases you might not want to run Synapse on the machine that has
@@ -44,7 +44,7 @@ a complicated dance which requires connections in both directions).
 
 Another common problem is that people on other servers can't join rooms that
 you invite them to. This can be caused by an incorrectly-configured reverse
-proxy: see [reverse_proxy.md](<reverse_proxy.md>) for instructions on how to correctly
+proxy: see [reverse_proxy.md](reverse_proxy.md) for instructions on how to correctly
 configure a reverse proxy.
 
 ### Known issues
@@ -63,4 +63,4 @@ release of Synapse.
 
 If you want to get up and running quickly with a trio of homeservers in a
 private federation, there is a script in the `demo` directory. This is mainly
-useful just for development purposes. See [demo/README](<../demo/README>).
+useful just for development purposes. See [demo/README](https://github.com/matrix-org/synapse/tree/develop/demo/).
diff --git a/docs/message_retention_policies.md b/docs/message_retention_policies.md
index 75d2028e17407ac443a4efa58e77f8dc5827aa96..ea3d46cc10f36ac5ede0fb4ed82b225b7b91f105 100644
--- a/docs/message_retention_policies.md
+++ b/docs/message_retention_policies.md
@@ -51,7 +51,7 @@ clients.
 
 Support for this feature can be enabled and configured in the
 `retention` section of the Synapse configuration file (see the
-[sample file](https://github.com/matrix-org/synapse/blob/v1.7.3/docs/sample_config.yaml#L332-L393)).
+[sample file](https://github.com/matrix-org/synapse/blob/v1.36.0/docs/sample_config.yaml#L451-L518)).
 
 To enable support for message retention policies, set the setting
 `enabled` in this section to `true`.
@@ -87,7 +87,7 @@ expired events from the database. They are only run if support for
 message retention policies is enabled in the server's configuration. If
 no configuration for purge jobs is configured by the server admin,
 Synapse will use a default configuration, which is described in the
-[sample configuration file](https://github.com/matrix-org/synapse/blob/master/docs/sample_config.yaml#L332-L393).
+[sample configuration file](https://github.com/matrix-org/synapse/blob/v1.36.0/docs/sample_config.yaml#L451-L518).
 
 Some server admins might want a finer control on when events are removed
 depending on an event's room's policy. This can be done by setting the
diff --git a/docs/metrics-howto.md b/docs/metrics-howto.md
index 6b84153274f9114e88752bd4b33ddcad3ee124df..4a77d5604c390d3311d7ce6b16ad6372c80b1903 100644
--- a/docs/metrics-howto.md
+++ b/docs/metrics-howto.md
@@ -72,8 +72,7 @@
 
 ## Monitoring workers
 
-To monitor a Synapse installation using
-[workers](https://github.com/matrix-org/synapse/blob/master/docs/workers.md),
+To monitor a Synapse installation using [workers](workers.md),
 every worker needs to be monitored independently, in addition to
 the main homeserver process. This is because workers don't send
 their metrics to the main homeserver process, but expose them
diff --git a/docs/presence_router_module.md b/docs/presence_router_module.md
index d2844915dffea2b621fcd811c8df67206a51baae..bf859e42545f2418c49a55e213f9271fd3f7e8a1 100644
--- a/docs/presence_router_module.md
+++ b/docs/presence_router_module.md
@@ -30,7 +30,7 @@ presence to (for those users that the receiving user is considered interested in
 It does not include state for users who are currently offline, and it can only be
 called on workers that support sending federation. Additionally, this method must
 only be called from the process that has been configured to write to the
-the [presence stream](https://github.com/matrix-org/synapse/blob/master/docs/workers.md#stream-writers).
+the [presence stream](workers.md#stream-writers).
 By default, this is the main process, but another worker can be configured to do
 so.
 
diff --git a/docs/reverse_proxy.md b/docs/reverse_proxy.md
index cf1b835b9d776173d4f1d271b4c3e879a2d3a516..01db466f96e5d2d080aa1c217e7afad52eef0e65 100644
--- a/docs/reverse_proxy.md
+++ b/docs/reverse_proxy.md
@@ -21,7 +21,7 @@ port 8448. Where these are different, we refer to the 'client port' and the
 'federation port'. See [the Matrix
 specification](https://matrix.org/docs/spec/server_server/latest#resolving-server-names)
 for more details of the algorithm used for federation connections, and
-[delegate.md](<delegate.md>) for instructions on setting up delegation.
+[delegate.md](delegate.md) for instructions on setting up delegation.
 
 **NOTE**: Your reverse proxy must not `canonicalise` or `normalise`
 the requested URI in any way (for example, by decoding `%xx` escapes).
diff --git a/docs/sso_mapping_providers.md b/docs/sso_mapping_providers.md
index 6db2dc8be5b9ecb32cf8d7be967d860883752e66..7a407012e0b19e088be9a4dafb6f53c3a7d87871 100644
--- a/docs/sso_mapping_providers.md
+++ b/docs/sso_mapping_providers.md
@@ -108,7 +108,7 @@ A custom mapping provider must specify the following methods:
 
 Synapse has a built-in OpenID mapping provider if a custom provider isn't
 specified in the config. It is located at
-[`synapse.handlers.oidc.JinjaOidcMappingProvider`](../synapse/handlers/oidc.py).
+[`synapse.handlers.oidc.JinjaOidcMappingProvider`](https://github.com/matrix-org/synapse/blob/develop/synapse/handlers/oidc.py).
 
 ## SAML Mapping Providers
 
@@ -194,4 +194,4 @@ A custom mapping provider must specify the following methods:
 
 Synapse has a built-in SAML mapping provider if a custom provider isn't
 specified in the config. It is located at
-[`synapse.handlers.saml.DefaultSamlMappingProvider`](../synapse/handlers/saml.py).
+[`synapse.handlers.saml.DefaultSamlMappingProvider`](https://github.com/matrix-org/synapse/blob/develop/synapse/handlers/saml.py).
diff --git a/docs/systemd-with-workers/README.md b/docs/systemd-with-workers/README.md
index a1135e9ed578b0749c92def065ac244d7017fe68..a7de2de88acaa0bec27a6684a306eab7e393a803 100644
--- a/docs/systemd-with-workers/README.md
+++ b/docs/systemd-with-workers/README.md
@@ -6,16 +6,18 @@ well as a `matrix-synapse-worker@` service template for any workers you
 require. Additionally, to group the required services, it sets up a
 `matrix-synapse.target`.
 
-See the folder [system](system) for the systemd unit files.
+See the folder [system](https://github.com/matrix-org/synapse/tree/develop/docs/systemd-with-workers/system/)
+for the systemd unit files.
 
-The folder [workers](workers) contains an example configuration for the
-`federation_reader` worker.
+The folder [workers](https://github.com/matrix-org/synapse/tree/develop/docs/systemd-with-workers/workers/)
+contains an example configuration for the `federation_reader` worker.
 
 ## Synapse configuration files
 
 See [workers.md](../workers.md) for information on how to set up the
 configuration files and reverse-proxy correctly. You can find an example worker
-config in the [workers](workers) folder.
+config in the [workers](https://github.com/matrix-org/synapse/tree/develop/docs/systemd-with-workers/workers/)
+folder.
 
 Systemd manages daemonization itself, so ensure that none of the configuration
 files set either `daemonize` or `worker_daemonize`.
@@ -29,8 +31,8 @@ There is no need for a separate configuration file for the master process.
 ## Set up
 
 1. Adjust synapse configuration files as above.
-1. Copy the `*.service` and `*.target` files in [system](system) to
-`/etc/systemd/system`.
+1. Copy the `*.service` and `*.target` files in [system](https://github.com/matrix-org/synapse/tree/develop/docs/systemd-with-workers/system/)
+to `/etc/systemd/system`.
 1. Run `systemctl daemon-reload` to tell systemd to load the new unit files.
 1. Run `systemctl enable matrix-synapse.service`. This will configure the
 synapse master process to be started as part of the `matrix-synapse.target`
diff --git a/docs/workers.md b/docs/workers.md
index 46b5e4b7374b8edf027c44bb15d6d29071c8a58f..797758ee84b3aaa9f3ea6e2232cee13f6bcc3d92 100644
--- a/docs/workers.md
+++ b/docs/workers.md
@@ -16,7 +16,7 @@ workers only work with PostgreSQL-based Synapse deployments. SQLite should only
 be used for demo purposes and any admin considering workers should already be
 running PostgreSQL.
 
-See also https://matrix.org/blog/2020/11/03/how-we-fixed-synapses-scalability
+See also [Matrix.org blog post](https://matrix.org/blog/2020/11/03/how-we-fixed-synapses-scalability)
 for a higher level overview.
 
 ## Main process/worker communication