Import with reverse_proxy doesn't work

1. The problem I’m having:

I have several reverse_proxy settings separated by sub-path. Usually, they are similar, so I try to remove duplicate code using import, but it doesn’t work well.

You can see my add_proxy snippet which generates like below.

handle_path /sam* {
		reverse_proxy localhost:3000 {
			header_up X-Real-IP {remote}
			header_up Host {upstream_hostport}
		}
		rewrite * /token{path}
	}

2. Error messages and/or full log output:

502 error for all reverse_proxy entries.

3. Caddy version:

unknown (maybe 2.6.x, upgraded yesterday)

4. How I installed and ran Caddy:

apk add caddy (alpine linux)

a. System environment:

alpine linux 3.18.0, x64, running alpine by rc-service

b. Command:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

c. Service/unit/compose file:

no docker use

d. My complete Caddy config:

collabora.aaaa.com {
	log {
		output file /var/log/caddy/collabora.log
	}

	reverse_proxy 192.168.0.50:9980 {
		header_up X-Real-IP {remote}
	}
}

(add_proxy) {
	handle_path /{args[0]}* {
		reverse_proxy {args[1]} {
			header_up X-Real-IP {remote}
			header_up Host {upstream_hostport}
		}
		rewrite * /{args[2]}{path}
	}
}

(add_header) {
	header_up X-Real-IP {remote}
	header_up Host {upstream_hostport}
}

proxy.aaaa.com {
	log {
		output file /var/log/caddy/proxy.log
	}

	@ws {
		header Connection *Upgrade*
		header Upgrade websocket
	}

	handle_path /eos* {
		reverse_proxy 1.2.3.4:8888 {
			header_up X-Real-IP {remote}
			header_up Host {upstream_hostport}
		}
	}

	handle_path /kon* {
		reverse_proxy https://api.kon-wallet.com {
			header_up X-Real-IP {remote}
			header_up Host {upstream_hostport}
		}
	}

	handle_path /arbitrum* {
		reverse_proxy https://arbitrum-sepolia-rpc.dedicated.allthatnode.com {
			import add_header
		}
		rewrite * /ffeda5ffd7{path}
	}

	#handle_path /sam* {
	#	reverse_proxy localhost:3000 {
	#		header_up X-Real-IP {remote}
	#		header_up Host {upstream_hostport}
	#	}
	#	rewrite * /token{path}
	#}
	import add_proxy sam localhost:3000 token

	handle_path /ripple* {
					reverse_proxy s1.ripple.com:443 {
									header_up X-Real-IP {remote}
									header_up Host {upstream_hostport}
					}
	}

	handle {
		respond "not found" 404
	}
}

5. Links to relevant resources:

What do you mean by “doesn’t work well”? What “doesn’t work”, exactly?

You didn’t share any logs or error messages. You didn’t describe the problem. We can’t help without more information.

That’s an old version, the latest is 2.7.6.

Please run the caddy version command to check the version.

After adding import directive (add_proxy), all handle_path inside proxy.aaaa.com block returns 502 Bad Gateway with no response body.

this is my import directive

(add_proxy) {
	handle_path /{args[0]}* {
		reverse_proxy {args[1]} {
			header_up X-Real-IP {remote}
			header_up Host {upstream_hostport}
		}
		rewrite * /{args[2]}{path}
	}
}

and used it like below.

import add_proxy sam localhost:3000 token

You can see the exact locations are original post.

And here’s log for two consecutive requests

  1. POST proxy.singingdeveloper.com/sam
  2. POST proxy.singingdeveloper.com/arbitrum
