---
eleventyNavigation:
  key: UsingCustomDomains
  title: Using custom domains
  parent: CodebergPages
  order: 10
---

{% admonition "Warning" %}

Codeberg Pages is currently migrating from the legacy v2 codebase to the newer [git-pages](https://git-pages.org/) codebase.

Currently, websites that use custom domains can only be deployed using the old method, but we are working to fix this.
Such websites will keep working indefinitely.
You will be able to seamlessly migrate to the new version of Pages once it is supported.
Take note of some minor [changes and deprecations](/codeberg-pages/migrating-from-pages-v2/#breaking-changes-and-deprecations).

Websites hosted under the `codeberg.page` domain can already use the new git-pages method.

The new documentation is work in progress, and we appreciate your feedback. Please let us know in case you find yourself confused.

{% endadmonition %}

Instead of using the `codeberg.page` domain, you can also purchase your own domain from a domain registrar of your choice
and configure it to serve content from Codeberg Pages.

{% admonition "warning" "Known pitfalls for failed certificate errors" %}

If you have a [CAA record](https://en.wikipedia.org/wiki/DNS_Certification_Authority_Authorization#Record) configured,
you must [explicitly allow Let's Encrypt in your CAA record](https://letsencrypt.org/docs/caa/).
The value of the CAA record would look like `letsencrypt.org;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/292520050;validationmethods=tls-alpn-01,http-01`.

If you're using [DNSSec](https://en.wikipedia.org/wiki/Domain_Name_System_Security_Extensions) on your custom domain, you might run into TLS certificate issues because `codeberg.page` doesn't use DNSSec at the moment.
In this case you must add `A` / `AAAA` / `TXT` records for all domains instead of `CNAME` records. You can use [this tool](https://dnssec-analyzer.verisignlabs.com) to verify your setup.

{% endadmonition %}

For custom domains, two things are required:

- a `.domains` file in the repository and branch where your files reside which you want to publish via Codeberg Pages.
  The file should contain a list of all external domains that shall be usable to access that repository,
  according to the following rules:
  - One domain per line, you can leave lines empty and comment out lines with `#`.
  - The first domain is the main domain, all other domains in the file will be redirected to the first one.

- a [DNS record](https://en.wikipedia.org/wiki/Domain_Name_System#Address_resolution_mechanism) pointing to one of the
  following targets, depending on where your static files reside:

<br />

{% admonition "question" "Why do I need all of these DNS records?" %}

To understand how the Pages server serves content, you need to know that a user browsing your custom domain just sends
"Hey, I want to see `yourdomain.com`" to the server.
But the server might not know that it is responsible for `yourdomain.com` and it cannot just serve all domains in the world.
So to find out if the server is responsible for `yourdomain.com` it will check the DNS entries of `yourdomain.com`.
If it returns something with `codeberg.page` (according to the domain schemes mentioned below) then it knows which
repository to check for the `.domains` file and your content.

{% endadmonition %}

## Setting the DNS record

There are several ways DNS records for your website can be setup in order to tell the Pages server your repository location.
For all of the options it is important that the Pages server knows where to look for the `.domains` file and your content.
Depending on from where you want to serve your files, there is a naming scheme for the domain:

<table class="table">
 <thead>
  <th>Domain Scheme</th>
  <th>Pages URL</th>
 </thead>
 <tbody>
  <tr>
   <td>
    <code>username.codeberg.page</code>
   </td>
   <td>
    https://username.codeberg.page<br />which will serve <code>codeberg.org/username/pages</code>
   </td>
  </tr>
  <tr>
   <td>
    <code>reponame.username.codeberg.page</code>
   </td>
   <td>
    https://username.codeberg.page/reponame<br />which will serve <code>codeberg.org/username/reponame</code>
   </td>
  </tr>
  <tr>
   <td>
    <code>branchname.reponame.username.codeberg.page</code>
   </td>
   <td>
    https://username.codeberg.page/reponame/@branchname/<br />
    which will serve <code>codeberg.org/username/reponame/src/branch/branchname</code>
   </td>
  </tr>
 </tbody>
<table>

{% admonition "warning" "Repository names with dots are not supported" %}

Repository names containing dots (`.`) are **not supported** for custom domains.
The Pages server uses dots as delimiters to parse the repository name, branch, and owner from DNS records.

For example, if your repository is named `my.project`, the TXT record `my.project.username.codeberg.page`
will be incorrectly parsed as:

- Branch: `my`
- Repository: `project`
- Owner: `username`

**Solution:** If you need to use a custom domain, rename your repository to use hyphens (`-`) or
underscores (`_`) instead of dots. For example, rename `my.project` to `my-project`.

{% endadmonition %}

_We assume for the following description, that you want to serve your website with and without www in front.
If you are on a subdomain already (like myproject.yourdomain.com), you can skip the `www.yourdomain.com` CNAME entry._

{% admonition "Warning" %}

When setting up DNS records with many registrars, any domain added to the `Domain` or `Host` option is automatically
appended onto the domain the records are being made for.

For example, if your domain is `example.com`, entering `www` will mean the record refers to `www.example.com`.

Therefore, in this guide, you may need to replace references to just your domain name (e.g. `example.com`) with `@` and
`anything.example.com` (i.e. any subdomain) with just `anything`.

{% endadmonition %}

### Option 1: CNAME record

The easiest and recommended way is to just setup a CNAME record for your domain, pointing to the mentioned above locations.
In the end, it should look like this:

<table class="table">
 <thead>
  <th>Domain</th>
  <th>Type</th>
  <th>Data</th>
 </thead>
 <tbody>
  <tr>
   <td>yourdomain.com</td>
   <td>CNAME</td>
   <td>reponame.username.codeberg.page</td>
  </tr>
  <tr>
   <td>www.yourdomain.com</td>
   <td>CNAME</td>
   <td>reponame.username.codeberg.page</td>
  </tr>
 </tbody>
</table>

<br />

{% admonition "Warning" %}

With a CNAME record everything on this domain is delegated to `codeberg.page`, which means you cannot setup your own
email address with this method.

If you need email or others services, you have to use one of the remaining options.

{% endadmonition %}

### Option 2: ALIAS record

If you cannot use a CNAME record to configure the target you can use this method, which needs two entries instead of one.

- First you need to specify which server should be serving your website. Similar to CNAME you can use an `ALIAS record`.
  The [difference](https://www.ecosia.org/search?q=cname%20vs%20alias%20record) between an CNAME record is,
  that the DNS server directly responds with the ip address and not the `codeberg.page` domain.
  Therefore you need to add a second entry, so that the pages server knows what to serve under this domain.
- Second, you need to setup a `TXT record` which contains the information from the `CNAME entry` which is your repository
  location as mentioned above. For example `[[branch.]repo.]user.codeberg.page`.

In the end it should look like this:

<table class="table">
 <thead>
  <th>Domain</th>
  <th>Type</th>
  <th>Data</th>
 </thead>
 <tbody>
  <tr>
   <td>yourdomain.com</td><td>ALIAS</td><td>codeberg.page</td>
  </tr>
  <tr>
   <td>yourdomain.com</td><td>TXT</td><td>reponame.username.codeberg.page</td>
  </tr>
  <tr>
   <td>www.yourdomain.com</td><td>CNAME</td><td>reponame.username.codeberg.page</td>
  </tr>
 </tbody>
</table>

### Option 3: A/AAAA record

If your service provider does not support `ALIAS records` you can also use `A records` and `AAAA records` instead.

- First you need to specify which server should be serving your website. You can do this by setting an `A record` for IPv4
  and an `AAAA record` for IPv6 which contains the ip address of the Codeberg Pages server. The servers' ip addresses are:
  - `A record` which contains the IPv4 value `217.197.84.141`
  - `AAAA record` which contains the IPv6 value `2a0a:4580:103f:c0de::2`
- Second, you need to setup a `TXT record` which contains the information of your repository
  location as mentioned above. For example `[[branch.]repo.]user.codeberg.page`.

In the end, it should look like this:

<table class="table">
 <thead>
  <th>Domain</th>
  <th>Type</th>
  <th>Data</th>
 </thead>
 <tbody>
  <tr>
   <td>yourdomain.com</td>
   <td>A</td>
   <td>217.197.84.141</td>
  </tr>
  <tr>
   <td>yourdomain.com</td>
   <td>AAAA</td>
   <td>2a0a:4580:103f:c0de::2</td>
  </tr>
  <tr>
   <td>yourdomain.com</td>
   <td>TXT</td>
   <td>reponame.username.codeberg.page</td>
  </tr>
 </tbody>
</table>

## Examples

The following sub-sections include a few examples of the different alternatives, assuming the following:

- we can add/modify DNS records in domain `example.com`.
- Our Codeberg username is `frida`, and we want to publish pages for:
  - `frida/pages`, with a _Personal_ static site inside branch `pages`;
  - `frida/colormix`, with a _Project_ site (again, inside branch `pages`).

All considerations regarding a _Personal_ site also apply to an _Organization_ site, so these two cases will be
addressed together.

### Personal (or Organization) site, subdomain

In this case, we want our _Personal_ pages available at the URL `https://myself.example.com`.

The `.domains` file contains the following:

```text
myself.example.com
```

For the DNS configuration:

- if the domain is not the apex of the zone and does not have other services such as email,
  you should always use a CNAME record:
  - name `myself.example.com`, type `CNAME`, data `frida.codeberg.page`

- otherwise, if ALIAS can be used, two DNS records will be needed:
  - name `myself.example.com`, type `ALIAS`, data `codeberg.page`
  - name `myself.example.com`, type `TXT`, data `frida.codeberg.page`

- otherwise, A/AAAA records must be used, together with one TXT record:
  - name `myself.example.com`, type `A`, data `217.197.84.141`
  - name `myself.example.com`, type `AAAA`, data `2a0a:4580:103f:c0de::2`
  - name `myself.example.com`, type `TXT`, data `frida.codeberg.page`

### Personal/Organization site, apex domain

In this case, we want our _Personal_/_Organization_ pages available at the URL `https://example.com`.
We also want the URL `https://www.example.com` to redirect to the apex domain.

The `.domains` file contains the following:

```text
example.com
www.example.com
```

_You may also put the `www` subdomain on the first line if you wish to use it as the canonical URL_
_and redirect the apex domain instead._

For the DNS configuration, CNAME records CANNOT be used for the apex domain, so:

- if ALIAS can be used, three DNS records will be needed:
  - name `example.com`, type `ALIAS`, data `codeberg.page`
  - name `example.com`, type `TXT`, data `frida.codeberg.page`
  - name `www.example.com`, type `CNAME`, data `frida.codeberg.page`

_Note that ALIAS records are not real DNS records and are typically incompatible with DNSSEC signed zones._

- otherwise, A/AAAA records must be used, together with a TXT record:
  - name `example.com`, type `A`, data `217.197.84.141`
  - name `example.com`, type `AAAA`, data `2a0a:4580:103f:c0de::2`
  - name `example.com`, type `TXT`, data `frida.codeberg.page`
  - name `www.example.com`, type `CNAME`, data `frida.codeberg.page`

### Project site, subdomain

In this case, we want our _Project_ pages available at the URL `https://colormix-app.example.com`.

The `.domains` file contains the following:

```text
colormix-app.example.com
```

For the DNS configuration:

- if the domain is not the apex of the zone and does not have other services such as email,
  you should always use a CNAME record:
  - name `colormix-app.example.com`, type `CNAME`, data `colormix.frida.codeberg.page`

- otherwise, if ALIAS can be used, two DNS records will be needed:
  - name `colormix-app.example.com`, type `ALIAS`, data `codeberg.page`
  - name `colormix-app.example.com`, type `TXT`, data `colormix.frida.codeberg.page`

- otherwise, A/AAAA records must be used, together with one TXT record:
  - name `colormix-app.example.com`, type `A`, data `217.197.84.141`
  - name `colormix-app.example.com`, type `AAAA`, data `2a0a:4580:103f:c0de::2`
  - name `colormix-app.example.com`, type `TXT`, data `colormix.frida.codeberg.page`

### Project site, apex domain

In this case, we want our _Project_ pages available at the URL `https://example.com`.

{% admonition "info" "Note" %}

This would be incompatible with using the apex `example.com` for other purposes, e.g. for the _Personal_/_Organization_
example discussed before.

{% endadmonition %}

The `.domains` file contains the following:

```text
example.com
www.example.com
```

_You may also put the `www` subdomain on the first line if you wish to use it as the canonical URL_
_and redirect the apex domain instead._

For the DNS configuration, CNAME records CANNOT be used for the apex domain, so:

- if ALIAS can be used, three DNS records will be needed:
  - name `example.com`, type `ALIAS`, data `codeberg.page`
  - name `example.com`, type `TXT`, data `colormix.frida.codeberg.page`
  - name `www.example.com`, type `CNAME`, data `colormix.frida.codeberg.page`

_Note that ALIAS records are not real DNS records and are typically incompatible with DNSSEC signed zones._

- otherwise, A/AAAA records must be used, together with one TXT record:
  - name `example.com`, type `A`, data `217.197.84.141`
  - name `example.com`, type `AAAA`, data `2a0a:4580:103f:c0de::2`
  - name `example.com`, type `TXT`, data `colormix.frida.codeberg.page`
  - name `www.example.com`, type `CNAME`, data `colormix.frida.codeberg.page`
