Forwarding requests to host to another server on same IP

1. Caddy version (caddy version):

  • prod1 v2.5.2 h1:eCJdLyEyAGzuQTa5Mh3gETnYWDClo1LjtQm2q9RNZrs=
  • dev1 v2.5.2 h1:eCJdLyEyAGzuQTa5Mh3gETnYWDClo1LjtQm2q9RNZrs=

2. How I run Caddy:

Both instances are in Ubuntu guests running under Hyper-V

a. System environment:

  • prod1 systemd
  • dev1 docker-compose

b. Command:

#prod1
sudo systemctl enable --now caddy
#dev1
docker-compose --profile main start 

c. Service/unit/compose file:

#
#prod1
#
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

#
#dev1
#
services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    networks:
      - main
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - $PWD/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

  focalboard:
    image: mattermost/focalboard
    profiles:
      - main
      - focalboard
    restart: unless-stopped
    networks:
      - main
      - focalboard
    volumes:
      - focalboard_data:/data

  wiki:
    image: requarks/wiki:2
    profiles:
      - main
      - wiki
    restart: unless-stopped
    depends_on:
      - wiki_db
    env_file:
      - ./wiki.env
    networks:
      - main
      - wiki
  wiki_db:
    image: postgres
    profiles:
      - main
      - wiki
    restart: unless-stopped
    env_file:
      - ./wiki.env
    networks:
      - wiki
    volumes:
      - wiki_db_data:/var/lib/postgresql/data

  rocket_chat:
    image: rocket.chat
    profiles:
      - main
      - rocket_chat
    restart: unless-stopped
    depends_on:
      - rocket_chat_db
    env_file:
      - ./rocket_chat.env
    networks:
      - main
      - rocket_chat
  rocket_chat_db:
    image: bitnami/mongodb
    profiles:
      - main
      - rocket_chat
    restart: unless-stopped
    env_file: ./rocket_chat.env
    networks:
      - rocket_chat
    volumes:
      - rocket_chat_data:/bitnami/mongodb


volumes:
  caddy_data:
    external: true
  caddy_config:
  wiki_db_data:
    external: true
  rocket_chat_data:
    external: true
  focalboard_data:
    external: true

networks:
  main:
  wiki:
  rocket_chat:
  focalboard:

d. My complete Caddyfile or JSON config:

#
#prod1
#

{
        debug
}

wiki.riverbedranch.org {
        reverse_proxy localhost:2080
}
riverbedranch.dev {
        reverse_proxy 10.0.1.80:80
}


#
#dev1
#

{
        debug
}

#:80, :443 {
#       respond "This is 10.0.1.80"
#}

riverbedranch.dev {
        reverse_proxy focalboard:8000
}
#kanban.riverbedranch.dev {
#       reverse_proxy focalboard:8000
#}

3. The problem I’m having:

I’m hosting a server at my house with Hyper-V installed. I have one IP, and decided that forwarding traffic to riverbedranch.dev from prod1 to dev1. If I uncomment the :80, :443 .... entry on dev1 I get the response.

4. Error messages and/or full log output:

# prod1
Jul 23 16: 18: 31 riverbedranch.org caddy[462346]: {
	"level": "error",
	"ts": 1658614711.0829048,
	"logger": "http.log.error",
	"msg": "dial tcp 10.0.1.80:80: connect: connection refused",
	"request": {
		"remote_ip": "216.147.121.173",
		"remote_port": "65349",
		"proto": "HTTP/2.0",
		"method": "GET",
		"host": "riverbedranch.dev",
		"uri": "/favicon.ico",
		"headers": {
			"Sec-Fetch-Mode": ["no-cors"],
			"Sec-Fetch-Site": ["same-origin"],
			"Sec-Gpc": ["1"],
			"Pragma": ["no-cache"],
			"Accept": ["image/avif,image/webp,*/*"],
			"Accept-Language": ["en-US,en;q=0.5"],
			"Referer": ["https://riverbedranch.dev/favicon.ico"],
			"Dnt": ["1"],
			"Te": ["trailers"],
			"User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0"],
			"Accept-Encoding": ["gzip, deflate, br"],
			"Sec-Fetch-Dest": ["image"],
			"Cache-Control": ["no-cache"]
		},
		"tls": {
			"resumed": false,
			"version": 772,
			"cipher_suite": 4865,
			"proto": "h2",
			"server_name": "riverbedranch.dev"
		}
	},
	"duration": 0.0016644,
	"status": 502,
	"err_id": "rs7v0n7a8",
	"err_trace": "reverseproxy.statusError (reverseproxy.go:1184)"
}

5. What I already tried:

I’ve tried setting X-Forwarded-Host and other things like trusted_proxies but, I’m not sure if I’m doing it correctly.

6. Links to relevant resources:

Well, it depends.

If both of your Caddy instances are in the same private network, then you can just proxy over HTTP and not HTTPS. But if traffic between them goes over public networks, then you very much should use HTTPS between them. Setting up HTTPS between services can open up a can of worms; there’s a bunch of manual steps to setting up mutual TLS, if ACME challenges aren’t possible to issue certs.

So with all that said, you probably just need to do two things, if both are in a private network:

  • Add http:// in front of the site addresses in the upstream instance, to tell them to just listen over HTTP, and not attempt to set up HTTPS. E.g. http://riverbedbranch.dev
  • Configure trusted_proxies on the upstream instance so that it trusts the incoming X-Forwarded-* headers from the downstream instance, so that the client’s origin IP is passed to your proxied app.
1 Like

That’s worked for the root domain, but if I add a wildcard it breaks and throws SSL_ERROR_INTERNAL_ERROR_ALERT

You need to use the DNS challenge if you want to use wildcard certificates.