2024/02/06 13:11:15.409 DEBUG   http.handlers.rewrite   rewrote request {"request": {"remote_ip": "14.52.161.35", "remote_port": "52849", "proto": "HTTP/1.1", "method": "POST", "host": "proxy.singingdeveloper.com", "uri": "/sam", "headers": {"Accept-Encoding": ["gzip, deflate, br"], "Connection": ["keep-alive"], "Content-Length": ["93"], "Content-Type": ["application/json"], "User-Agent": ["PostmanRuntime/7.36.1"], "Accept": ["*/*"], "Postman-Token": ["b7fa194e-7b28-419a-b2d5-514d8f6832a8"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "server_name": "proxy.singingdeveloper.com"}}, "method": "POST", "uri": "sam"}
2024/02/06 13:11:15.409 DEBUG   http.handlers.rewrite   rewrote request {"request": {"remote_ip": "14.52.161.35", "remote_port": "52849", "proto": "HTTP/1.1", "method": "POST", "host": "proxy.singingdeveloper.com", "uri": "sam", "headers": {"User-Agent": ["PostmanRuntime/7.36.1"], "Accept": ["*/*"], "Postman-Token": ["b7fa194e-7b28-419a-b2d5-514d8f6832a8"], "Accept-Encoding": ["gzip, deflate, br"], "Connection": ["keep-alive"], "Content-Length": ["93"], "Content-Type": ["application/json"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "server_name": "proxy.singingdeveloper.com"}}, "method": "POST", "uri": "/sam"}
2024/02/06 13:11:15.409 ERROR   http.log.error.log2     making dial info: upstream {args[1]}: invalid dial address : missing port in address    {"request": {"remote_ip": "14.52.161.35", "remote_port": "52849", "proto": "HTTP/1.1", "method": "POST", "host": "proxy.singingdeveloper.com", "uri": "/sam", "headers": {"Accept": ["*/*"], "Postman-Token": ["b7fa194e-7b28-419a-b2d5-514d8f6832a8"], "Accept-Encoding": ["gzip, deflate, br"], "Connection": ["keep-alive"], "Content-Length": ["93"], "Content-Type": ["application/json"], "User-Agent": ["PostmanRuntime/7.36.1"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "server_name": "proxy.singingdeveloper.com"}}, "duration": 0.000073521, "status": 502, "err_id": "j38i4zt35", "err_trace": "reverseproxy.statusError (reverseproxy.go:1299)"}
2024/02/06 13:11:20.842 DEBUG   http.handlers.rewrite   rewrote request {"request": {"remote_ip": "14.52.161.35", "remote_port": "52849", "proto": "HTTP/1.1", "method": "POST", "host": "proxy.singingdeveloper.com", "uri": "/arbitrum", "headers": {"Content-Length": ["93"], "Content-Type": ["application/json"], "User-Agent": ["PostmanRuntime/7.36.1"], "Accept": ["*/*"], "Postman-Token": ["99038593-aca3-462a-8bb4-5bcf3be208b6"], "Accept-Encoding": ["gzip, deflate, br"], "Connection": ["keep-alive"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "server_name": "proxy.singingdeveloper.com"}}, "method": "POST", "uri": "arbitrum"}
2024/02/06 13:11:20.842 DEBUG   http.handlers.rewrite   rewrote request {"request": {"remote_ip": "14.52.161.35", "remote_port": "52849", "proto": "HTTP/1.1", "method": "POST", "host": "proxy.singingdeveloper.com", "uri": "arbitrum", "headers": {"Content-Type": ["application/json"], "User-Agent": ["PostmanRuntime/7.36.1"], "Accept": ["*/*"], "Postman-Token": ["99038593-aca3-462a-8bb4-5bcf3be208b6"], "Accept-Encoding": ["gzip, deflate, br"], "Connection": ["keep-alive"], "Content-Length": ["93"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "server_name": "proxy.singingdeveloper.com"}}, "method": "POST", "uri": "/arbitrum"}
2024/02/06 13:11:20.842 ERROR   http.log.error.log2     making dial info: upstream {args[1]}: invalid dial address : missing port in address    {"request": {"remote_ip": "14.52.161.35", "remote_port": "52849", "proto": "HTTP/1.1", "method": "POST", "host": "proxy.singingdeveloper.com", "uri": "/arbitrum", "headers": {"Accept-Encoding": ["gzip, deflate, br"], "Connection": ["keep-alive"], "Content-Length": ["93"], "Content-Type": ["application/json"], "User-Agent": ["PostmanRuntime/7.36.1"], "Accept": ["*/*"], "Postman-Token": ["99038593-aca3-462a-8bb4-5bcf3be208b6"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "server_name": "proxy.singingdeveloper.com"}}, "duration": 0.000072874, "status": 502, "err_id": "afksguzgj", "err_trace": "reverseproxy.statusError (reverseproxy.go:1299)"}

and same request body is used

{
	"jsonrpc":"2.0",
	"method":"eth_getBlockByNumber",
	"params":["latest", false],
	"id": 1
}

caddy version says unknown exactly what I’ve said earlier, but I upgraded yesterday and I would be 2.7.6-r0(Alpine Linux packages).

Ah, right. The alpine packaging team is building incorrectly, so version information is not preserved properly. Sigh.

Here’s your problem. Your snippet didn’t produce a valid config.

Use caddy adapt -p to check the JSON config that your Caddyfile generates.

caddy adapt -p works well,

here’s part of it. args are not parsed I think.

{
  "group": "group8",
  "handle": [
    {
      "handler": "subroute",
      "routes": [
        {
          "handle": [
            {
              "handler": "rewrite",
              "strip_path_prefix": "/{args[0]}"
            }
          ]
        },
        {
          "group": "group0",
          "handle": [
            {
              "handler": "rewrite",
              "uri": "/{args[2]}{http.request.uri.path}"
            }
          ]
        },
        {
          "handle": [
            {
              "handler": "reverse_proxy",
              "headers": {
                "request": {
                  "set": {
                    "Host": ["{http.reverse_proxy.upstream.hostport}"],
                    "X-Real-Ip": ["{http.request.remote}"]
                  }
                }
              },
              "upstreams": [
                {
                  "dial": "{args[1]}"
                }
              ]
            }
          ]
        }
      ]
    }
  ],
  "match": [
    {
      "path": ["/{args[0]}*"]
    }
  ]
},

am i missing something basic about import?

If you’re actually using an older version of Caddy, then {args[0]} syntax didn’t exist and therefore it would fail.

I don’t have any way to help you verify you actually have the latest version, because clearly the Alpine releases don’t have it.

I suggest grabbing an official release from GitHub and using that instead, if you’re not able to guarantee you’re getting the latest release from the Alpine repo.

I picked latest version from github, and everything works like a charm.
All my efforts from yesterday is ended in sudden :melting_face:

My caddy version is
v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=.

For clarify, I tried upgrade caddy binary again from alpine repo,

apk update --no-cache
apk upgrade caddy --no-cache

but still got error, also shows version unknown.
Alpine crews need to work harder :slight_smile:

Thank you for your help! @francislavoie

Ahhh I see the problem:

https://pkgs.alpinelinux.org/packages?name=caddy&branch=v3.18&repo=&arch=&maintainer=

You said you’re on Alpine 3.18. That’s an older version, and therefore doesn’t have the latest packages. You were getting Caddy v2.6.4.

If you switch to 3.19 or “edge”, you’d have the latest.