Hello Together.
I have a question I can't seem to figure out. First of all, the background:
- OpnSense 26.1.5
- Lets Encrypt Cert with API of Netcup (*.mydomain.de) with ACME Client
- Caddy Plugin 2.1.0
- Synology DSM 7.2.2 Update 8
- Yubikey as Hardware-Security-Key
- usage until yet -> HAProxy -> Login in DSM works with Yubikey internal and external
- Rewrites of my Servers/Application in Unbound to IP of the Firewall (192.168.100.1)
I wanted to switch my reverse proxy from HAProxy to Caddy over the weekend. It worked fine at first. Then yesterday I noticed that logging in to Synology DSM (username/password/Yubikey as a security key) no longer works. The login is 'interrupted' – but not completely. This means that DSM registers it as an incorrect login. After three attempts, I locked myself out. I was then able to unlock it using a VPN and the OTP code (via the Yubikey). I then removed the Yubikey from the settings and tried to re-pair it -> error message: 'Registration could not be completed. Please try again'.
After an hour, searching on Google and here in the forum hadn't got me anywhere, and even the AI couldn't help. The theory is that Caddy does something with the headers that HAProxy doesn't. I switched back to HAProxy, and immediately the Yubikey registered as a security key again, and I was able to log in using the Yubikey once more.
My reason for switching to Caddy was that I'd like to use Authelia or Authentik in the future. Yes, that's also possible via Lua scripts in HAProxy, but unfortunately I don't understand the technical details well enough to really grasp what I'm doing there.
I'm hoping that someone here in the forum can help me out, as I know there are plenty of members here with loads of technical experience and knowledge.
Thanks in advance for your help. 😉
You're forgetting a key principle here - KISS
If you have a vpn there's no need to expose anything synology to the internet nor do you need 2FA.
Making sure that the management port is in a trusted vlan is all you need. Everything else way overkill.
Thank for your reply and your hint. Unfortunately it doesn't help to solve the problem and understanding caddy. 😉 I have same family members, which also use my Synology and it is to difficult to solve problems (VPN) remote and for these members it is easier to realize the access over a reverse proxy with a Yubikey. Many thanks again.
Ronny
You still have time to reconsider.
With a vpn, WireGuard or OpenVPN you'd only allow specific users to access the resource. Otherwise the whole of the internet can hammer the nas at will.
Assuming you'd go for WireGuard, you'd create everything that's needed and only send the third party a QR code.
Should there be a breakage of the vpn, the nas data is still accessible without issues.
_IF_ you can have ddns running on the clients to connect then you can simply lock down the wan access to the reverse proxy by creating a rule with source alias < ddns clients >, and then get rid of the token altogether.
Anyway, food for thought. The goal is simpler and more secure, one way or another.
Should there be a faulty nas update that breaks 2FA - you're in a heap of trouble.
Quote from: Ronny1978 on April 08, 2026, 06:13:29 AMI wanted to switch my reverse proxy from HAProxy to Caddy over the weekend. It worked fine at first. Then yesterday I noticed that logging in to Synology DSM (username/password/Yubikey as a security key) no longer works. The login is 'interrupted' – but not completely. This means that DSM registers it as an incorrect login.
Did you enable the X-Forwarded-For header in the advanced settings?
Do you proxying the whole domain or a virtual directory?
Is Caddy using the same protocol (http / https) as HAproxy to access the backend?
Hello @virgomann.
Thanks for your post and try to helping me.
QuoteDid you enable the X-Forwarded-For header in the advanced settings?
-> yes, see me screenshot Caddy.jpg
QuoteDo you proxying the whole domain or a virtual directory?
-> Domain
QuoteIs Caddy using the same protocol (http / https) as HAproxy to access the backend?
-> see my pictures HAProxy.jpg, Caddy2.jpg and Caddy3.jpg
Thanks a lot.
Ronny
With the help of a member from another forum, we found the solution:
Additional header configuration:
header_up Host {host}
That solves the problem.
Thanks JohneDoe 😉👍
Quote from: Ronny1978 on April 11, 2026, 07:31:54 AMheader_up Host {host}
Strange. This header already exists in the clients request and Caddy shouldn't remove it by default.
And also HAproxy doen't add it without specific settings.
Quote from: viragomann on April 11, 2026, 09:53:59 AMQuote from: Ronny1978 on April 11, 2026, 07:31:54 AMheader_up Host {host}
Strange. This header already exists in the clients request and Caddy shouldn't remove it by default.
Caddy recently changed how they treat that header when the backend/upstream connection is via HTTPS. See:
https://forum.opnsense.org/index.php?topic=51150.0
I see. Thank you.
I don't run HTTPS backends behind Caddy to be honest. But I do behind HAproxy.
However, I'm wondering, what's the particular meaning of removing the host header or overriding it with something else.
The host header is mostly used differentiator to select the proper virtual server, when running multiple websites on a single backend. The client is sending the proper header value. So why does Caddy change it?
HAproxy doesn't behave like that.
Probably because it expects to handle TLS termination and distribution of sites to different backend by itself, anyway.
However, even if it does that, a reverse proxy should aim for maximum transparency, also with the client info that is passed on.
I like HAproxy better as well. It has some distinguishing features that set it apart and with @TheHellSites tutorial, it works just great for me.
If the backend is HTTPS the host header is now forced to the configured backend URL. I find this quite reasonable - the backend might even rely on SNI ...
Hello Together.
Unfortunately, I didn't receive an email notification that the discussion had continued here. My apologies for that. Unfortunately, my knowledge of reverse proxies, headers and configurations isn't quite up to scratch yet. I'd like to use Authelia or Authentik, but I'm simply struggling to find a guide for HAProxy that I can actually understand.
However, it seems that Caddy does support implementation for these apps. That is why I decided to go with it.
And once again regarding the use of HTTPS behind a reverse proxy: I still don't understand why I should only use HTTP here. It makes no sense to me to downgrade Synology's DSM, Proxmox and the Unifi Controller to HTTP, if that is even possible. I also had the problem at Synology DSM with Yubikey as a hardware token - not if I had used Yubikey as OTP generator.
If you have further information, please let me know. I'm very interested in that.
P.S.
@viragomann: Do you use 2 Reverse Proxys? Caddy AND HAProxy?
You can use HTTPS for the backend, but if you do you must pass the host header from Caddy to the backend, too. I showed how to do that here:
https://forum.opnsense.org/index.php?topic=51150.msg261846#msg261846
Thanks @Patrick. I have seen in the protocoll of caddy another error. I'm not sure, what the error message means.
"warn","ts":"2026-04-16T15:06:23Z","logger":"http.handlers.reverse_proxy","msg":"aborting with incomplete response","upstream":"10.0.80.9:8096","duration":0.043666007,"request":{"remote_ip":"xxx.xxx.xx.xx","remote_port":"64698","client_ip":"xxx.xxx.xx.xx","proto":"HTTP/2.0","method":"GET","host":"jellyfin-nas01.xxxxxx","uri":"/Videos/d98dd6bf-5112-6253-69c2-3e678e867234/stream?container=mkv&static=true&tag=0fee8bb2a7d611d87a8b8fd6a2daf47f&mediaSourceId=d98dd6bf5112625369c23e678e867234&streamOptions=%7B%7D&enableAudioVbrEncoding=true","headers":{"X-Forwarded-For":["xxx.xxx.xx.xx"],"X-Forwarded-Proto":["https"],"Accept-Encoding":["identity"],"User-Agent":["okhttp/4.12.0"],"Icy-Metadata":["1"],"X-Forwarded-Host":["jellyfin-nas01.xxxxxx"],"Via":["2.0 Caddy"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"jellyfin-nas01.xxxxxx","ech":false}},"error":"writing: http2: stream closed"}
How can I correct my configuration?
Thanks a lot again. Have a great rest of the week.
Ronny
Your backend did not provide a complete response - check the log files of your backend.
Hello Patrick.
Thank you for helping me. May be this?
[2026-04-16 14:03:34.284 +00:00] [INF] Sending ForceKeepAlive message to 1 inactive WebSockets.
[2026-04-16 14:03:46.284 +00:00] [INF] Lost 1 WebSockets.
[2026-04-16 14:30:56.131 +00:00] [WRN] WS "10.0.80.1" error receiving data: "The remote party closed the WebSocket connection without completing the close handshake."
[2026-04-16 14:30:56.142 +00:00] [INF] WS "10.0.80.1" closed
[2026-04-16 15:04:41.396 +00:00] [INF] WS "10.0.80.1" request
You configured the host header as linked by me and activated that host header in your handler configuration under "Transport"?
Quote from: Ronny1978 on April 16, 2026, 11:39:18 AMDo you use 2 Reverse Proxys? Caddy AND HAProxy?
Not on the same OPNsense instance.
I use Caddy at home and HAproxy at the company.
Quote from: Ronny1978 on April 16, 2026, 05:20:18 PMI have seen in the protocoll of caddy another error. I'm not sure, what the error message means.
"warn","ts":"2026-04-16T15:06:23Z","logger":"http.handlers.reverse_proxy","msg":"aborting with incomplete response","upstream":"10.0.80.9:8096","duration":0.043666007,"request":{"remote_ip":"xxx.xxx.xx.xx","remote_port":"64698","client_ip":"xxx.xxx.xx.xx","proto":"HTTP/2.0","method":"GET","host":"jellyfin-nas01.xxxxxx","uri":"/Videos/d98dd6bf-5112-6253-69c2-3e678e867234/stream?container=mkv&static=true&tag=0fee8bb2a7d611d87a8b8fd6a2daf47f&mediaSourceId=d98dd6bf5112625369c23e678e867234&streamOptions=%7B%7D&enableAudioVbrEncoding=true","headers":{"X-Forwarded-For":["xxx.xxx.xx.xx"],"X-Forwarded-Proto":["https"],"Accept-Encoding":["identity"],"User-Agent":["okhttp/4.12.0"],"Icy-Metadata":["1"],"X-Forwarded-Host":["jellyfin-nas01.xxxxxx"],"Via":["2.0 Caddy"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"jellyfin-nas01.xxxxxx","ech":false}},"error":"writing: http2: stream closed"}
Seems that the logs show different things.
The Caddy log shows access to the backend using http, while the backend shows a websocket connection. I don't think, that Caddy upgrades the connection to ws.
Also this error might be specific to Jellyfin. So if you have trouble with streaming, maybe you have more luck to find a solution in Jellyfin forum.
Quote from: viragomann on April 16, 2026, 08:14:41 PMThe Caddy log shows access to the backend using http, while the backend shows a websocket connection. I don't think, that Caddy upgrades the connection to ws.
But Caddy does that. That's the beauty of the OPNsense plugin. Here in my network e.g. Apache Guacamole - which definitely needs WS.
Automatically, without any specific setting?
I'm excited!
However, none of my services at home actually need ws.
Quote from: viragomann on April 16, 2026, 11:12:54 PMAutomatically, without any specific setting?
Yes! That's the point. Caddy comes with very reasonable defaults.
Quote from: Patrick M. Hausen on April 16, 2026, 07:50:48 PMYou configured the host header as linked by me and activated that host header in your handler configuration under "Transport"?
Yes, I have.
Quote from: Patrick M. Hausen on April 16, 2026, 11:15:35 PMCaddy kommt mit sehr vernünftigen Standardeinstellungen.
This is, why Caddy will be recommend very often.
Thanks Patrick. At the moment it is only an error in the log. The streams of Jellyfin works fine. But I want to understand the error message and want to try to fix it. It is my personal target. 😁
Have a nice weekend.