Deployed your app to Fly.io and the root domain works fine, but www.yoursite.com throws an SSL handshake error? You're not alone. This Error 525 happens because Fly.io requires separate SSL certificates for each hostname—and most deployment guides completely skip this step.
Here's the fix, tested and verified on a production deployment.
The Problem
You've deployed to Fly.io, added your custom domain, and everything looks good. Then you try visiting www.yoursite.com and get:
Error 525: SSL handshake failedMeanwhile, yoursite.com (without www) works fine. What gives?
Why This Happens
Fly.io uses Let's Encrypt to provision SSL certificates, but here's the catch: adding a certificate for example.com does NOT automatically cover www.example.com.
They're treated as completely separate hostnames. You need to explicitly add a certificate for the www subdomain.
The Solution (5 Steps)
Step 1: Install Fly.io CLI
If you haven't already, install flyctl:
# Install flyctl
curl -L https://fly.io/install.sh | sh
# Add to PATH
export FLYCTL_INSTALL="$HOME/.fly"
export PATH="$FLYCTL_INSTALL/bin:$PATH"
# Make it permanent (add to ~/.bashrc or ~/.zshrc)
echo 'export FLYCTL_INSTALL="$HOME/.fly"' >> ~/.bashrc
echo 'export PATH="$FLYCTL_INSTALL/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Verify it works
flyctl versionStep 2: Check Your Current Certificates
First, see what certificates you already have:
flyctl certs list -a YOUR_APP_NAMEYou'll probably see something like:
Host Name Added Status
example.com 1 month ago Ready
api.example.com 1 month ago ReadyNotice what's missing? The www subdomain.
Step 3: Add the www Certificate (This Fixes It)
Here's the critical command that solves the problem:
flyctl certs add www.example.com -a YOUR_APP_NAMEFly.io will automatically provision a Let's Encrypt SSL certificate for your www subdomain. You'll see output like:
You are creating a certificate for www.example.com
We are using Let's Encrypt for this certificate.
Your certificate for www.example.com is being issued.
You can validate your ownership of www.example.com by:
1: Adding an AAAA record to your DNS service which reads:
AAAA @ 2a09:8280:1::X:XXXXDon't worry about the DNS validation—if your root domain is already working, the www subdomain will validate automatically.
Step 4: Verify the Certificate Is Ready
Wait 1-2 minutes, then check the certificate status:
flyctl certs show www.example.com -a YOUR_APP_NAMELook for "Status: Ready". If it says "Awaiting certificates", wait another minute and check again.
Once ready, your certificate list should show:
flyctl certs list -a YOUR_APP_NAMEHost Name Added Status
example.com 1 month ago Ready
www.example.com 13 seconds ago ReadyPerfect.
Step 5: Configure Cloudflare SSL/TLS Mode
This step is critical if you're using Cloudflare for DNS (which you should be).
- Log in to your Cloudflare dashboard
- Select your domain
- Go to SSL/TLS → Overview
- Set the encryption mode to "Full" (not "Flexible" or "Full (strict)")
Why "Full"?
- Flexible: Cloudflare uses HTTPS to your visitors, but HTTP to Fly.io (insecure, causes issues)
- Full: Cloudflare uses HTTPS to both visitors and Fly.io (correct)
- Full (strict): Requires a trusted certificate authority, but Fly.io manages its own certs (causes errors)
Configure Your DNS Records (Cloudflare)
Make sure your DNS records are set up correctly:
Root Domain (example.com):
- Type:
AorAAAA - Name:
@(or leave blank) - Content: Your Fly.io IP address (from
flyctl ips list) - Proxy status: Proxied (orange cloud enabled)
www Subdomain (www.example.com):
- Type:
CNAME - Name:
www - Target:
example.com(points to root domain) - Proxy status: Proxied (orange cloud enabled)
The orange cloud (Proxied) is important—it routes traffic through Cloudflare's CDN and enables SSL.
Test Everything
Verify both domains work:
# Test root domain
curl -I https://example.com
# Test www subdomain
curl -I https://www.example.comBoth should return HTTP/2 200 (or HTTP/1.1 200). If you get errors, see the troubleshooting section below.
Common Errors and Fixes
Error 525: SSL Handshake Failed
Symptoms: www subdomain throws Error 525, root domain works fine
Causes:
- Missing www certificate on Fly.io
- Cloudflare SSL/TLS mode is set to "Flexible" or "Full (strict)"
Fix:
# Add the www certificate
flyctl certs add www.example.com -a YOUR_APP_NAME
# Wait 2 minutes for certificate issuance
sleep 120
# Verify it's ready
flyctl certs show www.example.com -a YOUR_APP_NAMEAlso verify Cloudflare SSL/TLS mode is set to "Full".
www Subdomain Returns Connection Timeout
Symptoms: www subdomain doesn't load at all, no error page
Causes:
- DNS CNAME record missing or incorrect
- DNS not proxied through Cloudflare
- DNS propagation incomplete
Fix:
- Check your Cloudflare DNS settings for the www CNAME record
- Ensure the orange cloud (Proxied) is enabled
- Wait 5-15 minutes for DNS propagation
- Clear your browser cache or test in incognito mode
Certificate Shows "Awaiting Certificates" for More Than 5 Minutes
Symptoms: flyctl certs show keeps saying "Awaiting certificates"
Causes:
- DNS records not pointing to Fly.io correctly
- Cloudflare proxy interfering with certificate validation
Fix:
# Verify your DNS records are correct
dig www.example.com
# Check if DNS is resolving to Fly.io
nslookup www.example.com
# If stuck, delete and re-add the certificate
flyctl certs delete www.example.com -a YOUR_APP_NAME
flyctl certs add www.example.com -a YOUR_APP_NAMERoot Domain Works, www Redirects to Root (But You Want Both)
Symptoms: Visiting www.example.com redirects to example.com
Causes: This might be intentional behavior in your app code
Fix: If you want both to work independently, ensure:
- Both certificates exist in Fly.io
- Your app doesn't have redirect logic forcing www → non-www
- Both DNS records are configured correctly
Why Separate Certificates Matter
In traditional shared hosting, a wildcard SSL certificate (*.example.com) covers all subdomains. But Fly.io provisions certificates individually through Let's Encrypt.
This gives you more control but requires explicit setup for each subdomain:
example.com→ needs its own certificatewww.example.com→ needs its own certificateapi.example.com→ needs its own certificateblog.example.com→ needs its own certificate
You get the idea.
Best Practices for Fly.io + Cloudflare
- Add certificates for all subdomains you plan to use before going live
- Use Cloudflare's "Full" SSL/TLS mode for Fly.io deployments
- Enable Cloudflare proxy (orange cloud) for CDN and DDoS protection
- Test both www and non-www versions before announcing your site
- Set up redirects in your app if you want to force one version over the other
Useful Commands for Troubleshooting
# List all certificates for your app
flyctl certs list -a YOUR_APP_NAME
# View detailed info for a specific certificate
flyctl certs show www.example.com -a YOUR_APP_NAME
# Delete a certificate (if you need to start over)
flyctl certs delete www.example.com -a YOUR_APP_NAME
# Check your app's IP addresses
flyctl ips list -a YOUR_APP_NAME
# Check DNS resolution
dig example.com
dig www.example.com
# Test SSL connection with verbose output
curl -vI https://www.example.com
# Check app status
flyctl status -a YOUR_APP_NAME
# View app logs (useful for debugging)
flyctl logs -a YOUR_APP_NAMEComplete Setup Checklist
Use this checklist to verify everything is configured correctly:
Fly.io Certificates:
- Root domain certificate exists and shows "Ready"
- www subdomain certificate exists and shows "Ready"
- Any other subdomains have certificates added
Cloudflare DNS:
- A or AAAA record for root domain pointing to Fly.io IP
- CNAME record for www subdomain pointing to root domain
- All records have orange cloud (Proxied) enabled
Cloudflare SSL/TLS:
- Encryption mode set to "Full" (not Flexible or Full strict)
- Edge Certificates shows valid SSL
Testing:
-
https://example.comreturns 200 OK -
https://www.example.comreturns 200 OK - No SSL warnings in browser
- Both domains show secure lock icon
Real-World Example
Here's what the complete setup looks like for ftashark.com:
# Check certificates
$ flyctl certs list -a ftashark
Host Name Added Status
ftashark.com 1 month ago Ready
www.ftashark.com 13 seconds ago Ready
api.ftashark.com 1 month ago ReadyCloudflare DNS:
Type Name Content Proxy
A @ 66.241.124.123 Proxied
CNAME www ftashark.com Proxied
CNAME api ftashark.com ProxiedCloudflare SSL/TLS: Full mode
Result: All three URLs work correctly with valid SSL.
Why Most Guides Skip This
Most Fly.io deployment tutorials focus on getting your app running and adding a single custom domain. They assume you'll only use example.com or www.example.com—not both.
But in reality, users type both versions. Search engines index both. And you don't want half your traffic hitting SSL errors.
Adding the www certificate takes 30 seconds but saves hours of debugging later.
Alternative: Redirect www to Non-www (Or Vice Versa)
If you don't want to maintain both versions, you can set up a redirect in your app.
Option 1: Redirect www → non-www
Most frameworks have middleware for this. For example, in Express.js:
app.use((req, res, next) => {
if (req.hostname.startsWith('www.')) {
return res.redirect(301, `https://${req.hostname.slice(4)}${req.url}`)
}
next()
})Option 2: Redirect non-www → www
app.use((req, res, next) => {
if (!req.hostname.startsWith('www.')) {
return res.redirect(301, `https://www.${req.hostname}${req.url}`)
}
next()
})But even if you redirect, you still need both certificates or the redirect won't work (users will hit the SSL error before your app can redirect them).
Conclusion
The Fly.io www subdomain SSL issue is one of those "gotchas" that trips up even experienced developers. The fix is simple once you know it:
- Add a separate certificate for www:
flyctl certs add www.example.com -a YOUR_APP_NAME - Set Cloudflare SSL/TLS to "Full" mode
- Wait 1-2 minutes for the certificate to be ready
- Test both domains
That's it. No complex configuration, no server restarts, no editing config files. Just one command that most deployment guides forget to mention.
Now your users can access your site with or without www, and both will work correctly.
Related guides:
- Complete Guide: Deploying Lovable Projects to Cloudflare
- Deploy Claude Code & Codex Apps to Cloudflare
- Cloudflare Workers Deployment Guide
Resources:
Fred
AUTHORFull-stack developer with 10+ years building production applications. I've been deploying to Cloudflare's edge network since Workers launched in 2017.

