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

{% admonition "Warning" %}

Codeberg Pages has recently migrated from the legacy v2 codebase to the newer [git-pages](https://git-pages.org/) codebase.

Take note of some minor [changes and deprecations](/codeberg-pages/migrating-from-pages-v2/#breaking-changes-and-deprecations).

If you have not yet [migrated your own site to the new server,](/codeberg-pages/migrating-from-pages-v2/) we encourage you to do so.
Pages Server v2 has already been disabled for new users due to abuse, however it is still working for users and organizations that already existed prior to the service being discontinued. We apologize for any inconvenience this has caused.

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 (staging) in your CAA record](https://letsencrypt.org/docs/caa/).
This means you need to add two extra CAA records.
The first record has a value of `letsencrypt.org;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/292520050;validationmethods=tls-alpn-01,http-01`.
The second record has a value of `letsencrypt.org;accounturi=https://acme-staging-v02.api.letsencrypt.org/acme/acct/272029763;validationmethods=tls-alpn-01,http-01`.

{% endadmonition %}

{% admonition "info" "Notice" %}

Throughout this document, the domain `example.org` is used as a placeholder for your own domain. Please ensure you replace any literal instances of `example.org` with the domain that you've purchased to ensure the proper setup procedure.

We provide context-appropriate examples for both the apex domain, and the `www` subdomain commonly used for websites. If you wish to use a different subdomain, replace the `www` in the following examples with the hostname of your desired subdomain. If you wish to use the apex domain (that is, the bare domain without any `www.` in front), we recommend additionally setting up a redirect on the `www` subdomain (or vice versa) to ensure compatibility with all browsers and devices.

{% endadmonition %}

{% admonition "Warning" %}

When setting up DNS records with many providers, 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.org`, entering `www` will mean the record refers to `www.example.org`.

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

{% endadmonition %}

### Step 1: CNAME, ALIAS, or A/AAAA 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>www.example.org</td>
   <td>CNAME</td>
   <td>codeberg.page.</td>
  </tr>
 </tbody>
</table>

{% admonition "info" "Notice" %}

DNSSEC has now been enabled for `codeberg.page`, try using a CNAME record if your zone is signed! You can verify that your DNSSEC setup works properly using [this tool](https://dnssec-analyzer.verisignlabs.com).

{% endadmonition %}

{% admonition "Warning" %}

With a CNAME record, everything on this subdomain is delegated to `codeberg.page`, which means you cannot setup other types of DNS records for other services on the same subdomain.

If you need to setup other records for other services, such as MX records for email, on the same subdomain, you must use one of the remaining options.

{% endadmonition %}

If the domain you wish to use is the apex of the zone or has other existing DNS records, you will not be able to use a CNAME record.
In this case, some DNS providers support an ALIAS record, which will work instead. Some DNS providers (such as Cloudflare) only allow setting "flattened" CNAME records at the apex, which works the same way as an ALIAS record.

<table class="table">
 <thead>
  <th>Domain</th>
  <th>Type</th>
  <th>Data</th>
 </thead>
 <tbody>
  <tr>
   <td>example.org</td>
   <td>ALIAS</td>
   <td>codeberg.page</td>
  </tr>
  <tr>
   <td>www.example.org</td>
   <td>ALIAS</td>
   <td>codeberg.page</td>
  </tr>
 </tbody>
</table>

{% admonition "Warning" %}

This type of record is not supported in conjunction with DNSSEC signed zones, which may cause unexpected behavior with your domain if your domain's zone is signed and a client is using a DNSSEC validating resolver.

If you have DNSSEC enabled, you should use A/AAAA records for now. You can verify that your DNSSEC setup works properly using [this tool](https://dnssec-analyzer.verisignlabs.com).

{% endadmonition %}

If you cannot use a CNAME nor an ALIAS record,
you will need to set up the A and AAAA records to point to Codeberg’s IP addresses directly.

It is possible these IP addresses will change in future,
so keep an eye on Codeberg updates to check.

<table class="table">
 <thead>
  <th>Domain</th>
  <th>Type</th>
  <th>Data</th>
 </thead>
 <tbody>
  <tr>
   <td>example.org</td>
   <td>A</td>
   <td>217.197.84.141</td>
  </tr>
  <tr>
   <td>example.org</td>
   <td>AAAA</td>
   <td>2a0a:4580:103f:c0de::2</td>
  </tr>
 </tbody>
</table>

### Step 2: Configure git-pages authorization

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

When someone tries to deploy a website to your domain,
Codeberg Pages needs to know which repository is responsible for the content,
and that the content actually comes from that repository.

When the webhook or Forgejo Action are triggered,
the server receives a token letting it know that the repository’s policies allowed the deploy.
The DNS records in turn ensure that the domain owner authorizes that repository to be deployed to that domain.

{% endadmonition %}

{% admonition "info" "Notice" %}

Since the new git-pages server uses these DNS records as an authorization method, it is no longer necessary to have a `.domains` file in your repository. You may remove it if you are migrating your website from the old Pages Server v2.

If you were relying on the old server's multi-domain redirection implementation, it may still be used if you only deploy your site to one of your domains on git-pages. See [the last section of this document](/codeberg-pages/migrating-from-pages-v2/#deploying-to-versions-of-your-domain-both-with-and-without-www.) for detailed instructions on setting up similar redirects on git-pages.

{% endadmonition %}

**If you deploy from a webhook,**
set a TXT record on the `_git-pages-repository` subdomain of your domain with the HTTPS Git clone URL for your repository.

<table class="table">
 <thead>
  <th>Domain</th>
  <th>Type</th>
  <th>Data</th>
 </thead>
 <tbody>
  <tr>
   <td>_git-pages-repository.example.org</td>
   <td>TXT</td>
   <td>https://codeberg.org/username/repository.git</td>
  </tr>
  <tr>
   <td>_git-pages-repository.www.example.org</td>
   <td>TXT</td>
   <td>https://codeberg.org/username/repository.git</td>
  </tr>
 </tbody>
</table>

**If you deploy from Forgejo Actions,**
set a TXT record on the `_git-pages-forge-allowlist` subdomain of your domain with the HTTPS Git clone URL for your repository.

<table class="table">
 <thead>
  <th>Domain</th>
  <th>Type</th>
  <th>Data</th>
 </thead>
 <tbody>
  <tr>
   <td>_git-pages-forge-allowlist.example.org</td>
   <td>TXT</td>
   <td>https://codeberg.org/username/repository.git</td>
  </tr>
  <tr>
   <td>_git-pages-forge-allowlist.www.example.org</td>
   <td>TXT</td>
   <td>https://codeberg.org/username/repository.git</td>
  </tr>
 </tbody>
</table>

### Step 3: Set your webhook or Forgejo Actions deploy target

**If you deploy from a webhook,**
the webhook **Target URL** should be set to the domain you want to deploy your website to.
For technical reasons, the first deployment needs to go over HTTP and you need to specify the `http://` scheme.
After the first successful deployment you can change it to the `https://` scheme.

**If you deploy from Forgejo Actions,**
the `site` parameter to the git-pages action should be set to the URL of your custom domain, and the `server` parameter should be set to `codeberg.page`. The [Forgejo Actions guide](/codeberg-pages/forgejo-actions/) includes example workflows and more information.

{% admonition "info" "Notice" %}

If you wish to deploy your site to multiple (sub)domains, you must add a webhook or deployment action (and the respective DNS setup) for each of them.

If you are using a custom domain, you do not need a `codeberg.page` webhook unless you also want your site to be available from the respective `codeberg.page` URL.

{% endadmonition %}

### Deploying to versions of your domain both with and without `www.`

If you would like to serve your website at versions with and without a `www.` prefix,
you should choose one of them to be the ‘canonical’ URL,
add a [`_redirects` file](/codeberg-pages/advanced-usage/) to your site redirecting from one version to the other,
and deploy your website to both domains. (I.e. set up two separate webhooks, or use two separate deploy actions.)

For example, to redirect people from www.example.org to example.org,
use this `_redirects` file:

```
//www.example.org/* https://example.org/:splat 302!
```

For the redirect to work,
you should be sure that the code (here `302!`) includes an `!` at the end.
Otherwise, the redirect will only work on pages which are otherwise not found.
