Here are some tips when I am using CaddyV2 as a reverse proxy.

Build your own caddy to support proxy protocol

# Install xcaddy.
sudo apt install -y golang-go
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list
sudo apt update
sudo apt install xcaddy

# Build caddy with a plugin.
xcaddy build --with github.com/mastercactapus/caddy2-proxyprotocol --output /tmp/caddy

# Replace the original caddy
sudo systemctl stop caddy.service
cp /tmp/caddy /usr/bin/
sudo systemctl restart caddy.service

Modify your Caddy V2 file to support Proxy Protocol.

Caution: After this, normal requests without Proxy Protocol may crash!

sudo vim /etc/caddy/Caddyfile
{
        servers :443 {
                listener_wrappers {
                        proxy_protocol {
                                timeout 2s
                        }
                        http_redirect
                        tls
                }
        }
}

If you are using FRP as reverse proxy, don't forget that you can also update it!

sudo vim /etc/frp/frpc.ini
# Check on Caddy.
[HTTP]
type = tcp
local_ip = 127.0.0.1
local_port = 80
remote_port = 80

# Check on Caddy.
[HTTPS]
type = tcp
local_ip = 127.0.0.1
local_port = 443
remote_port = 443
proxy_protocol_version = v2

If you are using FRP as reverse proxy, also set the allow attribute to use this plugin only when the request is coming from the trusted reverse proxy server!

For example, frp it works at 127.0.0.1. So I set it as:

{
	servers :443 {
		listener_wrappers {
			proxy_protocol {
				timeout 2s
				allow 127.0.0.1/32
			}
			http_redirect
			tls
		}
	}
}

Use Caddy V2 to host a static file server

files.aiursoft.com {
    header Access-Control-Allow-Origin *
    header Cache-Control \"public, max-age=604800\"
    root * /var/www/html
    file_server
}

Use Caddy V2 to directly render HTML

somedomain.aiursoft.com {
        respond / "<h1>Welcome</h1>" 200
}

Use Caddy V2 to reverse proxy on certain address

somedomain.aiursoft.com {
        reverse_proxy /admin http://v2ray:10000 {
        }
}

Use Caddy V2 to do a permenant redirect

git.aiursoft.com {
        redir https://git.aiursoft.cn{uri} permanent
}

Use Caddy V2 to reversey proxy and remove\add custom header

git.aiursoft.cn {
        header -x-frame-options # Remove x-frame-options header
        reverse_proxy http://gitea:3000
}

Use Caddy V2 to reverse proxy but ignore cert issue

pve.aiursoft.cn {
        reverse_proxy https://pve:8006 {
                transport http {
                        tls_insecure_skip_verify # Allow insecure cert
                }
        }
}

Use Caddy V2 to reverse proxy, but only allow LAN access

media.aiursoft.cn {
        @blocked not remote_ip 192.168.1.0/24
        respond @blocked "<h1>Access Denied</h1>" 403
        reverse_proxy http://jellyfin:8096 {
        }
}

Use Caddy V2 to reverse proxy, but only allow LAN to sign in

# Protected by AAD.
anduin.aiursoft.cn {
	@hacker {
		not remote_ip 192.168.1.0/24
		path /admin*
	}
	respond @hacker  "<h1>You are not the admin! Don't try to hack my server :)</h1>" 200

	reverse_proxy http://blog01:48466 {
  }
}

Use Caddy V2 to reverse proxy, but override the HTTP Host header

nextcloud.aiursoft.cn {
        reverse_proxy http://nextcloud {
                header_up Host nextcloud.aiursoft.cn
        }
}

Use Caddy V2 to reverse proxy, and also protect by basic auth password authentication

You need to generate password hash first. You can generate it here.

jump.aiursoft.cn {
        basicauth / {
                Anduin password-hash
        }
        reverse_proxy https://jump:9090 {
                transport http {
                        tls_insecure_skip_verify
                }
        }
}

Use Caddy V2 to reverse proxy, and load balance between two nodes

# Protected by AAD.
anduin.aiursoft.cn {
	reverse_proxy http://blog01:48466 http://blog02:48466 {
		lb_policy cookie lb
		health_port     48466 
		health_interval 10s
		health_timeout  10s
		health_status   200
		health_uri /
  }
}

Full demo (Example configuration)

Reverse Proxy:

  • Protected by basic auth password authentication for external IP address.
  • Allow direct access from LAN.
  • Override HTTP Host from jump to cockpit
  • Allow insecure HTTPS
  • Remove Header x-frame-options
jump.aiursoft.cn {
        header -x-frame-options # Remove x-frame-options header

        # Require 2FA for all external user.
        @2fa not remote_ip 192.168.1.0/24
        basicauth @2fa  {
                anduin $2a$12$hashhashhashhashhashhashhashhashhash
        }

        # Block external user to access the admin panel.
        @hacker {
                not remote_ip 192.168.1.0/24
                path /admin*
        }
        respond @hacker  "<h1>You are not the admin! Don't try to hack my server :)</h1>" 401

        # Load banace between two nodes
        reverse_proxy https://jump1:9090 https://jump2:9090 {
                header_up Host cockpit # Override HTTP Host
                transport http {
                        tls_insecure_skip_verify
                }

                lb_policy cookie lb
                health_port     48466
                health_interval 10s
                health_timeout  10s
                health_status   200
                health_uri /
        }
}