---
title: Custom domains
layout: docs
nav: firecracker
redirect_from:
- /docs/apps/custom-domain/
- /docs/app-guides/custom-domains-with-fly/
- /docs/networking/custom-domains-with-fly/
---
<figure>
<img src="/static/images/docs-ui.webp" alt="">
</figure>
When you create a Fly App, it is automatically given a `fly.dev` subdomain, based on the app's name. This is great for testing, but when you want to go to full production you'll want your application to appear on your own domain and have HTTPS set up for you as it is with your `.fly.dev` domain. You can do this by adding your domain to your Fly App, then configuring DNS records through your DNS provider.
## Add a custom domain for your app
To add a custom domain, first attach your domain to your Fly App to get DNS configuration instructions, then configure your DNS records with your DNS provider.
### Add your domain to your app
Attach your domain to your Fly App. This prepares your app to generate TLS certificates and handle traffic for your custom domain, and shows you the DNS configuration options for your setup.
You can add your domain with flyctl or in your app [dashboard](https://fly.io/dashboard/) under **Certificates**.
For example, using the CLI:
```cmd
fly certs add example.com
```
This command will show you the applicable DNS configuration options for your setup.
If you are adding a wildcard domain with the CLI, put quotes around the hostname to avoid shell expansion:
```cmd
fly certs add "*.example.com"
```
Use `fly certs check <hostname>` to check the certificate status and validation progress, or `fly certs setup <hostname>` to view all setup options.
### Configure DNS records
Now that you've added your domain to your app, configure DNS records with your DNS provider to direct traffic to your Fly App. The setup instructions in the dashboard, or from `fly certs add`, show the recommended DNS configuration for your situation.
Choose the DNS setup that matches your needs:
<div class="important">
**Important:** To issue or renew a certificate, Fly.io needs to verify your domain through at least one of: an IPv6 address (AAAA record) pointing to your app, a [CNAME `_acme-challenge`](#dns-challenge), or a [`_fly-ownership` TXT record](#domain-ownership-verification).
</div>
#### A and AAAA records (recommended)
Use A and AAAA records for most direct connections to your app. These records point your domain directly to your app's IP addresses.
The A and AAAA records you need to set will be shown in your dashboard, and in the output from `fly certs add`. If your app doesn't have IPv4 and IPv6 addresses, allocate them with `fly ips allocate`.
#### CNAME records
CNAME records work well for subdomains (like `www.example.com` or `app.example.com`). A CNAME points your custom domain at a unique `.fly.dev` hostname for your app.
CNAME records are also a good option if you have many IP addresses assigned to your app, or expect to change them in the future.
Set the CNAME record with your DNS provider. Each app has a unique CNAME target that will be shown in the dashboard for your certificate, or in the output from `fly certs setup`.
Setting CNAME records for the apex domain can be problematic, and should be avoided unless your DNS provider supports CNAME flattening. Some providers use a special name for these records, such as ANAME or ALIAS, and some will flatten a CNAME at the apex automatically. In general, we recommend setting A/AAAA records on the apex domain.
#### DNS Challenge
Use the DNS-01 challenge when you need a wildcard certificate, or when you
want to generate the certificate before directing traffic to your app.
This will require setting an `_acme-challenge` CNAME record on your domain. The required record will be shown in your dashboard, or in the output from `fly certs setup`.
#### Domain ownership verification
Use a `_fly-ownership` TXT record to verify domain ownership when other validation methods aren't available for your setup. This is useful when:
- Your domain is behind a CDN or proxy that prevents direct validation
- You're importing a [custom certificate](#use-your-own-certificate)
- You don't want to allocate or use IPv6 addresses
The required record will be shown in your dashboard, or in the output from `fly certs setup`. You can include multiple values in a single TXT record by separating them with semicolons.
### Certificate validation
After you have configured your DNS, Fly.io automatically validates your domain ownership and issues certificates. This happens through one of these methods:
- **TLS-ALPN challenge**: Validates through a TLS handshake with Fly Proxy. This is the preferred method and works automatically for direct connections.
- **HTTP-01 challenge**: Validates by requesting a specific file from your domain. Used automatically when TLS-ALPN isn't available.
- **DNS-01 challenge**: You manually add a DNS record to validate domain ownership. Required for wildcard certificates, or to generate certificates before directing traffic to your app.
## Use your own certificate
In addition to the automatic Let's Encrypt certificates that Fly.io manages for you, you can upload your own TLS certificate and private key. Upload your certificate and private key in PEM format using the CLI:
```cmd
fly certs import example.com --fullchain fullchain.pem --private-key private-key.pem
```
You can also import certificates from your app dashboard under **Certificates**.
After uploading a custom certificate, it may show a status of `pending_ownership` until domain ownership is verified.
Ownership is verified by an IPv6 DNS record pointing at your app, or by the `_fly-ownership` TXT record.
Custom and Fly-managed (Let's Encrypt) certificates can coexist for the same hostname. When both are present, your custom certificate is served as the primary certificate, and the Fly-managed certificate acts as an automatic fallback.
## Other `fly cert` commands
* `fly certs list` - List the certificates associated with an app.
* `fly certs check <hostname>` - Trigger a check on the domain validation and DNS configuration for the given hostname and return results in the same format as `fly certs show`.
* `fly certs setup <hostname>` - Shows setup instructions for configuring DNS records for an existing certificate.
* `fly certs remove <hostname>` - Remove a certificate from an app for the given hostname. Use `--custom` to remove only a custom certificate, or `--acme` to stop ACME issuance only.
## Teaching your app about custom domains
Your application code needs to know how to accept custom domains and adjust the responses accordingly. If you're hosting content on behalf of your users, this typically means mapping the incoming hostname to a particular ID in your application database.
When users make requests, their browser sends a `Host` header you can use to alter the behavior of your application. When you run your app server on Fly.io directly, just get the contents of the `Host` header to identify a request.
If you're running your application on another provider, you will need to create a proxy application, like nginx to route traffic through Fly.io. Your application can then use the `X-Forwarded-Host` header to determine how to handle requests.
## Supported top-level domains
We support the top-level domains on the [IANA list](https://data.iana.org/TLD/tlds-alpha-by-domain.txt+external). Note that we only periodically update top-level domain support and there might be a delay before we add support for new top-level domains.
## Troubleshoot certificate creation
### Certificate creation or validation seems to hang, stall, or fail
*Let's Encrypt™* is a free, automated, and open certificate authority that Fly.io uses to issue TLS certificates for custom domains. However, Let's Encrypt imposes certain rate limits to ensure fair usage. If you encounter issues when creating or validating a certificate for a custom domain on Fly.io, it's possible that you've hit these rate limits.
The following [rate limits](https://letsencrypt.org/docs/rate-limits/) from Let's Encrypt apply:
* Certificates per Registered Domain: 50 per week
* Duplicate Certificate limit: 5 per week
* Failed Validation limit: 5 failures per hostname, per hour
Note that certificate renewals don’t count against your Certificates per Registered Domain limit.
If you encounter issues when adding or validating a certificate for a custom domain on Fly.io, you can use the following methods to troubleshoot:
* Use [Let's Debug](https://letsdebug.net/): A diagnostic tool/website to help figure out why you might not be able to issue a certificate for Let's Encrypt. Using a set of tests, it can identify a variety of issues, including: problems with basic DNS setup, problems with nameservers, rate limiting, networking issues, CA policy issues, and common website misconfigurations.
* Wait and retry: If you've hit a rate limit, you'll need to wait until the rate limit window passes before you can successfully create or validate a certificate again. We don’t have a way to reset it.
The best way to avoid hitting rate limits is to use staging environments and domains for testing and development, and to carefully plan your certificate issuance to stay within the limits. Avoid failed validation by ensuring that your DNS records are correctly configured, with no conflicting records.
If you're building a platform on top of Fly.io, and you expect that your users will frequently delete and then recreate the same resources within a short window, consider implementing "soft delete" logic into your platform that retains the Fly.io resources for a period of time, negating the need to recreate certs frequently.
### I use Cloudflare, and there seems to be a problem issuing or validating my Fly.io TLS certificate
If you're using Cloudflare's proxying feature (orange cloud), verify domain ownership by adding a [`_fly-ownership` TXT record](#domain-ownership-verification). Once ownership is verified, Fly.io can issue certificates using the HTTP-01 challenge through Cloudflare's proxy.
For this to work:
1. **Verify domain ownership**: Add a `_fly-ownership` TXT record with the values shown in your certificate details. See [Domain ownership verification](#domain-ownership-verification).
2. **Set SSL mode**: Use "Full" or "Full (Strict)" SSL mode in Cloudflare. "Flexible" mode can cause redirect loops.
Depending on your Cloudflare configuration, HTTP-01 challenges may be blocked and generation may still fail.
In these cases, you can bypass ACME certificate generation entirely by importing a [Cloudflare Origin Certificate](/docs/networking/understanding-cloudflare/#using-a-cloudflare-origin-certificate) and verifying ownership with the same `_fly-ownership` TXT record.
## Related reading
- [Networking overview](/docs/networking/) Broader look at how Fly.io handles routing, DNS, IPs, and certificates.
- [Certificates API reference](/docs/machines/api/certificates-resource/) Use the Machines API to automate cert provisioning and domain verification.
- [TLS termination by Fly Proxy](/docs/security/tls-termination/) — How Fly.io handles HTTPS for your apps and manages TLS certificates automatically behind the scenes.
- [Understanding Cloudflare](/docs/networking/understanding-cloudflare/) What happens when you put Fly.io behind Cloudflare, and how to avoid common pitfalls.
Custom domains
When you create a Fly App, it is automatically given a fly.dev subdomain, based on the app’s name. This is great for testing, but when you want to go to full production you’ll want your application to appear on your own domain and have HTTPS set up for you as it is with your .fly.dev domain. You can do this by adding your domain to your Fly App, then configuring DNS records through your DNS provider.
Add a custom domain for your app
To add a custom domain, first attach your domain to your Fly App to get DNS configuration instructions, then configure your DNS records with your DNS provider.
Add your domain to your app
Attach your domain to your Fly App. This prepares your app to generate TLS certificates and handle traffic for your custom domain, and shows you the DNS configuration options for your setup.
You can add your domain with flyctl or in your app dashboard under Certificates.
For example, using the CLI:
fly certs add example.com
This command will show you the applicable DNS configuration options for your setup.
If you are adding a wildcard domain with the CLI, put quotes around the hostname to avoid shell expansion:
fly certs add "*.example.com"
Use fly certs check <hostname> to check the certificate status and validation progress, or fly certs setup <hostname> to view all setup options.
Configure DNS records
Now that you’ve added your domain to your app, configure DNS records with your DNS provider to direct traffic to your Fly App. The setup instructions in the dashboard, or from fly certs add, show the recommended DNS configuration for your situation.
Choose the DNS setup that matches your needs:
Important: To issue or renew a certificate, Fly.io needs to verify your domain through at least one of: an IPv6 address (AAAA record) pointing to your app, a CNAME _acme-challenge, or a _fly-ownership TXT record.
A and AAAA records (recommended)
Use A and AAAA records for most direct connections to your app. These records point your domain directly to your app’s IP addresses.
The A and AAAA records you need to set will be shown in your dashboard, and in the output from fly certs add. If your app doesn’t have IPv4 and IPv6 addresses, allocate them with fly ips allocate.
CNAME records
CNAME records work well for subdomains (like www.example.com or app.example.com). A CNAME points your custom domain at a unique .fly.dev hostname for your app.
CNAME records are also a good option if you have many IP addresses assigned to your app, or expect to change them in the future.
Set the CNAME record with your DNS provider. Each app has a unique CNAME target that will be shown in the dashboard for your certificate, or in the output from fly certs setup.
Setting CNAME records for the apex domain can be problematic, and should be avoided unless your DNS provider supports CNAME flattening. Some providers use a special name for these records, such as ANAME or ALIAS, and some will flatten a CNAME at the apex automatically. In general, we recommend setting A/AAAA records on the apex domain.
DNS Challenge
Use the DNS-01 challenge when you need a wildcard certificate, or when you
want to generate the certificate before directing traffic to your app.
This will require setting an _acme-challenge CNAME record on your domain. The required record will be shown in your dashboard, or in the output from fly certs setup.
Domain ownership verification
Use a _fly-ownership TXT record to verify domain ownership when other validation methods aren’t available for your setup. This is useful when:
Your domain is behind a CDN or proxy that prevents direct validation
The required record will be shown in your dashboard, or in the output from fly certs setup. You can include multiple values in a single TXT record by separating them with semicolons.
Certificate validation
After you have configured your DNS, Fly.io automatically validates your domain ownership and issues certificates. This happens through one of these methods:
TLS-ALPN challenge: Validates through a TLS handshake with Fly Proxy. This is the preferred method and works automatically for direct connections.
HTTP-01 challenge: Validates by requesting a specific file from your domain. Used automatically when TLS-ALPN isn’t available.
DNS-01 challenge: You manually add a DNS record to validate domain ownership. Required for wildcard certificates, or to generate certificates before directing traffic to your app.
Use your own certificate
In addition to the automatic Let’s Encrypt certificates that Fly.io manages for you, you can upload your own TLS certificate and private key. Upload your certificate and private key in PEM format using the CLI:
You can also import certificates from your app dashboard under Certificates.
After uploading a custom certificate, it may show a status of pending_ownership until domain ownership is verified.
Ownership is verified by an IPv6 DNS record pointing at your app, or by the _fly-ownership TXT record.
Custom and Fly-managed (Let’s Encrypt) certificates can coexist for the same hostname. When both are present, your custom certificate is served as the primary certificate, and the Fly-managed certificate acts as an automatic fallback.
Other fly cert commands
fly certs list - List the certificates associated with an app.
fly certs check <hostname> - Trigger a check on the domain validation and DNS configuration for the given hostname and return results in the same format as fly certs show.
fly certs setup <hostname> - Shows setup instructions for configuring DNS records for an existing certificate.
fly certs remove <hostname> - Remove a certificate from an app for the given hostname. Use --custom to remove only a custom certificate, or --acme to stop ACME issuance only.
Teaching your app about custom domains
Your application code needs to know how to accept custom domains and adjust the responses accordingly. If you’re hosting content on behalf of your users, this typically means mapping the incoming hostname to a particular ID in your application database.
When users make requests, their browser sends a Host header you can use to alter the behavior of your application. When you run your app server on Fly.io directly, just get the contents of the Host header to identify a request.
If you’re running your application on another provider, you will need to create a proxy application, like nginx to route traffic through Fly.io. Your application can then use the X-Forwarded-Host header to determine how to handle requests.
Supported top-level domains
We support the top-level domains on the IANA list. Note that we only periodically update top-level domain support and there might be a delay before we add support for new top-level domains.
Troubleshoot certificate creation
Certificate creation or validation seems to hang, stall, or fail
Let’s Encrypt™ is a free, automated, and open certificate authority that Fly.io uses to issue TLS certificates for custom domains. However, Let’s Encrypt imposes certain rate limits to ensure fair usage. If you encounter issues when creating or validating a certificate for a custom domain on Fly.io, it’s possible that you’ve hit these rate limits.
The following rate limits from Let’s Encrypt apply:
Certificates per Registered Domain: 50 per week
Duplicate Certificate limit: 5 per week
Failed Validation limit: 5 failures per hostname, per hour
Note that certificate renewals don’t count against your Certificates per Registered Domain limit.
If you encounter issues when adding or validating a certificate for a custom domain on Fly.io, you can use the following methods to troubleshoot:
Use Let’s Debug: A diagnostic tool/website to help figure out why you might not be able to issue a certificate for Let’s Encrypt. Using a set of tests, it can identify a variety of issues, including: problems with basic DNS setup, problems with nameservers, rate limiting, networking issues, CA policy issues, and common website misconfigurations.
Wait and retry: If you’ve hit a rate limit, you’ll need to wait until the rate limit window passes before you can successfully create or validate a certificate again. We don’t have a way to reset it.
The best way to avoid hitting rate limits is to use staging environments and domains for testing and development, and to carefully plan your certificate issuance to stay within the limits. Avoid failed validation by ensuring that your DNS records are correctly configured, with no conflicting records.
If you’re building a platform on top of Fly.io, and you expect that your users will frequently delete and then recreate the same resources within a short window, consider implementing “soft delete” logic into your platform that retains the Fly.io resources for a period of time, negating the need to recreate certs frequently.
I use Cloudflare, and there seems to be a problem issuing or validating my Fly.io TLS certificate
If you’re using Cloudflare’s proxying feature (orange cloud), verify domain ownership by adding a _fly-ownership TXT record. Once ownership is verified, Fly.io can issue certificates using the HTTP-01 challenge through Cloudflare’s proxy.
For this to work:
Verify domain ownership: Add a _fly-ownership TXT record with the values shown in your certificate details. See Domain ownership verification.
Set SSL mode: Use “Full” or “Full (Strict)” SSL mode in Cloudflare. “Flexible” mode can cause redirect loops.
Depending on your Cloudflare configuration, HTTP-01 challenges may be blocked and generation may still fail.
In these cases, you can bypass ACME certificate generation entirely by importing a Cloudflare Origin Certificate and verifying ownership with the same _fly-ownership TXT record.
Related reading
Networking overview Broader look at how Fly.io handles routing, DNS, IPs, and certificates.