Redirect from www to non-www with Kamal and Traefik

Search for a command to run...

No comments yet. Be the first to comment.
Besides programming, tech, and entrepreneurship, I also like to run marathons and I'm a 1 Dan black belt in Kyokushin Karate. There are some big differences between these two sports, but they also have common grounds: training schedules, nutrition, m...

A couple of years ago, I discovered elixir, and since then, it has become my go-to language for creating full web applications, APIs, or just scripts. Elixir comes with strong scripting capabilities, enabling us to write code in a file—like some_scri...

What is Kamal Kamal is a new deployment tool designed for the efficient rollout of containerized applications. It's developed by 37Signals, the creators of Basecamp and Hey. Kamal provides zero-downtime deployments, rolling restarts, remote builds, a...

In December 2022 I joined Neurony Solutions , a 20 years old development agency in Bucharest, as their CTO and one of my first tasks was to improve our hiring process. I'm familiar with the company and the team, as this wasn't our first time meeting ...

I recently wrote an article about how I do deployments with Kamal, which included setting up SSL for your domain and redirecting from non-ssl to ssl. In this article, I want to go further and show you how I redirect from www to non-www.
In the config folder, I have 3 yaml files: deploy.yml, deploy.development.yml, and deploy.production.yml.
deploy.yml contains the shared configuration across environments. Then, in each deploy.*.yml, I add the specifics for each environment, such as the server IP address, different domain names, etc.
# config/deploy.yml
# Name of your application.
service: my_app
image: username/image_name
registry:
# Specify the registry server
username: registry_username
password:
- KAMAL_REGISTRY_PASSWORD
env:
clear:
HOSTNAME: your_hostname
secret:
- KAMAL_REGISTRY_PASSWORD
- add_any_other_secrets_here
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: "your_email_address"
certificatesResolvers.letsencrypt.acme.storage: "/letsencrypt/acme.json"
certificatesResolvers.letsencrypt.acme.httpchallenge: true
certificatesResolvers.letsencrypt.acme.httpchallenge.entrypoint: web
# add this if you are using a different route and port than kamal's defaults
healthcheck:
path: /
port: 1234
Before you begin the deployment process for the first time, remember to create the necessary folders and Docker network:
Setup the directory for Let's encrypt
mkdir -p /letsencrypt && touch /letsencrypt/acme.json && chmod 600 /letsencrypt/acme.json
create a Docker network called private
docker network create -d bridge private
The reason we're using a Docker private network is that when you open a port in Kamal, it becomes accessible to everyone. This happens because Docker automatically adds it to the iptables firewall.
Now let's see how config.development.yml looks like:
servers:
web:
hosts:
- put_your_deployment_server_ip_address_here
labels:
traefik.http.routers.devproject_secure.entrypoints: websecure
traefik.http.routers.devproject.rule: Host(`your_domain.tld`) || Host(`www.your_domain.tld`)
traefik.http.routers.devproject_secure.rule: Host(`your_domain.tld`) || Host(`www.your_domain.tld`)
traefik.http.routers.devproject_secure.tls: true
traefik.http.routers.devproject_secure.tls.certresolver: letsencrypt
traefik.http.routers.devproject_secure.middlewares: redirect-to-non-www
traefik.http.middlewares.redirect-to-non-www.redirectregex.regex: ^https?://www.your_domain.tld/(.*)
traefik.http.middlewares.redirect-to-non-www.redirectregex.replacement: https://your_domain.tld/$1
traefik.http.middlewares.redirect-to-non-www.redirectregex.permanent: true
builder:
multiarch: false
To accept traffic from both the www subdomain and our main domain in our router, we can simply use || (OR) to include both hosts. By doing this, we'll accept incoming traffic from both and also obtain an SSL certificate for them.
traefik.http.routers.devproject_secure.middlewares: redirect-to-non-www
We hook up a new middleware caled: redirect-to-non-www to our devproject_secure router.
traefik.http.middlewares.redirect-to-non-www.redirectregex.regex: ^https?://www.your_domain.tld/(.*)
traefik.http.middlewares.redirect-to-non-www.redirectregex.replacement: https://your_domain.tld/$1
traefik.http.middlewares.redirect-to-non-www.redirectregex.permanent: true
This part is straightforward: we specify the regex expression, define the replacement, and enable 301 redirects by setting it to true.
Now, you can deploy your app (or update your configuration), but don't forget to run kamal traefik reboot every time you change Traefik settings.
I began using Traefik when I started deploying with kamal, and I'm currently learning about what it can do and how.