Api Path Railway proxy

1. The problem I’m having:

I am trying to do a reverse proxy to /api/ to an internal service in Railway where it is subservice.local/api . My current configuration is always going to the index.html for the angular app

2. Error messages and/or full log output:

No error message just not redirecting correctly

3. Caddy version:

2.7

4. How I installed and ran Caddy:

I am using the docker image FROM caddy:2.7

a. System environment:

Docker

b. Command:

CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

d. My complete Caddy config:

# global options
{
	admin off # theres no need for the admin api in railway's environment
	persist_config off # storage isn't persistent anyway
	auto_https off # railway handles https for us, this would cause issues if left enabled
	# runtime logs
	log {
		format json # set runtime log format to json mode 
	}
	# server options
	servers {
		trusted_proxies static private_ranges 100.0.0.0/8 # trust railway's proxy
	}
}


(lb_settings) {
	lb_policy round_robin
	lb_retries 100
	lb_try_duration 10s
	lb_try_interval 250ms
}

(passive_health_checks) {
	fail_duration 60s
	max_fails 300
	unhealthy_latency 5s
	unhealthy_request_count 200
}

:{$PORT} {
	# access logs
	log {
		format json # set access log format to json mode
	}

	# health check for railway
	rewrite /health /*

    # the handle_path directive WILL strip /api/ from the path before proxying
	# use `handle` instead of `handle_path` if you dont want to strip the /api/ path
	# this is needed if your backend's api routes don't start with /api/
	# change paths as needed
	handle_path /api/* {
		# the /api/ prefix WILL be stripped from the uri sent to the proxy host
		#
		# proxy all requests for /api/* to the backend, configure this variable in the service settings
		reverse_proxy {            
			# for private networking replicas are exposed as multiple dns results, use those dns results as the upstreams
			dynamic a {
				name {$BACKEND_DOMAIN}
				port {$BACKEND_PORT}
				refresh 1s
				dial_timeout 30s
				versions ipv4 ipv6
			}

			# configure load balancing settings
			import lb_settings

			# configure passive health checks
			import passive_health_checks

			# sets the Host header to the header to the dynamic name and port options
			header_up Host {upstream_hostport}
		}
	}

	# serve from the 'dist' folder (Vite builds into the 'dist' folder)
	root * /dist

	# enable gzipping responses
	encode gzip

	# serve files from 'dist'
	file_server
	
	try_files {path} /index.html @notApi
    
}

5. Links to relevant resources:

Trying to figure out why handle_path /api/* { is not working

Please upgrade to the latest, v2.8.4.

FYI lb_retries isn’t doing anything for you because lb_try_duration takes precedence. In other words, at most you could have 40 retries because 250ms fits in 10s 40 times. But in practice it’ll be a bit lower than that because of the latency of each retry being non-zero.

This is rewriting /health to literally /*. That doesn’t seem right. Do you mean / instead?

You probably only need this if you upstreams are HTTPS, otherwise you can let Host remain the original value.

You have all this stuff at the top-level of your config. Caddy’s directives get sorted according to the directive order so try_files will run before your handle_path, so your path will be rewritten before it even gets proxied.

You should put that entire chunk inside of a handle to make it mutually exclusive and not run for /api routes.

Also, @notApi cannot be used in that position in try_files, that doesn’t make sense.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.