Hi
So issue is between Zoraxy (Reverse Proxy written in Go) and OPNsense WebUI. Currently Zoraxy seems to work with most if not all sites except OPNSense.
When trying to add a HTTP Proxy for OPNsense there are a couple of options available:
- [] Allow plain HTTP access # Allow inbound connections without TLS/SSL
- [] Disable Requests Logging # Disable logging for all incoming requests for this hostname
- [] Disable Statistic Collection # Disable collecting statistics for this hostname but keep request logging
- [] Monitor Uptime # Enable active uptime monitor and auto disable upstreams that are offline
- [] Use Sticky Session # Enable stick session on load balancing
- [] Disable Chunked Transfer Encoding # Enable this option if your upstream uses a legacy HTTP server implementation (e.g. Proxmox / opencloud)
- [] Require TLS # Proxy target require HTTPS connection
- [] Skip Verification # Check this if proxy target is using self signed certificates
- [] Skip WebSocket Origin Check # Check this to allow cross-origin websocket requests
It's also possible to set/remove headers on zoraxy>client or zoraxy>origin
I've tried about every possible way and could not get it to work, I seem to be not the only one: https://github.com/tobychui/zoraxy/discussions/228
I've tried this suggestion: https://github.com/opnsense/plugins/issues/4471#issuecomment-2742109624 which did not work and also this one https://github.com/opnsense/plugins/issues/4471#issuecomment-2599639355 by adding the line server.http-parseopts = ( "method-get-body" => "enable" ) to the file: /usr/local/etc/lighttpd/lighttpd.conf I hope that's the correct one? Both of these suggested fixes did not work for zoraxy, I'm still getting the Bad request error:
Here a curl output of the site:
❯❯ curl -v https://opnsense.XXX.dev
* Host opnsense.XXX.dev:443 was resolved.
* IPv6: (none)
* IPv4: 10.10.20.9
* Trying 10.10.20.9:443...
* schannel: disabled automatic use of client certificate
* ALPN: curl offers http/1.1
* ALPN: server accepted http/1.1
* Established connection to opnsense.XXX.dev (10.10.20.9 port 443) from XXX port 57877
* using HTTP/1.x
> GET / HTTP/1.1
> Host: opnsense.XXX.dev
> User-Agent: curl/8.16.0
> Accept: */*
>
* schannel: remote party requests renegotiation
* schannel: renegotiating SSL/TLS connection
* schannel: SSL/TLS connection renegotiated
* Request completely sent off
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: no-store, no-cache, must-revalidate
< Content-Length: 2789
< Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' 'unsafe-eval';
< Content-Type: text/html; charset=UTF-8
< Date: Tue, 09 Dec 2025 09:10:56 GMT
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Pragma: no-cache
< Referrer-Policy: same-origin
< Server: OPNsense
< Set-Cookie: PHPSESSID=XXX; path=/; secure; HttpOnly; SameSite=Lax
< Set-Cookie: PHPSESSID=XXX; path=/; secure; HttpOnly
< Set-Cookie: cookie_test=XXX; expires=Tue, 09 Dec 2025 10:10:56 GMT; Max-Age=3600; path=/; secure; HttpOnly
< Strict-Transport-Security: max-age=31536000
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
<
<!doctype html>
<html lang="en-US" class="no-js">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="robots" content="noindex, nofollow" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="copyright" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Login | OPNsense</title>
<link href="/ui/themes/rebellion/build/css/main.css?v=190a5ea47ddfe74a" rel="stylesheet">
<link href="/ui/themes/rebellion/build/images/favicon.png?v=190a5ea47ddfe74a" rel="shortcut icon">
<script src="/ui/js/jquery-3.5.1.min.js"></script>
<script src="/ui/js/theme.js?v=190a5ea47ddfe74a"></script>
<script>
$( document ).ready(function() {
$.ajaxSetup({
'beforeSend': function(xhr) {
xhr.setRequestHeader("X-CSRFToken", "lsIHDJMZv7fNwZEWS_S0Pw" );
}
});
});
</script>
</head>
<body class="page-login">
<div class="container">
<main class="login-modal-container">
<header class="login-modal-head" style="height:50px;">
<div class="navbar-brand">
<img src="/ui/themes/rebellion/build/images/default-logo.png?v=190a5ea47ddfe74a" height="30" alt="logo" />
</div>
</header>
<div class="login-modal-content">
<div id="inputerrors" class="text-danger"> </div><br />
<form class="clearfix" id="iform" name="iform" method="post" autocomplete="off"><input type="hidden" name="NqqKPVoCWf2rymUXMqttXQ" value="lsIHDJMZv7fNwZEWS_S0Pw" autocomplete="new-password" />
<div class="form-group">
<label for="usernamefld">Username:</label>
<input id="usernamefld" type="text" name="usernamefld" class="form-control user" tabindex="1" autofocus="autofocus" autocapitalize="off" autocorrect="off" />
</div>
<div class="form-group">
<label for="passwordfld">Password:</label>
<input id="passwordfld" type="password" name="passwordfld" class="form-control pwd" tabindex="2" />
</div>
<button type="submit" name="login" value="1" class="btn btn-primary pull-right">Login</button>
</form>
</div>
</main>
<div class="login-foot text-center">
<a target="_blank" href="https://opnsense.org/">OPNsense</a> (c) 2014-2025 <a target="_blank" href="https://www.deciso.com/">Deciso B.V.</a>
</div>
</div>
</body>
</html>
* Connection #0 to host opnsense.XXX.dev:443 left intact
Zoraxy does not seem to have an option to force a specific HTTP version, and as this is not neccessary for any other proxy setup in my homelab (50+ http proxies) I think there should be another way?
It would be very nice if we could get to the bottom of this, thanks!
Shhhh use the caddy plugin on opnsense.
I think i actually was in that zoraxy thread in github.
For caddy all of that is figured out and you also have a nice GUI directly on the OPNsense.
Quote from: Monviech (Cedrik) on December 09, 2025, 01:02:20 PMShhhh use the caddy plugin on opnsense.
I think i actually was in that zoraxy thread in github.
For caddy all of that is figured out and you also have a nice GUI directly on the OPNsense.
Hi,
Thanks for the suggestion, but I'd prefer to stick with Zoraxy as it's working perfectly for my other services. Switching to Caddy just for OPNsense feels like avoiding the root cause rather than fixing it.
The issue seems to be lighttpd rejecting Zoraxy's requests with a 400 Bad Request, while direct curl access works fine?
Any ideas if my attempt for changing the lighttpd config was the correct file? Or any idea which specific headers could interfere here?
Also see this reply from the maintainer: https://github.com/tobychui/zoraxy/discussions/228#discussioncomment-12095120
According to this comment: https://github.com/opnsense/plugins/issues/4471#issuecomment-2602517275
It seems like Opnsense got a PR to disable HTTP/3, so this issue should be resolved now? Yet for zoraxy "the issue" still appears.
You have to enable verbose logging in the lighttpd server and find out the exact error message why it rejects the connection.
The OPNsense PR was from me exactly for the caddy plugin, it has nothing to do with lighttpd running in OPNsense core.
I see.
I'm not particularly sure if this is the correct way, but I added the following lines to the file: /usr/local/etc/lighttpd/lighttpd.conf
debug.log-request-header = "enable"
debug.log-response-header = "enable"
Then running:
/usr/local/etc/rc.restart_webgui
I could see the following when selecting Debug and Informational:
2025-12-09T15:15:36
Informational
lighttpd
10.10.20.9 opnsense.XXX.dev - [09/Dec/2025:15:15:36 +0100] "GET / HTTP/2.0" 400 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0"
2025-12-09T15:15:36
Informational
lighttpd
10.10.20.9 opnsense.XXX.dev - [09/Dec/2025:15:15:36 +0100] "GET / HTTP/2.0" 400 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0"
2025-12-09T15:15:34
Informational
lighttpd
10.10.20.9 opnsense.XXX.dev - [09/Dec/2025:15:15:34 +0100] "GET / HTTP/2.0" 400 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0"
2025-12-09T15:15:33
Informational
lighttpd
10.10.20.9 opnsense.XXX.dev - [09/Dec/2025:15:15:33 +0100] "GET / HTTP/2.0" 400 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0"
But that does not really look like "debug" info to me, any ideas what I'm missing?
I don't remember it was a while ago but maybe here?
/usr/local/etc/lighttpd/conf.d/debug.conf
The error log should be redirected to syslog since thats defined already in the startup of lighttpd
https://redmine.lighttpd.net/projects/1/wiki/Server_errorlogDetails
Only a minor observation, but I could access at least the / URI with curl - IFF I call "curl -vk --http1.1". You cannot try this on any modern browser, since you cannot force HTTP/1.1 any more with TLS/ALPN.
Also, I tried modifying HTTP headers to no avail. There seems to be something way off with the way Zoraxy translates frontend calls to backend.
Other reverse proxies do this just fine, like HAproxy or Caddy.
I can't seem to get the debug lighttpd working.
I updated the following:
/usr/local/etc/lighttpd/conf.d/debug.con
-> uncommented: debug.log-response-header = "enable"
debug.log-request-header = "enable"
In the file: /usr/local/etc/lighttpd/conf.d/access_log.conf
I changed syslog-level from 6 to 7
accesslog.syslog-level = 7
I uncommented this line:
accesslog.use-syslog = "enable"
and commented out:
accesslog.filename = log_root + "/access.log"
After that I restarted lighttpd:
configctl webgui restart
/usr/local/etc/rc.restart_webgui
I also rebooted the node.
Though after doing all that, I could not see any additional logfiles being written to /var/log/lighttpd/ and the default one still only contains the informational data:
2025-12-09T21:56:04
Informational
lighttpd
10.10.20.9 opnsense.XXX.dev - [09/Dec/2025:21:56:04 +0100] "GET / HTTP/2.0" 400 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0"
I also checked dmesg, but that did also not contain the debug logs of lighttpd, maybe this is something trivial that I'm missing with my limited FreeBSD knowledge.
Maybe someone knowns what I'm doing wrong?
I also did some further tests with curl on http2/ http1.1 if this sparks any idea for someone reading this?
Here directly via IP using http2
⚡tobia ❯❯ ./curl -vk --http2 https://10.50.20.1
Note: Using embedded CA bundle (230814 bytes)
Note: Using embedded CA bundle, for proxies (230814 bytes)
* Trying 10.50.20.1:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* SSL Trust: peer verification disabled
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: CN=OPNsense.localdomain; C=NL; ST=Zuid-Holland; L=Middelharnis; O=OPNsense self-signed web certificate
* start date: May 12 14:22:51 2024 GMT
* expire date: Jun 13 14:22:51 2025 GMT
* issuer: CN=OPNsense.localdomain; C=NL; ST=Zuid-Holland; L=Middelharnis; O=OPNsense self-signed web certificate
* Certificate level 0: Public key type ? (4096/128 Bits/secBits), signed using sha256WithRSAEncryption
* SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
* SSL certificate verification failed, continuing anyway!
* Established connection to 10.50.20.1 (10.50.20.1 port 443) from 192.168.1.200 port 53262
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://10.50.20.1/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: 10.50.20.1]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.17.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: 10.50.20.1
> User-Agent: curl/8.17.0
> Accept: */*
>
* Request completely sent off
< HTTP/2 200
< set-cookie: PHPSESSID=XXX; path=/; secure; HttpOnly; SameSite=Lax
< set-cookie: PHPSESSID=XXX; path=/; secure; HttpOnly
< set-cookie: cookie_test=XXX; expires=Tue, 09 Dec 2025 21:21:34 GMT; Max-Age=3600; path=/; secure; HttpOnly
< expires: Thu, 19 Nov 1981 08:52:00 GMT
< cache-control: no-store, no-cache, must-revalidate
< pragma: no-cache
< content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' 'unsafe-eval';
< x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< referrer-policy: same-origin
< content-type: text/html; charset=UTF-8
< strict-transport-security: max-age=31536000
< accept-ranges: bytes
< content-length: 2789
< date: Tue, 09 Dec 2025 20:21:33 GMT
< server: OPNsense
<
<!doctype html>
<html lang="en-US" class="no-js">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="robots" content="noindex, nofollow" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="copyright" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Login | OPNsense</title>
<link href="/ui/themes/rebellion/build/css/main.css?v=190a5ea47ddfe74a" rel="stylesheet">
<link href="/ui/themes/rebellion/build/images/favicon.png?v=190a5ea47ddfe74a" rel="shortcut icon">
<script src="/ui/js/jquery-3.5.1.min.js"></script>
<script src="/ui/js/theme.js?v=190a5ea47ddfe74a"></script>
<script>
$( document ).ready(function() {
$.ajaxSetup({
'beforeSend': function(xhr) {
xhr.setRequestHeader("X-CSRFToken", "Mg_cQQ_BwGrt5cZfGZCH2Q" );
}
});
});
</script>
</head>
<body class="page-login">
<div class="container">
<main class="login-modal-container">
<header class="login-modal-head" style="height:50px;">
<div class="navbar-brand">
<img src="/ui/themes/rebellion/build/images/default-logo.png?v=190a5ea47ddfe74a" height="30" alt="logo" />
</div>
</header>
<div class="login-modal-content">
<div id="inputerrors" class="text-danger"> </div><br />
<form class="clearfix" id="iform" name="iform" method="post" autocomplete="off"><input type="hidden" name="QdgI-W_IbDP7V2LuCt37pw" value="Mg_cQQ_BwGrt5cZfGZCH2Q" autocomplete="new-password" />
<div class="form-group">
<label for="usernamefld">Username:</label>
<input id="usernamefld" type="text" name="usernamefld" class="form-control user" tabindex="1" autofocus="autofocus" autocapitalize="off" autocorrect="off" />
</div>
<div class="form-group">
<label for="passwordfld">Password:</label>
<input id="passwordfld" type="password" name="passwordfld" class="form-control pwd" tabindex="2" />
</div>
<button type="submit" name="login" value="1" class="btn btn-primary pull-right">Login</button>
</form>
</div>
</main>
<div class="login-foot text-center">
<a target="_blank" href="https://opnsense.org/">OPNsense</a> (c) 2014-2025 <a target="_blank" href="https://www.deciso.com/">Deciso B.V.</a>
</div>
</div>
</body>
</html>
* Connection #0 to host 10.50.20.1:443 left intact
Here using zoraxy with http2
⚡tobia ❯❯ ./curl -vk --http2 https://opnsense.XXX.dev
Note: Using embedded CA bundle (230814 bytes)
Note: Using embedded CA bundle, for proxies (230814 bytes)
* Host opnsense.XXX.dev:443 was resolved.
* IPv6: (none)
* IPv4: 10.10.20.9
* Trying 10.10.20.9:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* SSL Trust: peer verification disabled
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
* subject: CN=*.XXX.dev
* start date: Nov 14 12:53:44 2025 GMT
* expire date: Feb 12 12:53:43 2026 GMT
* issuer: C=US; O=Let's Encrypt; CN=R12
* Certificate level 0: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 1: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
* SSL certificate verification failed, continuing anyway!
* Established connection to opnsense.XXX.dev (10.10.20.9 port 443) from 192.168.1.200 port 53371
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://opnsense.XXX.dev/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: opnsense.XXX.dev]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.17.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: opnsense.XXX.dev
> User-Agent: curl/8.17.0
> Accept: */*
>
* Request completely sent off
< HTTP/2 400
< content-type: text/html
< date: Tue, 09 Dec 2025 20:24:22 GMT
< server: OPNsense
< content-length: 162
<
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>400 Bad Request</title>
</head>
<body>
<h1>400 Bad Request</h1>
</body>
</html>
* Connection #0 to host opnsense.XXX.dev:443 left intact
Here directly via IP using http1.1
⚡tobia ❯❯ ./curl -vk --http1.1 https://10.50.20.1
Note: Using embedded CA bundle (230814 bytes)
Note: Using embedded CA bundle, for proxies (230814 bytes)
* Trying 10.50.20.1:443...
* ALPN: curl offers http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* SSL Trust: peer verification disabled
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / [blank] / UNDEF
* ALPN: server accepted http/1.1
* Server certificate:
* subject: CN=OPNsense.localdomain; C=NL; ST=Zuid-Holland; L=Middelharnis; O=OPNsense self-signed web certificate
* start date: May 12 14:22:51 2024 GMT
* expire date: Jun 13 14:22:51 2025 GMT
* issuer: CN=OPNsense.localdomain; C=NL; ST=Zuid-Holland; L=Middelharnis; O=OPNsense self-signed web certificate
* Certificate level 0: Public key type ? (4096/128 Bits/secBits), signed using sha256WithRSAEncryption
* SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
* SSL certificate verification failed, continuing anyway!
* Established connection to 10.50.20.1 (10.50.20.1 port 443) from 192.168.1.200 port 53497
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 10.50.20.1
> User-Agent: curl/8.17.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Set-Cookie: PHPSESSID=XXX; path=/; secure; HttpOnly; SameSite=Lax
< Set-Cookie: PHPSESSID=XXX; path=/; secure; HttpOnly
< Set-Cookie: cookie_test=XXX; expires=Tue, 09 Dec 2025 21:28:14 GMT; Max-Age=3600; path=/; secure; HttpOnly
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' 'unsafe-eval';
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Referrer-Policy: same-origin
< Content-type: text/html; charset=UTF-8
< Strict-Transport-Security: max-age=31536000
< Accept-Ranges: bytes
< Content-Length: 2789
< Date: Tue, 09 Dec 2025 20:28:14 GMT
< Server: OPNsense
<
<!doctype html>
<html lang="en-US" class="no-js">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="robots" content="noindex, nofollow" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="copyright" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Login | OPNsense</title>
<link href="/ui/themes/rebellion/build/css/main.css?v=190a5ea47ddfe74a" rel="stylesheet">
<link href="/ui/themes/rebellion/build/images/favicon.png?v=190a5ea47ddfe74a" rel="shortcut icon">
<script src="/ui/js/jquery-3.5.1.min.js"></script>
<script src="/ui/js/theme.js?v=190a5ea47ddfe74a"></script>
<script>
$( document ).ready(function() {
$.ajaxSetup({
'beforeSend': function(xhr) {
xhr.setRequestHeader("X-CSRFToken", "QHvHZSgsipJdn7QCOlywiA" );
}
});
});
</script>
</head>
<body class="page-login">
<div class="container">
<main class="login-modal-container">
<header class="login-modal-head" style="height:50px;">
<div class="navbar-brand">
<img src="/ui/themes/rebellion/build/images/default-logo.png?v=190a5ea47ddfe74a" height="30" alt="logo" />
</div>
</header>
<div class="login-modal-content">
<div id="inputerrors" class="text-danger"> </div><br />
<form class="clearfix" id="iform" name="iform" method="post" autocomplete="off"><input type="hidden" name="H6oJ5FEb0wUfRprByrj2DQ" value="QHvHZSgsipJdn7QCOlywiA" autocomplete="new-password" />
<div class="form-group">
<label for="usernamefld">Username:</label>
<input id="usernamefld" type="text" name="usernamefld" class="form-control user" tabindex="1" autofocus="autofocus" autocapitalize="off" autocorrect="off" />
</div>
<div class="form-group">
<label for="passwordfld">Password:</label>
<input id="passwordfld" type="password" name="passwordfld" class="form-control pwd" tabindex="2" />
</div>
<button type="submit" name="login" value="1" class="btn btn-primary pull-right">Login</button>
</form>
</div>
</main>
<div class="login-foot text-center">
<a target="_blank" href="https://opnsense.org/">OPNsense</a> (c) 2014-2025 <a target="_blank" href="https://www.deciso.com/">Deciso B.V.</a>
</div>
</div>
</body>
</html>
* Connection #0 to host 10.50.20.1:443 left intact
Here using http1.1 and directly via IP:
⚡tobia ❯❯ ./curl -vk --http1.1 https://opnsense.XXX.dev
Note: Using embedded CA bundle (230814 bytes)
Note: Using embedded CA bundle, for proxies (230814 bytes)
* Host opnsense.XXX.dev:443 was resolved.
* IPv6: (none)
* IPv4: 10.10.20.9
* Trying 10.10.20.9:443...
* ALPN: curl offers http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* SSL Trust: peer verification disabled
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256 / [blank] / UNDEF
* ALPN: server accepted http/1.1
* Server certificate:
* subject: CN=*.XXX.dev
* start date: Nov 14 12:53:44 2025 GMT
* expire date: Feb 12 12:53:43 2026 GMT
* issuer: C=US; O=Let's Encrypt; CN=R12
* Certificate level 0: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* Certificate level 1: Public key type ? (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
* SSL certificate verification failed, continuing anyway!
* Established connection to opnsense.XXX.dev (10.10.20.9 port 443) from 192.168.1.200 port 53562
* using HTTP/1.x
> GET / HTTP/1.1
> Host: opnsense.XXX.dev
> User-Agent: curl/8.17.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: no-store, no-cache, must-revalidate
< Content-Length: 2789
< Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' 'unsafe-eval';
< Content-Type: text/html; charset=UTF-8
< Date: Tue, 09 Dec 2025 20:30:14 GMT
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Pragma: no-cache
< Referrer-Policy: same-origin
< Server: OPNsense
< Set-Cookie: PHPSESSID=XXX; path=/; secure; HttpOnly; SameSite=Lax
< Set-Cookie: PHPSESSID=XXX; path=/; secure; HttpOnly
< Set-Cookie: cookie_test=XXX; expires=Tue, 09 Dec 2025 21:30:14 GMT; Max-Age=3600; path=/; secure; HttpOnly
< Strict-Transport-Security: max-age=31536000
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
<
<!doctype html>
<html lang="en-US" class="no-js">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="robots" content="noindex, nofollow" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="copyright" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Login | OPNsense</title>
<link href="/ui/themes/rebellion/build/css/main.css?v=190a5ea47ddfe74a" rel="stylesheet">
<link href="/ui/themes/rebellion/build/images/favicon.png?v=190a5ea47ddfe74a" rel="shortcut icon">
<script src="/ui/js/jquery-3.5.1.min.js"></script>
<script src="/ui/js/theme.js?v=190a5ea47ddfe74a"></script>
<script>
$( document ).ready(function() {
$.ajaxSetup({
'beforeSend': function(xhr) {
xhr.setRequestHeader("X-CSRFToken", "vCn25poe5-7duF4xaGVFqg" );
}
});
});
</script>
</head>
<body class="page-login">
<div class="container">
<main class="login-modal-container">
<header class="login-modal-head" style="height:50px;">
<div class="navbar-brand">
<img src="/ui/themes/rebellion/build/images/default-logo.png?v=190a5ea47ddfe74a" height="30" alt="logo" />
</div>
</header>
<div class="login-modal-content">
<div id="inputerrors" class="text-danger"> </div><br />
<form class="clearfix" id="iform" name="iform" method="post" autocomplete="off"><input type="hidden" name="Y-eTdSKnnMVkTXU-RgdR8g" value="vCn25poe5-7duF4xaGVFqg" autocomplete="new-password" />
<div class="form-group">
<label for="usernamefld">Username:</label>
<input id="usernamefld" type="text" name="usernamefld" class="form-control user" tabindex="1" autofocus="autofocus" autocapitalize="off" autocorrect="off" />
</div>
<div class="form-group">
<label for="passwordfld">Password:</label>
<input id="passwordfld" type="password" name="passwordfld" class="form-control pwd" tabindex="2" />
</div>
<button type="submit" name="login" value="1" class="btn btn-primary pull-right">Login</button>
</form>
</div>
</main>
<div class="login-foot text-center">
<a target="_blank" href="https://opnsense.org/">OPNsense</a> (c) 2014-2025 <a target="_blank" href="https://www.deciso.com/">Deciso B.V.</a>
</div>
</div>
</body>
</html>
* Connection #0 to host opnsense.XXX.dev:443 left intact
Yup, as I said, the moment you connect via HTTP/2 to Zoraxy with OpnSense as the backend, it does not work any more.
There must be something that is special on the backend when that happens which OpnSense does not like. However, I have found no way of setting or deleting HTTP headers on the frontend not could I find a setting within Zoraxy to change it. I used many combinations of advanced settings, like deleting headers that pertain to HTTP/2, to no avail.
The only approach I can think of is to dump all request data on the HTTPS backend - but that is not easy, since you cannot easily use tcpdump for that, you will need to have the web server (or Zoraxy as the client) do it. Zoraxy itself is relatively fresh - there is a bug open for this problem and there are no means to log requests, either (that is a feature request).
Yeah seems like this is somewhat out of my league and power, but I'm happy to provide/do any testing for this to be resolved, as this is kind of the online major pain-point I currently have in my homelab.
On a side note, on this thread, I'm also helping to troubleshoot Forward Auth in zoraxy when using authentik: https://github.com/tobychui/zoraxy/issues/895#issuecomment-3621381598
Here there is a image of zoraxy that logs far more verbose data, maybe this is in any way helpful?
I mean you could still use caddy which is more mature in general which will fix most pain points you will have.
It also supports Authentik and I know quite some people using it that way.
If Zoraxy is your personal quest though to improve, go ahead. Not much I can do though.
If I remember the debug logging in lighttpd was also a major pita for me, I disabled syslogging and manually started it and looked at stdout in the console.