CDN Custom Domains

Your own domain name, such as cdn.example.com, can point at a CDN site in Open Source Cloud. The CDN serves your content over HTTPS with a certificate that OSC arranges for you, or with a certificate that you upload yourself. You prove that you control the name by publishing a few DNS records at your DNS provider, and OSC checks them.

The one rule that matters most: order of the DNS records matters, and a move from an older setup causes a short outage unless you follow the cutover steps below. Read "Order of the DNS changes" before you touch any DNS.

Availability

CDN custom domains are available in beta on the Professional plan and above. The CDN runs on European points of presence, and during the beta there is no service level agreement (SLA). To check whether your workspace has the feature, call GET /mycdn/enabled and look at the byod flag in the answer.

For now a site can carry 5 custom domains and a workspace can carry 20 in total. These limits are interim and can change. Adding a domain beyond the limit is refused with domain_limit_reached.

Which path do I need?

Your situation What to do
New name, nothing mapped to it today Add the domain to the CDN site and follow "Order of the DNS changes".
Name already mapped through My Domains (instance or My App) Add it with migrateFrom: 'mydomains', then follow "Moving a name you already use".
Name already attached to a My Page Add it with migrateFrom: 'mypage', then follow "Moving a name you already use".
Wildcard name such as *.example.com Add it as a wildcard domain and follow "Wildcard domains".
Wildcard name already mapped through My Domains Add it with migrateFrom: 'mydomains', then follow "Moving a name you already use".
You want to serve your own certificate instead of the managed one See "Using your own certificate".
Name that maps to a bucket prefix on a MinIO instance It stays on My Domains. See "What cannot move to the CDN".
Name managed by Terraform See "Terraform users".

What you can put behind a custom domain

A custom domain is attached to a CDN site, and a CDN site has one of three origins: a My Page, an instance on the storage allowlist (MinIO), or a My App. The domain works the same way for all three. What differs is where an existing mapping comes from. A name that is already in My Domains (used by instances and My Apps) is migrated with migrateFrom: 'mydomains'. A name that is attached to a My Page is migrated with migrateFrom: 'mypage'; My Page domains never go through My Domains. Using the wrong source for the origin is refused with migration_mismatch.

The four DNS records

OSC shows you the exact records, with their values, for each domain. In total there are four.

  1. Ownership check for OSC. A TXT record at _osc-challenge.<your-name> with a value that looks like osc-challenge=<32 characters>. OSC reads it to confirm that you control the name, and only then does it set the name up.
  2. Ownership check for the CDN. A TXT record at the name itself, with a value that looks like _varnish-cdn-verify=<token>. Note that this record sits at the name, not under a prefix.
  3. Certificate record. A CNAME at _acme-challenge.<your-name> that points to the value OSC shows. It lets the certificate be issued and renewed without any action from you.
  4. Traffic record. A CNAME at the name itself that points to <siteId>.edge.<cdn zone>, for example k3m9x2qa.edge.cdn.osaas.io. OSC shows the exact target. For Liivo sites the target is the same osaas.io address.

A CNAME and a TXT record cannot exist at the same name. That is the reason for the order in the next section.

If you upload your own certificate, OSC does not need to issue one and the certificate CNAME is not listed for that domain. A wildcard domain publishes its records at slightly different names, described under "Wildcard domains".

Order of the DNS changes

For a new name that is not an apex:

  1. Publish the two TXT records (the OSC check and the CDN check) and the certificate CNAME.
  2. Wait until OSC shows the name as verified.
  3. Remove the TXT record at the name itself.
  4. Publish the traffic CNAME.

Publishing the certificate CNAME before you do anything else matters. If it is created just before OSC asks for the certificate, the first certificate can take 5 to 12 minutes. If it is already in DNS, issuance usually takes seconds.

To make a later change quick, lower the TTL of the traffic record to 60 seconds a day before a cutover, and raise it again afterwards.

Apex domains

An apex name (example.com as opposed to www.example.com) cannot hold a CNAME. OSC supports one apex mode, alias, which needs a DNS provider that offers ALIAS, ANAME or CNAME flattening at the apex, pointing to the same traffic target. For an apex the CDN TXT record can stay next to the other records.

Two other modes are not available. a_records (fixed IP addresses) is off, because the CDN vendor has not confirmed stable addresses, and asking for it is refused with apex_mode_not_available. Redirect mode is dropped and is refused with the same message. If your DNS provider cannot flatten an apex, use www.<your-domain> instead.

CAA records

If your domain has CAA records, they must allow letsencrypt.org, because that is the authority that issues the certificate. A CAA record that names only another authority blocks the first certificate and later renewals, and you will not be warned before it happens.

Wildcard domains

A wildcard domain such as *.example.com is added the same way as any other name, with *.example.com as the domain. It covers every name one level below the base name, for example shop.example.com and a1.example.com. It does not cover example.com itself and it does not cover names two levels down such as a.b.example.com. A wildcard uses a managed certificate by default, and you can upload a wildcard certificate instead.

