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 setting DNS records through your DNS provider and adding a TLS certificate on Fly.io for your custom domain.
Add a custom domain for your app
The order of the tasks to add a custom domain depends on when you want start directing traffic to your app:
When you want to start accepting traffic immediately on your custom domain, follow the sections below in order.
When you want to get certificates before your app starts accepting traffic, for example if you’re cutting over from another platform to Fly.io, you should create the certificates and configure the ACME challenge first, and then add the DNS records when you’re ready to send traffic to your app.
Add DNS records
Direct traffic to your site by mapping your custom domain name to your Fly App through your DNS provider. Create either a CNAME (Option I) or A/AAAA (Option II) record.
Option I: Set a CNAME record
In most cases, you can use a CNAME record, which points your custom domain at your .fly.dev
host. If your DNS provider doesn’t allow Apex, or root, hostnames to have CNAME records, then you can use Option II: Set the A/AAAA records.
Set the CNAME record with your DNS provider. For example, if you have a domain called example.com
and an app called exemplum
, then you can create a CNAME record for example.com
‘s DNS that would look like this:
Record Type | Host / Hostname / Name | Value / Content / Alias of |
---|---|---|
CNAME | @ | exemplum.fly.dev |
Different DNS providers might use different terms for the parts of the record and we’ve listed a few of them in the table above.
For our example, with this CNAME record added, accessing example.com
will tell the DNS system to look up exemplum.fly.dev
and return its results.
Option II: Set the A/AAAA records
A and AAAA records use the app’s IP addresses rather than the domain name. This option might be slightly faster than the CNAME record lookup.
Get your app’s IP addresses:
fly ips list
VERSION IP TYPE REGION CREATED AT
v6 2a09:8280:1::39:b14f:0 public (dedicated) global Jun 18 2024 17:09
v4 66.241.124.193 public (shared) Jan 1 0001 00:00
Set the A and AAAA records with your DNS provider. Add an A record for your domain that points to the IPv4 address, and add an AAAA record for your domain that points to the IPv6 address.
Once the A and AAAA records are added and propagated through the DNS system, you should be able to connect over unencrypted HTTP to the domain name. Continuing the preceding example, that’s the domain name: http://example.com
.
Important: Hostname validation will fail without an IPv6 address—and we won’t attempt to issue or renew a certificate—unless you’re using a CNAME _acme-challenge
for domain verification. However, we still recommend having both an IPv4 and an IPv6 address allocated if your app is serving traffic. If your app doesn’t have an IPv6 address, allocate one with flyctl ips allocate-v6
.
Get certified
You’ll need a TLS certificate for your domain if your app:
- Should accept HTTPS connections, or
- Uses a shared IPv4 Anycast address. Fly Proxy uses the certificate to associate the custom domain name with your app for routing purposes.
You can add certificates with flyctl or in your app dashboard under Certificates.
Create a certificate for your custom domain with the fly certs add
command. For example:
fly certs add example.com
Hostname = example.com
Configured = true
Issued =
Certificate Authority = lets_encrypt
DNS Provider = enom
DNS Validation Instructions =
DNS Validation Hostname =
DNS Validation Target = example.com.5xzw.flydns.net
Source = fly
Created At = 0001-01-01T00:00:00Z
Status =
If you need a wildcard domain, put quotes around the hostname to avoid shell expansion:
fly certs add "*.example.com"
Running fly certs add
starts the process of getting a certificate. Configured
should be true and Status
will change to Ready
when the certificates are available. You can run fly certs show <hostname>
to check the status.
(Optional) Validate with an ACME DNS-01 challenge
Validate your domain with an ACME DNS-01 challenge if one or more of the following scenarios apply:
- You want to issue a certificate before creating the CNAME or A/AAAA records to point to your app.
- You’re using a proxy like Cloudflare, which prevents our systems from verifying the source IP addresses.
- You want to ensure no HTTPS connection errors occur during the short time (usually minutes) it takes to generate the first-ever certificate for your site.
- You’re using a wildcard certificate.
Run the
fly certs show <hostname>
command. For example:fly certs show example.com
Hostname = example.com Configured = true Issued = ecdsa, rsa Certificate Authority = lets_encrypt DNS Provider = enom DNS Validation Instructions = CNAME _acme-challenge.example.com => example.com.5xzw.flydns.net. DNS Validation Hostname = _acme-challenge.example.com DNS Validation Target = example.com.5xzw.flydns.net Source = fly Created At = 1m24s ago Status = Ready
Reference the DNS Validation Instructions to create a
CNAME
DNS record for a subdomain,_acme-challenge
, of your domain (DNS Validation Hostname) and point it at the DNS Validation Target.
Once complete, and the updated DNS data has propagated, that domain will be queried to confirm you have control of it. Certificates will be generated and installed.
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 asfly certs show
.fly certs remove <hostname>
- Remove a certificate from an app for the given hostname.
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, you might be using their Universal SSL feature which inserts a TXT record of _acme_challenge.<YOUR_DOMAIN>
for your domain. This can interfere with our certificate validation/challenge and you should disable this feature.
You can then verify that the change has propagated and the TXT record is no longer present by running dig txt _acme-challenge.<YOUR_DOMAIN> +short
.
We’ve also noticed that Cloudflare’s “Flexible” SSL mode can cause redirect loops for applications hosted on Fly.io. Thus, we recommend setting your Cloudflare SSL mode to “Full” or “Full (Strict)”.