24 August 2024

Protecting a specific route with basic auth in coolify with traefik

I ran into an issue recently where I wanted to protect just one routepath in my webapp. There was no clear documentation on coolify docs, and google searches didn't help.

I did find this stackoverflow question on it, but for some reason I couldn't make it work easily. With a little help from claude sonnet 3.5, I managed to do it though.

Implementation

Your coolify app will have a configuration textbox for passing in some traefik labels, in there, you should create a new router, call it what you like, I've called it admin-router.

# Admin router, routes under `/admin` will be using this router
traefik.http.routers.admin-router.rule=Host(`your-app.com`) && PathPrefix(`/admin`)
traefik.http.routers.admin-router.entrypoints=https
traefik.http.routers.admin-router.tls.certresolver=letsencrypt
traefik.http.routers.admin-router.tls=true
traefik.http.routers.admin-router.middlewares=admin-auth
traefik.http.routers.admin-router.service=admin-service

The last line is crucial; you need to create a service for that specific router. This was one of my initial pitfalls.

traefik.http.routers.admin-router.service=admin-service

Now, you're going to have more configurations in that file, since also the rest of your app needs to be configured. Coolify has created some automatically. We don't need to get rid of those, just modify them a bit.

traefik.enable=true
traefik.http.middlewares.gzip.compress=true
traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
 
# Your apps HTTP router
traefik.http.routers.http-0-<your-apps-router-name>.entryPoints=http
traefik.http.routers.http-0-<your-apps-router-name>.middlewares=redirect-to-https
traefik.http.routers.http-0-<your-apps-router-name>.rule=Host(`your-app.com`)
traefik.http.routers.http-0-<your-apps-router-name>.service=<your-apps-router-name>
 
# HTTPS router for main site
traefik.http.routers.https-0-<your-apps-router-name>.entryPoints=https
traefik.http.routers.https-0-<your-apps-router-name>.middlewares=gzip
# Important bit right here, `!PathPrefix(`/admin`)` will not use this router for admin routes
traefik.http.routers.https-0-<your-apps-router-name>.rule=Host(`your-app.com`) && !PathPrefix(`/admin`)
traefik.http.routers.https-0-<your-apps-router-name>.service=https-0-<your-apps-router-name>
traefik.http.routers.https-0-<your-apps-router-name>.tls.certresolver=letsencrypt
traefik.http.routers.https-0-<your-apps-router-name>.tls=true
 
# Admin router, routes under `/admin` will be using this router
traefik.http.routers.admin-router.rule=Host(`your-app.com`) && PathPrefix(`/admin`)
traefik.http.routers.admin-router.entrypoints=https
traefik.http.routers.admin-router.tls.certresolver=letsencrypt
traefik.http.routers.admin-router.tls=true
traefik.http.routers.admin-router.middlewares=admin-auth
traefik.http.routers.admin-router.service=admin-service
 
# Services
traefik.http.services.http-0-<your-apps-router-name>.loadbalancer.server.port=80
traefik.http.services.https-0-<your-apps-router-name>.loadbalancer.server.port=80
# Define the load balancer port for admin-service as well
traefik.http.services.admin-service.loadbalancer.server.port=80
 
# Middlewares - this is where you define your basicauth credentials
traefik.http.middlewares.admin-auth.basicauth.users=<username>:<hashed_password>
 
# Possible Caddy configuration
# ...

Passing !PathPrefix('/admin') after your main https routers rule will make it so that the routers won't be conflicting. I did see that the length of the rules has an effect on which takes precedence, but I didn't test that out too thorougly. If that is the case, we could be fine with just passing Host(your-app.com') in the rule.

Conclusion

This ended up working perfectly for my use case! Hope this post helps you as well. The coolify discord is also a great place to ask for help or learn about this stuff from other people. Andreas, the creator of coolify is also always very helpful. 😎