The records for a wildcard sit at the base name, example.com, except for the traffic record:

  1. A TXT record at _osc-challenge.example.com with the value osc-challenge=<32 characters>.
  2. The CDN ownership TXT (_varnish-cdn-verify=<token>) at the base name example.com. The CDN also accepts it at the literal name *.example.com. Use the literal name if the base name already carries a CNAME, because a CNAME and a TXT record cannot exist at the same name. OSC shows and checks the record at the base name.
  3. A CNAME at _acme-challenge.example.com that points to the value OSC shows. It is not listed when you upload your own certificate.
  4. A CNAME at *.example.com that points to the site's edge address, as OSC shows it.

Whether the wildcard is routed to your site is checked on one name that OSC makes up under it each time, a random label such as osc-x7k2m9qa.example.com. The literal * name is never looked up, so a wildcard counts as routed when any made-up name under it reaches the CDN.

A name belongs to one workspace at a time. If another workspace holds a name that the wildcard would cover, such as www.example.com, or holds a wildcard that covers the name you ask for, the add is refused with domain_in_use. The same applies inside your own workspace: you cannot hold both www.example.com and *.example.com as CDN domains, and that is refused with domain_in_use as well. A wildcard together with the base name, example.com and *.example.com, is allowed, because the wildcard does not cover the base name.

Using your own certificate

By default OSC arranges a managed certificate for each domain. If you need a certificate from your own authority, you can send a PEM certificate and its private key when you add the domain, or later. The certificate is optional and the managed one stays the default.

The certificate must be PEM, with the full chain and your certificate first. The private key must match it, the certificate must be valid now (not expired and not yet valid), and it must cover the domain name. For a wildcard domain it must cover *.example.com. A pair that fails any of these checks is refused with invalid_certificate, and nothing is created. OSC does not check CAA records for an uploaded certificate, so the CAA rules below apply to managed certificates only.

The private key is stored only at the CDN vendor. OSC does not keep it in its own storage and does not log it. Each domain has one certificate.

An uploaded certificate is not renewed by OSC. To replace it, upload a new pair in the console (the "Upload certificate" action on an active domain), with the MCP tool update-my-cdn-domain-certificate, or with PUT /mycdn/<siteId>/domains/<name>/certificate. If the domain still uses a managed certificate, the upload is refused with certificate_mode_conflict unless you send switchToUploaded: true. The console asks you to confirm the switch and then repeats the upload with that flag. OSC emails you 21 and 7 days before an uploaded certificate expires and asks you to upload a new one. A domain whose uploaded certificate has expired is marked misconfigured.

If the CDN is not able to take the upload at that moment, the request is refused with certificate_upload_unavailable and can be repeated.

Moving a name you already use

OSC moves a name from My Domains or from a My Page without removing anything on its own. The old mapping stays until you remove it.

Because the CDN verification record has to sit at the name itself and your name already carries a CNAME, the migration uses one mode: an announced cutover window. The other mode, a zero-downtime path through a TXT at the registrable apex, is not offered, and asking for it is refused with migration_mode_not_available.

The steps are:

  1. Create the CDN site. It serves on its OSC address.
  2. Add the name with migrateFrom: 'mydomains' or migrateFrom: 'mypage'. The name must belong to your own workspace and map to the same origin as the site.
  3. Publish the OSC TXT and the certificate CNAME. Neither affects live traffic.
  4. A day ahead, lower the TTL to 60 seconds.
  5. In the cutover window, replace the CNAME at the name with the CDN TXT record, wait for the name to verify (about 10 to 20 seconds), and wait for the status that says the name is ready for cutover (the certificate is issued).
  6. Remove the TXT record and publish the traffic CNAME to the site's edge address.

Expect an outage of a few minutes, bounded by your TTL and DNS propagation. Before step 6 you can roll back by pointing the CNAME at ingress.osaas.io again.

OSC never removes the old mapping automatically. After the cutover, remove the old My Domains entry or the My Page domain yourself. OSC reminds you in the console and in the MCP tools, and by email once a week, at most three times. Until then the old mapping cannot renew its own certificate, which does no harm because no traffic reaches it.

Moving a wildcard from My Domains

A wildcard entry in My Domains moves with migrateFrom: 'mydomains' and the same announced cutover_window as any other name, and the console offers Move to CDN on wildcard rows too. The name must be the wildcard entry of your own workspace, mapped to the same origin as the site. A My Page domain is never a wildcard. The certificate of the old entry is not moved, the CDN gets a new one (managed, or the one you upload while adding).

Expect the outage of the cutover window, a few minutes bounded by your TTL. After the cutover, delete the old wildcard mapping from My Domains yourself (and the osc_domain resource if Terraform manages it). OSC does not do it. An exact name that a wildcard My Domains entry covers cannot be migrated on its own and is refused with migration_mismatch; migrate the wildcard entry instead.

Moving a name between sites

Moving a name from one CDN site to another is treated as a new migration. Each add gets a new CDN token, and the traffic target is different for each site. You publish the new CDN TXT, point the traffic CNAME at the new site's address, and wait for the new certificate. The name is down from the moment it is removed from the old site until the new token is published and the certificate is issued.

My App sites that use a custom domain in the legacy slot

If your My App already serves a customer domain in its main domain slot and has no OSC-managed name besides that, adding a CDN domain is refused with origin_not_routable. The CDN needs an OSC-managed name for the app to reach it. Add one distinct managed name to the app as a secondary, for example <tenantId>-<app>-cdn.apps.osaas.io, and retry. Do not use the app's own stable name for this.

What cannot move to the CDN

These cases are refused on purpose.

Refusal When it happens
origin_path_not_supported The existing mapping uses an originPath. This applies to instances and to My Apps and it is permanent, because the CDN has no way to add a path prefix to the origin.
origin_not_routable See the My App section above.
migration_mismatch The name does not exist, belongs to another workspace, or maps to a different origin than the site. Also an exact name that is covered by a wildcard My Domains entry, and a wildcard asked for with migrateFrom: 'mypage'.
domain_in_use The name is already held by a CDN site, a My Domains entry or a My Page, in your workspace or another. A wildcard and the names one level below it count as the same name, so www.example.com and *.example.com cannot both be CDN domains of one workspace.
invalid_certificate The uploaded certificate or key was refused: it cannot be parsed, the key does not match, the certificate is expired or not yet valid, or it does not cover the name.
certificate_mode_conflict You uploaded a certificate for a domain that uses a managed certificate, without switchToUploaded: true.
certificate_upload_unavailable The CDN could not take the certificate at that moment. Try again.
apex_mode_not_available You asked for the redirect or fixed-IP apex mode.
migration_mode_not_available You asked for the zero-downtime TXT-at-apex migration.

A MinIO bucket-prefix mapping (for example, a name that serves one bucket as a video store) stays on My Domains and cannot move to the CDN, for the same reason as origin_path_not_supported.

Terraform users

There is no Terraform resource for CDN domains yet. If a name is managed by osc_domain or by the custom_domain attribute of osc_my_page, remove the old mapping in the same change as the DNS cutover: delete the osc_domain resource, or clear custom_domain on the page. OSC will not touch your Terraform state, so a mapping that you leave in place will still be there when you apply again.

After the cutover, do not apply the old resource again. While the CDN domain exists, an apply that tries to map the name in My Domains or on the page is refused with an HTTP 409. If you later remove the CDN domain, the same workspace can map the name in My Domains again, and other workspaces cannot take it for 30 days.

If osc_my_page.custom_domain fails with HTTP 409 when you create a new page, the page itself has already been created and the apply is only partly done. Remove or fix whatever holds the name, then apply again.

Liivo My Pages

A My Page that should get a Liivo address can be created only through the REST API, with the header x-brand: liivo. Neither the MCP tool create-my-page nor the My Page form in the console sends that header, so a page created through either gets an OSC address.

Behaviour to know about

HSTS: the CDN adds none, your app may. Once a site carries a custom domain, OSC turns off the CDN's own strict transport header for every name on that site, including the OSC addresses of the site, and it stays off after the last custom domain is removed. If your app sends the header itself, the CDN passes it on unchanged to every name of the site, your custom domain included, whether it is an apex name or not. My Apps on OSC send max-age=15724800; includeSubDomains, so a custom domain in front of a My App carries that header. After a visit, browsers then use only HTTPS for that name and all of its subdomains for 182 days. That is shorter than the one year the browser preload list requires, so the name cannot be added to the preload list. A prod My Page host returned the same value on 2026-10-20. If your origin sends no such header, your custom name gets none either.

Your app sees the CDN's host, not yours. The origin receives only the host name it is configured with. It does not receive your custom name in a header. Apps that build absolute links from the Host header will produce links with the origin name. Cookies set without a Domain attribute belong to your custom name, while cookies that name the origin in Domain are dropped by the browser.

A suspended site fails with a TLS error. When a site is suspended, all of its names, custom ones included, stop being served. Visitors see a browser certificate error, not a page. When the site is resumed it serves again in about 15 seconds, with no DNS work.

Deleting a domain stops serving within a few seconds. Adding it again starts verification from the beginning with a new token.

Certificates are issued by Let's Encrypt and renew by themselves while the certificate CNAME stays in DNS. If it is removed, OSC emails you 21 and 7 days before the certificate expires. Certificates that you upload are not renewed by OSC, see "Using your own certificate".

The certificate end date of a domain is shown once the domain has passed its ownership check. While a domain is still waiting for that check, the certificate field is empty, also for an uploaded certificate (osaas-deploy-manager#2017).

Glossary

Apex: the bare domain, such as example.com, without a name in front of it.

CNAME: a DNS record that makes one name an alias of another.

TXT record: a DNS record that holds text. Services use it to confirm that you control a name.

CAA record: a DNS record that lists which certificate authorities may issue certificates for your name.

TTL: how long, in seconds, other computers may remember a DNS answer. A low TTL makes a change take effect sooner.

ALIAS / ANAME / CNAME flattening: a DNS provider feature that lets the bare domain behave like a CNAME.

HSTS: a header that tells browsers to use HTTPS only for a name for a long time.

Cutover: the moment traffic changes from the old setup to the CDN.