I have a bunch of small (toy?) apps hosted on Heroku. They are probably used by a few dozen people, at most. For these apps, I’d like the following setup:
Use a custom domain for the apps
Heroku provides domains of the form
appname.herokuapp.comfor all apps.
But, it also has the option to add one or more custom domains
I usually already have a domain under which I want to add a sub-domain, where these apps would run.
Use HTTPS for all connections
The domains or the sub-domains usually don’t already already have an SSL certificate. With lets-encrypt, I guess this can change in future.
Heroku provides SSL certificates for the default domain (
appname.herokuapp.com) for free.
They also have an option to buy SSL certificates for custom domains, but they are expensive!
I’m going to use Cloudflare’s free SSL service instead. I’d like to have SSL for the full domain, and not just the app’s subdomain.
Redirect all the requests to the Heroku domain to the custom domain
Nobody should really be using the
appname.herokuapp.comdomain, in case I’d like to move away from it.
A few lines of app (Flask) code can do this for us.
Setup DNS to use Cloudflare
Since we plan to use Cloudflare for the SSL certificates, we need to change DNS settings at our domain registrar to use Cloudflare. We first need to create a Cloudflare account, and let Cloudflare do a DNS scan to add all the existing domain settings automatically. Next we point to the Cloudflare DNS servers on our domain registrar.
Enable HTTPS always in Cloudflare
Using page rules in Cloudflare, add a rule for the whole domain to “Always use
HTTPS”. For example, use the url
http://*example.com/* and select the
Always use HTTPS option.
Select the SSL option to use
Cloudflare provides different options for the SSL setting which changes whether or not traffic is encrypted between Cloudflare and the Heroku app.
Full (strict) to enable encryption between Cloudflare and Heroku.
If you are not so concerned about encryption between Cloudflare and Heroku, you
could select the
Flexible option too.
Add a custom domain in Heroku
Add a custom domain –
app.example.com – in Heroku’s settings.
Heroku provides a DNS Target that needs to be used as the destination for a
CNAME setting in the DNS provider (Cloudflare). The DNS Target looks something
If you chose
Full (strict) SSL option, this DNS target cannot be used and can
Add a CNAME for the subdomain
Add a new CNAME setting in Cloudflare for
app.example.com and use the
app’s Heroku domain name (
appname.herokuapp.com) as the destination value/IP
It is important to use the
appname.herokuapp.com value if the SSL settings you
chose above was
Full (strict). Using the DNS Target provided by Heroku instead
foo-bar-123abcdef.herokudns.com) would give an SSL Handshake error since the
SSL certificate provided by Heroku only works for the
domain, and not for
If you chose
Flexible, though, you can use the DNS Target provided by Heroku
Also, ensure that the Cloudflare Proxy Toggle is toggled on – the cloud icon is orange, not grey!
Redirect all requests
We redirect all the requests coming to the old domain to the new one.
@app.before_request def redirect_heroku(): """Redirect herokuapp requests.""" urlparts = urlparse(request.url) if urlparts.netloc == "appname.herokuapp.com": urlparts_list = list(urlparts) urlparts_list = "app.example.com" return redirect(urlunparse(urlparts_list), code=301)
Enforce HTTPS on Heroku
If you don’t care about a custom domain and just wish to enforce SSL for the
Heroku domain (
Flask-SSLify is the way to go. The
app can be hosted on Heroku and we can use the certs provided for free.
from flask_sslify import SSLify app = Flask(__name__) if "DYNO" in os.environ: # Always use SSL if the app is running on Heroku (not locally) sslify = SSLify(app)
I’ve done this setup, or some parts of it quite a few times, but each time I seem to need to look up the documentation. Every time, it seems to take longer than it needs to! Hopefully, this post will make it quick and reproducible.