Caddy reverse_proxy and React Router

Hello all! I am unable to setup my Caddyfile to work with a React SPA app such that

  1. React router routes works
  2. Calls to /api/ (e.g. example.com/api/foo) are properly reverse proxied to another location

With my current Caddyfile below, React router appears to be working (visiting mysite.com/faq does not give a 404) but calls to the API backend (e.g. mysite.com/api/foo) appears to be trying to load a React Router route.

How can we fix this Caddyfile?

www.example.com {
	redir https://example.com{uri}
}

example.com {
    root * /root/example/frontend/build
    file_server
    encode gzip zstd

    reverse_proxy /api/*  api.example.com:8000

    try_files {path} /index.html
    
    tls admin@example.com

    log {
        output file /root/example/logs/access.log {
                roll_size 100mb
                roll_keep 5
                roll_keep_for 720h
        }
    }
}

Update: This second Caddyfile does not work too, React router no longer works, getting an error 404 when visiting https://example.com/faq. However, reverse proxy appears to be partially working: The API server is getting hits when we visit https://example.com/api/foo, but its getting them incorrectly as http://api.example.com:8000/api/foo instead of http://api.example.com:8000/foo

www.example.com {
    redir https://example.com{uri}
}

example.com {
    root * /root/example/frontend/build
    file_server
    encode gzip zstd

    reverse_proxy /api/*  api.example.com:8000

    @notAPI {
        not {
            path /api/*
        }
        file {
            try_files {path} {path}/ /index.html?{query}
        }
    }
    rewrite @notAPI {http.matchers.file.relative}
    
    tls admin@example.com

    log {
        output file /root/example/logs/access.log {
                roll_size 100mb
                roll_keep 5
                roll_keep_for 720h
        }
    }
}

Using Caddy v2.4.3
Caddy is started using caddy start --config ~/foo/Caddyfile

The issue you’re running into is that directives are sorted according to a predetermined order:

The better way to write this is with handle blocks, for mutual exclusivity:

example.com {
	tls admin@exampole.com

	handle /api* {
		reverse_proxy api.example.com:8000
	}

	handle {
		root * /root/example/frontend/build

		try_files {path} /index.html

		encode gzip zstd

		file_server
	}
}

Then you need to use handle_path instead of handle, to strip the path prefix.

handle_path /api* {
	reverse_proxy api.example.com:8000
}

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