Authentication Issue using basic_auth with Caddy
chrisschmit
PROOP

a year ago

I have a web application deployed on Railway with two environments:

  1. Production: Publicly accessible without authentication
  2. Staging: Should be protected with HTTP Basic Authentication

I've implemented Caddy as a reverse proxy to handle routing and, in the case of the staging environment, to add Basic Authentication. While the authentication works perfectly in my local environment, it appears to be bypassed in the Railway-hosted staging environment.

What Works

  1. Local Environment: When testing locally, the Basic Authentication works perfectly
  • Requests to test.localhost return 401 without credentials
  • Requests with valid credentials are authenticated properly
  • The staging.localhost route is also properly protected
  1. Production on Railway: Working as expected without authentication

What Doesn't Work

Staging on Railway: The Basic Authentication is bypassed

  • Requests to staging.example.com return content without requiring authentication
  • The response headers show server: railway-edge indicating Railway's edge network is handling the requests
  • Authentication headers are being sent but not enforced

Here is my caddy_file:

{ # global options  
    admin off  
    persist_config off  
    auto_https off  
    log {  
        format console  
        level DEBUG  
    }  
    servers {  
        trusted_proxies static private_ranges  
    }  
}  
:{$PORT} {  
    log {  
        format console  
        level DEBUG  
    }  
    handle /join-waitlist/api/* {  
        uri strip_prefix /join-waitlist  
        reverse_proxy {$BACKEND_HOST}  
    }  
    handle /api/* {  
        reverse_proxy {$BACKEND_HOST}  
    }  
    header {  
        # Set JavaScript MIME type for module scripts  
        Content-Type "application/javascript" *.js  
        # Set CSS MIME type  
        Content-Type "text/css" *.css  
    }  
    handle_path /join-waitlist/* {  
        reverse_proxy {$FRONTEND_HOST}  
    }  
    redir / /join-waitlist/ permanent  
}  
# Production staging domain (protected with basic auth)  
staging.example.com {  
    log {  
        output stdout  
        format console  
    }  
    # Authentication for all paths  
    basicauth /* {  
        dev <HASHED_PASSWORD_HERE>  
    }  
    # Add cache control headers to prevent edge caching  
    header {  
        Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate"  
        Pragma "no-cache"  
        Expires "0"  
    }  
      
    # Handle specific paths AFTER authentication  
    handle /join-waitlist/api/* {  
        uri strip_prefix /join-waitlist  
        reverse_proxy {$BACKEND_HOST}  
    }  
    handle /api/* {  
        reverse_proxy {$BACKEND_HOST}  
    }  
    header {  
        Content-Type "application/javascript" *.js  
        Content-Type "text/css" *.css  
    }  
    handle_path /join-waitlist/* {  
        reverse_proxy {$FRONTEND_HOST}  
    }  
    redir / /join-waitlist/ permanent  
}  
# Local staging environment (also protected)  
staging.localhost.test:80 {  
    log {  
        output stdout  
        format console  
    }  
    # Same authentication block as production staging  
    basicauth /* {  
        dev <HASHED_PASSWORD_HERE>  
    }  
      
    # Handle specific paths AFTER authentication  
    handle /join-waitlist/api/* {  
        uri strip_prefix /join-waitlist  
        reverse_proxy {$BACKEND_HOST}  
    }  
    handle /api/* {  
        reverse_proxy {$BACKEND_HOST}  
    }  
    header {  
        Content-Type "application/javascript" *.js  
        Content-Type "text/css" *.css  
    }  
    handle_path /join-waitlist/* {  
        reverse_proxy {$FRONTEND_HOST}  
    }  
    redir / /join-waitlist/ permanent  
}  
# Test endpoint to verify authentication  
test.localhost.test:80 {  
    basicauth /* {  
        dev <HASHED_PASSWORD_HERE>  
    }  
    respond "Authentication successful"  
}  
$10 Bounty

3 Replies

sim
FREE

a year ago

Railway is routing traffic to the port instead of the staging block


sim
FREE

a year ago

You will have to update the file so the port block handles that case which maybe a catch all


sim
FREE

a year ago

Why don't try logging something in that block and if it is logged when you make a staging request then that will prove this theory


Welcome!

Sign in to your Railway account to join the conversation.

Loading...