1. The problem I’m having:
Is it possible to share the same site/hostname and the same port between a Layer 4 (L4) and a Layer 7 (L7/HTTP) application?
Specifically, when connecting to a specific hostname (e.g., vscode.portal.{env.ACME_DOMAIN}) via a browser, I need standard L7/HTTP handling to apply, including cookie and query string management within the Caddyfile. Conversely, when connecting via SSH over TLS to the same hostname, I want a simple L4 proxy to take effect.
I have no issues running the two setups separately on two different hostnames, but I cannot get them to work on the same one. For example, the following configuration works (vscode-ssh.portal.{env.ACME_DOMAIN} for ssh and vscode.portal.{env.ACME_DOMAIN} for http):
listener_wrappers {
layer4 {
matching_timeout 1s
@vscode-ssh tls sni vscode-ssh.portal.{env.ACME_DOMAIN}
route @vscode-ssh {
tls
proxy vscode:22
}
}
tls
}
and also this
listener_wrappers {
layer4 {
matching_timeout 1s
@vscode-ssh tls sni vscode-ssh.portal.{env.ACME_DOMAIN}
route @vscode-ssh {
tls
subroute {
@ssh ssh
route @ssh {
proxy vscode:22
}
}
}
}
tls
}
but I don’t know if this could works
listener_wrappers {
layer4 {
matching_timeout 1s
@vscode tls sni vscode.portal.{env.ACME_DOMAIN}
route @vscode {
tls
subroute {
@ssh ssh
route @ssh {
proxy vscode:22
}
route {
# How to send to normal L7 http handling?
}
}
}
}
tls
}
I also tried another approach, i.e. matching after tls
listener_wrappers {
# tls <- implicit
layer4 {
matching_timeout 1s
@vscode vars l4.tls.server_name vscode.portal.{env.ACME_DOMAIN}
route @vscode {
subroute {
@ssh ssh
route @ssh {
proxy vscode:22
}
}
}
}
}
but this doesn’t works and raise the following error in log.
2. Error messages and/or full log output:
tls is enabled, but listener wrapper returns a connection that doesn’t implement connectionStater
3. Caddy version:
2.11.3
4. How I installed and ran Caddy:
FROM caddy:${CADDY_BUILDER_VERSION} AS builder
RUN xcaddy build ${CADDY_VERSION} \
--with github.com/caddyserver/ntlm-transport \
--with github.com/caddyserver/replace-response \
--with github.com/caddy-dns/cloudflare \
--with github.com/lucaslorentz/caddy-docker-proxy/v2 \
--with github.com/mholt/caddy-l4
a. System environment:
Docker
b. Command:
c. Service/unit/compose file:
d. My complete Caddy config:
The full config is 1000 rows spread among 30 files. The http part for the same site is:
@vscode {
host vscode.portal.{$ACME_DOMAIN}
remote_ip private_ranges
}
handle @vscode {
basic_auth {
vscode "$2a$14$7nq..."
}
@inject_cookie {
path /
method GET
not header Cookie *vscode-tkn=*
}
uri @inject_cookie query +tkn {env.VSCODE_WEB_TOKEN}
reverse_proxy http://vscode:8000
}