Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: Split Custom Domains as Explanation and How-to Guide (Diátaxis) #9676

Merged
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
6b08a64
Diatáxis refactor: Move Custom Domains to the How-to section
benjaoming Oct 19, 2022
35647a8
Proposal: Split up Custom Domains into two articles, no new contents …
benjaoming Oct 20, 2022
620f03a
Try to make "Custom Domain" feature description more self-contained
benjaoming Oct 20, 2022
a8b42e9
Update cross-references to match new location
benjaoming Oct 20, 2022
16baf25
Update docs/user/guides/custom-domains.rst
benjaoming Oct 21, 2022
e702e01
Update docs/user/custom-domains.rst
benjaoming Oct 21, 2022
216f4b5
Update seealso:: box with a better pattern
benjaoming Oct 21, 2022
27795ad
Merge branch 'diataxis/move-custom-domains' of github.com:benjaoming/…
benjaoming Oct 21, 2022
c5ff11b
Remove redundant section label
benjaoming Oct 24, 2022
85994e9
Merge branch 'diataxis/main' of github.com:readthedocs/readthedocs.or…
benjaoming Nov 25, 2022
a071664
Add custom-domains to explanation section, add a "What to consider" s…
benjaoming Nov 25, 2022
9b2a5a4
Replace "central" with "reliable"
benjaoming Nov 25, 2022
e81981e
Remove the example, there's already enough explanation
benjaoming Nov 25, 2022
60b4069
Add mention of canonical domains
benjaoming Nov 25, 2022
d660530
Highlight **canonical** at first apperance, then emphasize its import…
benjaoming Nov 25, 2022
8aac235
Try to simplify explanation and adds CNAME to the equation.
benjaoming Nov 28, 2022
234aaf0
Fix language
benjaoming Nov 28, 2022
42bfb84
Remove "by default"
benjaoming Nov 28, 2022
b40f904
Apply suggestions from code review @ericholscher
benjaoming Nov 28, 2022
33c2e53
Use Dashboard term
benjaoming Nov 29, 2022
f3bf30b
Fix up the canonical domain explanation
benjaoming Nov 29, 2022
13de41b
Change to use :guilabel: in explanation of where to add Custom Domains
benjaoming Nov 30, 2022
19234fe
Try to build an SVG diagram with sphinxcontrib-mermaid and mmdc
benjaoming Dec 1, 2022
df034f5
Start a real diagram, only build with mmdc if in a Read the Docs build
benjaoming Dec 1, 2022
9f1a58f
Disable SVG generation with mermaid-js
benjaoming Dec 1, 2022
133ec92
Swap direction of diagram, add some more icons
benjaoming Dec 1, 2022
778ca17
Also illustrate the build process
benjaoming Dec 1, 2022
e435ab9
Sketching: Move contents of Canonical URLs to Custom Domains explanat…
benjaoming Dec 1, 2022
5e7bd3c
Tweak text, sembr
benjaoming Dec 1, 2022
6b3c7b7
Canonical URLs again in separate article. More cross-references in Cu…
benjaoming Dec 2, 2022
585a115
Make sure to mention cache invalidation for Read the Docs for Business
benjaoming Dec 2, 2022
ea43c43
Replace "See more" with a better caption
benjaoming Dec 2, 2022
ed2bbf6
Merge branch 'diataxis/main' of github.com:readthedocs/readthedocs.or…
benjaoming Dec 6, 2022
21d64b7
Refer using seealso::
benjaoming Dec 6, 2022
2d9c62e
Text tweaks to Canonical URLs explanation
benjaoming Dec 6, 2022
4d0746e
Move How-to content to a separate how-to
benjaoming Dec 6, 2022
3e52416
Updates to the original Canonical URLs how-to sections and further re…
benjaoming Dec 6, 2022
03f68a4
Revert back to previous phrase, it reads better
benjaoming Dec 6, 2022
4dd01d8
Update docs/user/canonical-urls.rst
benjaoming Dec 6, 2022
93953a1
Apply suggestions from code review from @agjohnson and @benjaoming
benjaoming Dec 6, 2022
42e8368
Update docs/user/custom-domains.rst
benjaoming Dec 6, 2022
b2824a1
Apply suggestions from @ericholscher code review
benjaoming Dec 7, 2022
db3ff0d
Downgrade cross-reference from a seealso to normal text re:@ericholsher
benjaoming Dec 7, 2022
20f7349
Add a cautious message to anyone that would want to define html_baseurl.
benjaoming Dec 7, 2022
b3c749c
parenthesis clarified
benjaoming Dec 7, 2022
2ee8508
Add a shortcut convention for referencing issues
benjaoming Dec 7, 2022
2972aa7
Add example code for MkDocs which unfortunately requires a bit of ela…
benjaoming Dec 7, 2022
eea3ec0
Updates diagram and intro text to be easier to digest
benjaoming Dec 7, 2022
5726e8f
Add a bold text that a project needs to be rebuilt. Move the note abo…
benjaoming Dec 7, 2022
30d7d74
Turn support seealso into a note
benjaoming Dec 7, 2022
3ca6b7d
Merge branch 'diataxis/main' of github.com:readthedocs/readthedocs.or…
benjaoming Dec 7, 2022
e8856d3
Apply suggestions from @ericholscher code review
benjaoming Dec 8, 2022
22a7bfe
Convert Mermaid diagram to SVG, remove sphinxcontrib-mermaid
benjaoming Dec 8, 2022
b5a230b
Merge branch 'diataxis/move-custom-domains' of github.com:benjaoming/…
benjaoming Dec 8, 2022
1c14c80
Add a closing backtick, remove image alignment (causes wrong vertical…
benjaoming Dec 8, 2022
ef276b8
Update docs/user/guides/canonical-urls.rst
benjaoming Dec 9, 2022
ba392a7
Manually create a PNG version (not as straight-forward as assumed)
benjaoming Dec 9, 2022
d85055e
Merge branch 'diataxis/move-custom-domains' of github.com:benjaoming/…
benjaoming Dec 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
"multiproject",
"sphinx.ext.autosectionlabel",
"sphinx.ext.autodoc",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinxcontrib.httpdomain",
"sphinxcontrib.mermaid",
"sphinxcontrib.video",
"djangodocs",
"doc_extensions",
Expand Down Expand Up @@ -159,8 +161,11 @@
hoverxref_domains = ["py"]
hoverxref_roles = [
"option",
"doc", # Documentation pages
"term", # Glossary terms
# Documentation pages
# Not supported yet: https://github.com/readthedocs/sphinx-hoverxref/issues/18
"doc",
# Glossary terms
"term",
]
hoverxref_role_types = {
"mod": "modal", # for Python Sphinx Domain
Expand Down Expand Up @@ -206,3 +211,28 @@
# This page is under login
r"https://readthedocs\.org/accounts/gold",
]

extlinks = {
"rtd-issue": ("https://github.com/readthedocs/readthedocs.org/issues/%s", "#"),
}

# Config values for sphinxcontrib-mermaid are handled differently
# If running on a local environment, we render "raw" and bundle mermaid-js from CDN to render diagrams in the browser.
# This is to avoid requiring the @mermaid-js/mermaid-cli package
#
# This can run locally but the following issues need to be solved:
# a) Read the Docs Docker images need at least libasound2 to be installed for puppeteer to work.
# b) A <style> with FontAwesome needs to be injected into the SVG's DOM.
if False and os.environ.get("READTHEDOCS"):
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

# Write SVGs, those we can style via CSS! (we aren't doing that yet)
mermaid_output_format = "svg"

# Do not load javascript from CDN
mermaid_version = ""

# Nothing to init, we don't build raw diagrams
mermaid_init_js = ""

# Use transparent backgrounds
mermaid_params = ["--backgroundColor", "transparent"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove all of this at the end of this PR. It seems we cannot benefit from the extension, unless we resolve how to run mermaid-cli in RTD docker containers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using Sphinx Timeline to express the steps required for the DNS: https://sphinx-timeline.readthedocs.io/en/latest/ ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What times would you use?

49 changes: 20 additions & 29 deletions docs/user/canonical-urls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,34 @@ Canonical URLs

A `canonical URL`_
allows you to specify the preferred version of a web page to prevent duplicated content.
They are mainly used by search engines to link users to the correct
version and domain of your documentation.
Here are some examples of when a canonical URL is used:

If canonical URL's aren't used,
- Search engines use your canonical URL to link users to the correct version and domain of your documentation.
- Many popular chat clients and social media networks generate link previews,
using your canonical URL as the final destination.
ericholscher marked this conversation as resolved.
Show resolved Hide resolved

If canonical URLs aren't used,
it's easy for outdated documentation to be the top search result for various pages in your documentation.
This is not a perfect solution for this problem,
but generally people finding outdated documentation is a big problem,
and this is one of the suggested ways to solve it from search engines.

.. _canonical URL: https://developers.google.com/search/docs/advanced/crawling/consolidate-duplicate-urls

.. tip::

In most cases, Read the Docs will automatically generate a canonical URL for Sphinx projects.
Most Sphinx users do not need to take further action.

.. seealso::

:doc:`/guides/canonical-urls`
More information on how to enable canonical URLs in your project.

How Read the Docs generates canonical URLs
------------------------------------------

The canonical URL takes into account:
The canonical URL takes the following into account:

* The default version of your project (usually "latest" or "stable").
* The canonical :doc:`custom domain </custom-domains>` if you have one,
Expand All @@ -40,32 +53,10 @@ thus avoiding duplicating the content.
Implementation
--------------

The canonical URL is set in HTML with a ``link`` element.
For example, this page has a canonical URL of:
A canonical URL is automatically specified in the HTML output with a ``<link>`` element.
For instance, regardless of whether you are viewing this page on ``/en/latest`` or ``/en/stable``,
the following HTML header data will be present:

.. code-block:: html

<link rel="canonical" href="https://docs.readthedocs.io/en/stable/canonical-urls.html" />

Sphinx
~~~~~~

If you are using :doc:`Sphinx </intro/getting-started-with-sphinx>`,
Read the Docs will set the value of the html_baseurl_ setting (if isn't already set) to your canonical domain.
If you already have ``html_baseurl`` set, you need to ensure that the value is correct.

.. _html_baseurl: https://www.sphinx-doc.org/page/usage/configuration.html#confval-html_baseurl

Mkdocs
~~~~~~

For :doc:`MkDocs </intro/getting-started-with-mkdocs>` this isn't done automatically,
but you can use the site_url_ setting to set a similar value.

.. _site_url: https://www.mkdocs.org/user-guide/configuration/#site_url

.. warning::

If you change your default version or canonical domain,
you'll need to re-build all your versions in order to update their
canonical URL to the new one.
154 changes: 56 additions & 98 deletions docs/user/custom-domains.rst
Original file line number Diff line number Diff line change
@@ -1,126 +1,84 @@
Custom Domains
==============
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

Custom domains allow you to serve your documentation from your own domain.
This is great for maintaining a consistent brand for your documentation and application.
You can serve your documentation project from your own domain,
for instance ``docs.example.com``.
This is great for maintaining a consistent brand for your product and its documentation.

By default, your documentation is served from a Read the Docs :ref:`subdomain <hosting:subdomain support>` using the project's :term:`slug`:
*By default*, your documentation is served from a Read the Docs :ref:`subdomain <hosting:subdomain support>` using the project's :term:`slug`:

* ``<slug>.readthedocs.io`` for |org_brand|
* ``<slug>.readthedocs-hosted.com`` for |com_brand|.

For example if you import your project and it gets the :term:`slug` ``example-docs``, it will be served from ``https://example-docs.readthedocs.io``.
.. seealso::

.. contents:: Contents
:local:
:doc:`/guides/custom-domains`
Information on creating and managing custom domains,
and common configurations you might use to set up your domain
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

Adding a custom domain
----------------------
How custom domains work
-----------------------

To setup your custom domain, follow these steps:
To use a custom domain, two actions are all that are needed from you: 1) enter the domain in your Read the Docs project's :guilabel:`Admin` and 2) update your DNS provider with a new DNS entry. The name and value of the DNS entry is found in Read the Docs' :guilabel:`Admin`.
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

#. Go the :guilabel:`Admin` tab of your project.
#. Click on :guilabel:`Domains`.
#. Enter the domain where you want to serve the documentation from (e.g. ``docs.example.com``).
#. Mark the :guilabel:`Canonical` option if you want use this domain
as your :doc:`canonical domain </canonical-urls>`.
#. Click on :guilabel:`Add`.
#. At the top of the next page you'll find the value of the DNS record that you need to point your domain to.
For |org_brand| this is ``readthedocs.io``, and for :doc:`/commercial/index`
the record is in the form of ``<hash>.domains.readthedocs.com``.
Once the new DNS record has propagated,
Read the Docs automatically issues an SSL certificate through Cloudflare and starts serving your documentation.

.. note::
.. mermaid::

For a subdomain like ``docs.example.com`` add a CNAME record,
and for a root domain like ``example.com`` use an ANAME or ALIAS record.
graph TD
subgraph rtd [On Read the Docs]
A(fa:fa-pencil Add docs.example.com as Custom Domain)
end
subgraph dns [On your domain's DNS administration]
B(fa:fa-pencil Edit/add a DNS entry for docs.example.com<br>making it point to Read the Docs)
end

By default, we provide a validated SSL certificate for the domain,
managed by `Cloudflare <https://www.cloudflare.com/>`_.
The SSL certificate issuance should happen within a few minutes,
but might take up to one hour.
See `SSL certificate issue delays`_ for more troubleshooting options.
rtd & dns-->C(fa:fa-spinner Wait for DNS propagation.<br>Usually just a few minutes)

As an example, our blog's DNS record looks like this:
direction LR
subgraph automatic [fa:fa-paper-plane The rest is handled automatically]
direction TB
D(fa:fa-spinner The next time your project is built,<br>its Canonical URLs use docs.example.com)
D-->E(Visit https://docs.example.com)
E-->F(fa:fa-lock Correct SSL Certificate <br>automatically used)
F-->G(fa:fa-check Read the Docs knows<br> to serve your project <br>at ``docs.example.com``)
end

.. prompt:: bash $, auto
C-->automatic

$ dig +short CNAME blog.readthedocs.com
readthedocs.io.

.. warning::
Your documentation can have multiple secondary domains but only one **canonical** domain name.
Additional domains or subdomains will redirect to the canonical domain.
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

We don't support pointing subdomains or root domains to a project using A records.
DNS A records require a static IP address and our IPs may change without notice.
To make this work, Read the Docs generates a special text that you are responsible for copy-pasting to your domain's DNS.
In most cases, the ``CNAME`` record is used.
This is all that's needed for a web browser to resolve your domain name to Read the Docs' servers and for our servers to match the right documentation project.
You can find step-by-step instructions for this in :doc:`/guides/custom-domains`.

Read the Docs uses a :ref:`hosting:Content Delivery Network (CDN)` to host and serve your documentation pages.
This final step isn't changed by a custom domain
and therefore the response times are unaffected as the delivery of resources happens through the same CDN setup.

Removing a custom domain
------------------------
Considerations for custom domain usage
--------------------------------------

To remove a custom domain:
Some open source projects have seen their domains expire.
Even prominent ones.
**It's important that you give the responsibility for managing your domain to someone reliable in your organization.**

#. Go the :guilabel:`Admin` tab of your project.
#. Click on :guilabel:`Domains`.
#. Click the :guilabel:`Remove` button next to the domain.
#. Click :guilabel:`Confirm` on the confirmation page.
The **canonical domain** feature allows you to have several domains and the canonical domain will be indexed by search engines.
The domain that you choose as your canonical domain is by far the most important one.
If you lose the canonical domain,
someone else can set up a website that search results will end up referring to.

.. warning::
.. seealso::

Once a domain is removed,
your previous documentation domain is no longer served by Read the Docs,
and any request for it will return a 404 Not Found!
In a URL, both the domain and the path (``https://<domain>/<path>``) are important.
In combination, they are referred to as the *canonical URL* of a resource.

Strict Transport Security (HSTS) and other custom headers
---------------------------------------------------------
Most documentation projects are versioned.
Therefore, it's important to ensure that incoming links and search engine results point to the canonical URL of the resource
and not a specific version that becomes outdated.

By default, we do not return a `Strict Transport Security header`_ (HSTS) for user custom domains.
This is a conscious decision as it can be misconfigured in a not easily reversible way.
For both |org_brand| and |com_brand|, HSTS and other custom headers can be set upon request.

We always return the HSTS header with a max-age of at least one year
for our own domains including ``*.readthedocs.io``, ``*.readthedocs-hosted.com``, ``readthedocs.org`` and ``readthedocs.com``.

Please contact :doc:`support` if you want to add a custom header to your domain.

.. _Strict Transport Security header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security

Multiple documentation sites as sub-folders of a domain
-------------------------------------------------------

You may host multiple documentation repositories as **sub-folders of a single domain**.
For example, ``docs.example.org/projects/repo1`` and ``docs.example.org/projects/repo2``.
This is `a way to boost the SEO of your website <https://moz.com/blog/subdomains-vs-subfolders-rel-canonical-vs-301-how-to-structure-links-optimally-for-seo-whiteboard-friday>`_.

See :doc:`subprojects` for more information.

Troubleshooting
---------------

SSL certificate issue delays
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The status of your domain validation and certificate can always be seen on the details page for your domain
under :guilabel:`Admin` > :guilabel:`Domains` > :guilabel:`YOURDOMAIN.TLD (details)`.

Domains are usually validated and a certificate issued within minutes.
However, if you setup the domain in Read the Docs without provisioning the necessary DNS changes
and then update DNS hours or days later,
this can cause a delay in validating because there is an exponential back-off in validation.

.. tip::

Loading the domain details in the Read the Docs dashboard and saving the domain again will force a revalidation.

The validation process period has ended
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After you add a new custom domain, you have 30 days to complete the configuration.
Once that period has ended, we will stop trying to validate your domain.
If you still want to complete the configuration,
go to your domain and click on :guilabel:`Save` to restart the process.

Migrating from GitBook
~~~~~~~~~~~~~~~~~~~~~~

If your custom domain was previously used in GitBook, contact GitBook support (via live chat in their website)
to remove the domain name from their DNS Zone in order for your domain name to work with Read the Docs,
else it will always redirect to GitBook.
To learn more about canonical URLs, see: :doc:`/canonical-urls`
6 changes: 6 additions & 0 deletions docs/user/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ Glossary
and hypens. You can retreive your project or version slugs from
:doc:`our API <api/v3>`.

subproject
Project A can be configured such that when requesting a URL ``/projects/<subproject-slug>``,
the root of project B is returned.
In this case, *project B* is the subproject.
Read more in :doc:`/subprojects`.

root URL
Home URL of your documentation without the ``/<lang>`` and ``/<version>`` segments.
For projects without custom domains, the one ending in ``.readthedocs.io/``
Expand Down
2 changes: 2 additions & 0 deletions docs/user/guides/administrators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ have a look at our :doc:`/tutorial/index`.
.. toctree::
:maxdepth: 1

Manage Custom Domains <custom-domains>
ericholscher marked this conversation as resolved.
Show resolved Hide resolved
Enable Canonical URLs <canonical-urls>
technical-docs-seo-guide
manage-translations-sphinx
hiding-a-version
Expand Down
57 changes: 57 additions & 0 deletions docs/user/guides/canonical-urls.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
How to Enable Canonical URLs
============================

In this guide, we introduce relevant settings for enabling canonical URLs in popular documentation frameworks.

If you need to customize the domain from which your documentation project is served,
please refer to :doc:`/guides/custom-domains`.

Sphinx
~~~~~~

If you are using :doc:`Sphinx </intro/getting-started-with-sphinx>`,
Read the Docs will automatically add a default value of the html_baseurl_ setting matching your canonical domain.

If you need a custom ``html_baseurl`` in your ``conf.py``,
you need to ensure that the value is correct.
benjaoming marked this conversation as resolved.
Show resolved Hide resolved
This can be complex,
given the possibility for PR builds (which are published on a separate domain),
benjaoming marked this conversation as resolved.
Show resolved Hide resolved
special branches
or if you are using :term:`subproject` s or :ref:`translations <localization:Localization of Documentation>`.
We recommend leaving out ``html_baseurl`` from ``conf.py``, letting Read the Docs define it.
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

.. _html_baseurl: https://www.sphinx-doc.org/page/usage/configuration.html#confval-html_baseurl

MkDocs
~~~~~~

For :doc:`MkDocs </intro/getting-started-with-mkdocs>` we do not define your canonical domain automatically,
but you can use the site_url_ setting to set a similar value.
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

In your ``mkdocs.yml``, define the following:

.. code-block:: yaml

# Canonical URL, adjust as need with respect to your slug, language,
# default branch and if you use a custom domain.
site_url: https://<slug>.readthedocs.io/en/stable/

Note that this will define the same canonical URL for all your branches and versions.
According to MkDocs, defining site_url_ only affects the canonical URL of a website.
benjaoming marked this conversation as resolved.
Show resolved Hide resolved

.. note::

2 know issues are currently making it impossible to use `environment variables in MkDocs configuration`_.
benjaoming marked this conversation as resolved.
Show resolved Hide resolved
Once these issues are solved, it will be easier.

- Support for ``!ENV``: :rtd-issue:`8529`
- Add environment variable for canonical URL: :rtd-issue:`9781`

.. _site_url: https://www.mkdocs.org/user-guide/configuration/#site_url
.. _environment variables in MkDocs configuration: https://www.mkdocs.org/user-guide/configuration/#environment-variables

.. warning::

If you change your default version or canonical domain,
you'll need to re-build all your versions in order to update their
canonical URL to the new one.
Loading