Skip to content

Conversation

JangoCG
Copy link

@JangoCG JangoCG commented Aug 9, 2025

Summary

Adds host canonicalization to redirect all requests to a single canonical host, e.g., force root (domain.com) or www (www.domain.com).
Supports both directions:

  • www.domain.com → domain.com
  • domain.com → www.domain.com

Redirects happen in one hop even with TLS (e.g., http://wwwhttps://root).

Changes

  • Added CanonicalHost to ServiceOptions
  • Centralized redirect logic to handle both scheme and host together
  • Added --canonical-host flag to deploy command
  • Added full test coverage for canonical host redirects (including TLS cases)

Motivation

Kamal currently has no built-in way to handle www ↔ root redirects, forcing users to rely on Cloudflare or custom reverse proxy rules.
This is a basic feature in most reverse proxies, and this PR makes it available natively in Kamal.

Compatibility

Backwards compatible, only active when explicitly configured.

Implements host canonicalization to redirect requests to a single host (e.g., force root or www).
Works with TLS redirect in a single hop (e.g., http://www -> https://root).

Changes:
- Added CanonicalHost to ServiceOptions
- Centralized redirect logic to compute both scheme and host in one place
- Exposed --canonical-host flag in deploy command
- Added comprehensive tests for canonical host redirects including TLS cases

This feature is backwards compatible and only active when configured.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@JangoCG JangoCG closed this Aug 9, 2025
@JangoCG JangoCG reopened this Aug 9, 2025
@Talha345
Copy link

Would love to get this merged!

@AnyCPU
Copy link
Contributor

AnyCPU commented Aug 14, 2025

@JangoCG @Talha345 why not to register a one service for two hosts, for instance: --host=example.com, www.example.com?

@Talha345
Copy link

@JangoCG @Talha345 why not to register a one service for two hosts, for instance: --host=example.com, www.example.com?

Having 2 hosts is fine but there should be a way to configure redirections from one to the other so a typical use case is from www to non-www domain or vice versa, which is required for SEO and its always a good idea to have your site running on just one domain usually.

@AnyCPU
Copy link
Contributor

AnyCPU commented Aug 14, 2025

@Talha345 i see your point.
however, it would be good point if we were discussing it 20 years ago.

these days if you want to have a one website just use a one host, keep your website name as short as possible for humans.
the www part is not required at all. Besides a lot of websites may use something like www1, ww5 ... for some reasons.

p.s.: create websites for humans, not for SEO.

@Talha345
Copy link

@Talha345 i see your point.
however, it would be good point if we were discussing it 20 years ago.

these days if you want to have a one website just use a one host, keep your website name as short as possible for humans.
the www part is not required at all. Besides a lot of websites may use something like www1, ww5 ... for some reasons.

p.s.: create websites for humans, not for SEO.

There could be various other use cases as well and that is out of the scope of this discussion.

In general, a proxy should support this kind of basic redirection.

I still have a couple of sites which are using Kamal 1 with Traefik and I simply have not upgraded to Kamal 2 for this exact reason.

@AnyCPU
Copy link
Contributor

AnyCPU commented Aug 14, 2025

@JangoCG

  1. do we still need following methods: shouldRedirectToHTTPS & redirectToHTTPS?
  2. do we have to check whether a canonical host is also presented in values for a --host option?

Copy link
Collaborator

@kevinmcconnell kevinmcconnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @JangoCG. This feature seems like a good idea to me!

I've left some small suggestions about the details. Let me know what you think. I'm also happy to address those myself if you don't have time.

I also like @AnyCPU's suggestion that if both --canonical-host and --host are set, we should validate that there is a --host that matches the --canonical-host (because otherwise, that deployment would be invalid). We can validate that is the command before attempting the deployment.

@JangoCG
Copy link
Author

JangoCG commented Sep 28, 2025

Thanks @JangoCG. This feature seems like a good idea to me!

I've left some small suggestions about the details. Let me know what you think. I'm also happy to address those myself if you don't have time.

I also like @AnyCPU's suggestion that if both --canonical-host and --host are set, we should validate that there is a --host that matches the --canonical-host (because otherwise, that deployment would be invalid). We can validate that is the command before attempting the deployment.

Awesome, I’m glad you like it @kevinmcconnell thank you for the review! And thanks as well @AnyCPU for your input.
I recently started a new job so I didn’t have much time to address your suggestions earlier, but I’ve now implemented the changes you mentioned.

# Conflicts:
#	internal/server/router_test.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants