Until recently, deploying a dockerized application seemed like a daunting task. Fortunately, this has changed thanks to Kamal, a tool specifically designed to streamline the deployment of web applications through a simple yet efficient workflow.
At Unagi, we’ve been “Kamalizing” some of our developments for a couple of months now, and so far, we’ve had a great experience.
But even with recent improvements, the official docs are still not clear. So, we have to rely on articles or content shared by the community.
To contribute our two cents, today I’m going to share something I haven’t found much information about: how to serve the application from a specific domain (e.g., example.com) and with the subdomain www (e.g., www.example.com).
Disclaimer: I assume you know what Kamal is and are familiar with the basics of its configuration.
Let’s assume we have a system built with Ruby on Rails that is already deployed on Hetzner/Digital Ocean or any preferred server. It’s likely that we have a configuration like this in the deploy.yml
file:
service: messi
image: messigoat/web
servers:
web:
hosts:
- <%= ENV['WEB_IP'] %>
labels:
traefik.http.routers.messi-web.rule: Host(`messigoat.com`)
traefik.http.routers.messi-web.tls: true
traefik.http.routers.messi-web.tls.certresolver: letsencrypt
# Other configurations like builder, volumes, etc
# ...
traefik:
options:
publish:
- "443:443"
volume:
- "/letsencrypt/acme.json:/letsencrypt/acme.json"
args:
entryPoints.web.address: ":80"
entryPoints.websecure.address: ":443"
entryPoints.web.http.redirections.entryPoint.to: websecure
entryPoints.web.http.redirections.entryPoint.scheme: https
entryPoints.web.http.redirections.entrypoint.permanent: true
certificatesResolvers.letsencrypt.acme.email: "you@mail.com"
certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
certificatesResolvers.letsencrypt.acme.httpchallenge: true
certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web
With this configuration, we establish a web role where we specify the application’s domain and designate Let’s Encrypt to serve the certificate. In the Traefik configuration, we set up a redirection to ensure the application is consistently accessed via HTTPS, along with the necessary parameters to generate the certificate.
When we deploy and access messigoat.com, the application runs smoothly. However, the challenge arises when attempting to access www.messigoat.com because we’ve solely defined messigoat.com as the domain for the application.
To fix this, we just need to adjust the Traefik setup to handle requests for both messigoat.com and www.messigoat.com. This usually means setting up a rule to handle requests for both the main domain and the www subdomain, making sure that both are covered by the SSL certificate.
To achieve this, two very simple actions are necessary:
- Create a DNS record that points to the same IP as the main domain. This can be done from the platform where you manage DNS records.
- Add the subdomain configuration to Traefik configuration inside the deploy.yml file.
Here, we’re just gonna talk about the second item because for the first one you can easily find hundred of resources on how to do it. You’ll see that the changes are pretty simple. But because there isn’t much documentation, it took a lot of trial and error to make the changes I’m showing.
The first thing we need to do is add our subdomain as a rule of the web role. To do this, we replace the value of the key traefik.http.routers.messi-web.rule
with the following:
traefik.http.routers.messi-web.rule: Host(`messigoat.com`) || Host(`www.messigoat.com`)
And then we must define a primary and secondary domain in the Traefik configuration:
traefik:
...
args:
...
entrypoints.websecure.http.tls.domains[0].main: "messigoat.com"
entrypoints.websecure.http.tls.domains[0].sans: "www.messigoat.com"
...
Done! With these changes, the next deployment will create the corresponding certificate, and the application will be accessible with or without the www subdomain.
I hope you found this information useful and that it saved you time on your Kamal configuration. Please let me know if you have any alternatives or suggestions.