Kamal Rails Series Part 3: Enable HTTPS and SSL Certificate
This is Part 3 of my Kamal Rails Series. So far, we’ve deployed a Rails application and accessed the application using the HTTP protocol. However, in production, we rarely do this and always deploy our application using HTTPS recommended secure way with an SSL certificate. This article is to add HTTPS and SSL configuration to our already deployed Rails application using Kamal.
Pre-Requisites
- Already deployed Rails application using Kamal
- Can access the Rails application using
<SERVER_IP>/up
command.
This GET request should return a 200 OK response.
Bought a domain on any domain provider like Namecheap or GoDaddy
Step 1: Add traefik configuration to deploy.yml
- These are the things we need to add in our
config/deploy.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Name of your application. Used to uniquely configure containers.
service: rubypodcatcher
# Name of the container image.
image: joshio1/rubypodcatcher
# Deploy to these servers.
servers:
web:
hosts:
- <SERVER_IP>
labels:
traefik.http.routers.rubypodcatcher.rule: Host(`rubypodcatcher.com`)
traefik.http.routers.rubypodcatcher_secure.entrypoints: websecure
traefik.http.routers.rubypodcatcher_secure.rule: Host(`rubypodcatcher.com`)
traefik.http.routers.rubypodcatcher_secure.tls: true
traefik.http.routers.rubypodcatcher_secure.tls.certresolver: letsencrypt
options:
network: "private"
# Credentials for your image host.
registry:
# Specify the registry server, if you're not using Docker Hub
# server: registry.digitalocean.com / ghcr.io / ...
username: joshio1
# Always use an access token rather than real password when possible.
password:
- KAMAL_REGISTRY_PASSWORD
# Inject ENV variables into containers (secrets come from .env).
# Remember to run `kamal env push` after making changes!
env:
clear:
HOSTNAME: rubypodcatcher.com
secret:
- RAILS_MASTER_KEY
# Configure custom arguments for Traefik
traefik:
options:
publish:
- "443:443"
volume:
- "/letsencrypt/acme.json:/letsencrypt/acme.json"
network: "private"
args:
entryPoints.web.address: ":80"
entryPoints.websecure.address: ":443"
certificatesResolvers.letsencrypt.acme.email: "omkar.nitin.joshi@gmail.com"
certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
certificatesResolvers.letsencrypt.acme.httpchallenge: true
certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web
- Replace
with the IP address of your remote server.
Step 2: Create LetsEncrypt acme file and docker network on remote server
- We are going to use letsencrypt for our HTTPS configuration as you may have seen from the
deploy.yml
file above. - We will need to create an
acme.json
file on the remote server for ourdeploy.yml
changes to work. - We also need to create a “private” Docker network changes which we use to communicate internally.
- We can do that by SSHing to the remote server as follows:
1
2
3
$ ssh root@<SERVER_IP>
root# mkdir -p /letsencrypt && touch /letsencrypt/acme.json && chmod 600 /letsencrypt/acme.json
root# docker network create -d bridge private
- We can also automate this by using Kamal hooks but this is just a one-time task and not needed for every deploy (of course)
Step 3: Change force_ssl to true in production.rb
- If you followed my previous articles, I had configured
config.force_ssl
to befalse
so that we can access our server using HTTP as well. - We need to revert this change and instead
force_ssl
should be set totrue
1
2
3
4
# config/production.rb
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
Step 4: Allow inbound HTTPS connections
- We need to also allow inbound HTTPS connections to our remote server.
- To do this, create a firewall and allow inbound connections to port 80 and 443 into the remote server.
Step 5: Add A record and CNAME in domain provider settings
- We need to point our domain to the IP address of our remote server.
- To do this, we will need to add the following records in the DNS settings of our domain provider (i.e. wherever we have purchased our domain from)
- We need to add an
A record
withHOST
value of@
and value will be the IP address of the remote server. - We also need to add a
CNAME record
withHOST
value ofwww
and value will be the name of ourdomain
ending with.com
. - Note that these settings might change based on your domain provider. Hence, please check with your domain provider. (Above settings are applicable for Namecheap which is where I have my domain from)
Step 6: Deploy using Kamal
- Once we are done with all the configuration, it is time to deploy our changes to the remote server.
- We will run these following commands:
1
2
3
kamal setup
kamal deploy
kamal traefik restart
- After running these commands, if we visit our website directly using the domain name, we should be able to see our Rails application up and running.
- Other commands you might wanna try for debugging in case there was some error:
1
2
kamal traefik logs
kamal app logs
- Also, you can use
kamal env push
to push your environment variables andkamal traefik reboot
to reboot traefik. Please checkkamal traefik help
for more information. - This concludes our steps to add HTTPS and SSL certificate to our Rails application using Kamal.
Next Part: Sidekiq and Redis
- Click HERE to read the next post where I talk about adding Redis and Sidekiq to our Kamal configuration.
- Check out these previous articles from this series:
Part 1: Deploying a basic Rails application using Kamal on Hetzner
Listen to this podcast where DHH talks about Rails and Kamal.
If you would like to search for specific terms or concepts or names in Ruby/Rails podcasts, check out rubypodcatcher.com
This post is licensed under CC BY 4.0 by the author.