Caddy and OPNsense Help Requested By Beginner

1. The problem I’m having:

Hello Caddy Community,

I’m currently working on setting up a Nextcloud instance hosted on my TrueNAS server to be accessible from outside my network. I have a setup that includes a separate machine running OPNsense, and I’m trying to use Caddy as a reverse proxy on my OPNsense to achieve this. I’m currently facing an issue where I cannot access my Nextcloud site externally. Internally, I am able to access the site but it shows an insecure warning before allowing me to proceed. It then does not reflect the domain on my browser but my TrueNAS IP followed by the port. I’m unsure if there’s something I’ve missed in the configuration or if there’s an issue with how I’ve set things up. I’m looking for advice on troubleshooting steps or configuration adjustments that could help resolve this access issue. Any insights or suggestions from those who have successfully set up a similar configuration would be greatly appreciated!

Thank you in advance for your help.

2. Error messages and/or full log output:

2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"45.83.126.4","remote_port":"33131","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"managed":false,"expiration":"2040-03-06T11:20:01Z","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800"}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"custom certificate selection results","identifier":"nc.tzbcloud.com","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"managed":false,"issuer_key":"","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800"}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"choosing certificate","identifier":"nc.tzbcloud.com","num_choices":1}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"no matching certificate; will choose from all certificates","identifier":"nc.tzbcloud.com"}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"events","msg":"event","name":"tls_get_certificate","id":"e9e18994-4096-4428-b856-95b104f77014","origin":"tls","data":{"client_hello":{"CipherSuites":[4865,4867,4866],"ServerName":"nc.tzbcloud.com","SupportedCurves":[4588,29,23,24,25],"SupportedPoints":null,"SignatureSchemes":[1027,1283,1539,515,2052,2053,2054,1025,1281,1537,513],"SupportedProtos":["h3"],"SupportedVersions":[772],"RemoteAddr":{"IP":"45.83.126.4","Port":33131,"Zone":""},"LocalAddr":{"IP":"138.75.205.192","Port":443,"Zone":""}}}}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"192.168.1.50:30027","duration":0.037979546,"request":{"remote_ip":"45.83.126.4","remote_port":"35015","client_ip":"45.83.126.4","proto":"HTTP/2.0","method":"GET","host":"nc.tzbcloud.com","uri":"/","headers":{"Priority":["u=0, i"],"Te":["trailers"],"Sec-Fetch-Site":["none"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"],"Accept-Language":["en-US,en;q=0.5"],"Sec-Fetch-User":["?1"],"Accept-Encoding":["gzip, deflate, br, zstd"],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0"],"Upgrade-Insecure-Requests":["1"],"Sec-Fetch-Mode":["navigate"],"Dnt":["1"],"Sec-Gpc":["1"],"X-Forwarded-Host":["nc.tzbcloud.com"],"Sec-Fetch-Dest":["document"],"X-Forwarded-For":["45.83.126.4"],"X-Forwarded-Proto":["https"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"nc.tzbcloud.com"}},"headers":{"Server":["nginx/1.27.4"],"X-Content-Type-Options":["nosniff"],"Location":["https://192.168.1.50:30027/login"],"X-Frame-Options":["SAMEORIGIN"],"Content-Security-Policy":["default-src 'self'; script-src 'self' 'nonce-sVniZvGGDgcbOD/9MNEhsK/NTFybDLdxc5bZurRsvdM='; style-src 'self' 'unsafe-inline'; frame-src *; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src *; object-src 'none'; base-uri 'self';"],"Strict-Transport-Security":["max-age=15552000; includeSubDomains; preload"],"Content-Type":["text/html; charset=UTF-8"],"Content-Length":["0"],"X-Permitted-Cross-Domain-Policies":["none"],"X-Robots-Tag":["noindex, nofollow"],"X-Powered-By":["PHP/8.3.17"],"Set-Cookie":["REDACTED"],"Date":["Mon, 10 Mar 2025 13:09:25 GMT"],"X-Xss-Protection":["1; mode=block"],"Referrer-Policy":["no-referrer"]},"status":302}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"http.handlers.reverse_proxy","msg":"selected upstream","dial":"192.168.1.50:30027","total_upstreams":1}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"45.83.126.4","remote_port":"35015","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"managed":false,"expiration":"2040-03-06T11:20:01Z","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800"}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"custom certificate selection results","identifier":"nc.tzbcloud.com","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"managed":false,"issuer_key":"","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800"}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"choosing certificate","identifier":"nc.tzbcloud.com","num_choices":1}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"tls.handshake","msg":"no matching certificate; will choose from all certificates","identifier":"nc.tzbcloud.com"}	
2025-03-10T21:09:25	Debug	caddy	"debug","ts":"2025-03-10T13:09:25Z","logger":"events","msg":"event","name":"tls_get_certificate","id":"0e5ee900-3d52-4925-9ee8-80f4e79f6237","origin":"tls","data":{"client_hello":{"CipherSuites":[4865,4867,4866,49195,49199,52393,52392,49196,49200,49162,49161,49171,49172,156,157,47,53],"ServerName":"nc.tzbcloud.com","SupportedCurves":[4588,29,23,24,25,256,257],"SupportedPoints":"AA==","SignatureSchemes":[1027,1283,1539,2052,2053,2054,1025,1281,1537,515,513],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771],"RemoteAddr":{"IP":"45.83.126.4","Port":35015,"Zone":""},"LocalAddr":{"IP":"138.75.205.192","Port":443,"Zone":""}}}}	
2025-03-10T21:09:22	Error	caddy	"debug","ts":"2025-03-10T13:09:22Z","logger":"http.stdlib","msg":"http: TLS handshake error from 45.83.126.4:33988: remote error: tls: unknown certificate authority"}	
2025-03-10T21:09:22	Debug	caddy	"debug","ts":"2025-03-10T13:09:22Z","logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"45.83.126.4","remote_port":"33988","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"managed":false,"expiration":"2040-03-06T11:20:01Z","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800"}	
2025-03-10T21:09:22	Debug	caddy	"debug","ts":"2025-03-10T13:09:22Z","logger":"tls.handshake","msg":"custom certificate selection results","identifier":"nc.tzbcloud.com","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"managed":false,"issuer_key":"","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800"}	
2025-03-10T21:09:22	Debug	caddy	"debug","ts":"2025-03-10T13:09:22Z","logger":"tls.handshake","msg":"choosing certificate","identifier":"nc.tzbcloud.com","num_choices":1}	
2025-03-10T21:09:22	Debug	caddy	"debug","ts":"2025-03-10T13:09:22Z","logger":"tls.handshake","msg":"no matching certificate; will choose from all certificates","identifier":"nc.tzbcloud.com"}	
2025-03-10T21:09:22	Debug	caddy	"debug","ts":"2025-03-10T13:09:22Z","logger":"events","msg":"event","name":"tls_get_certificate","id":"1672c9d3-8305-43d7-800a-9a333ba6710d","origin":"tls","data":{"client_hello":{"CipherSuites":[4865,4867,4866,49195,49199,52393,52392,49196,49200,49162,49161,49171,49172,156,157,47,53],"ServerName":"nc.tzbcloud.com","SupportedCurves":[4588,29,23,24,25,256,257],"SupportedPoints":"AA==","SignatureSchemes":[1027,1283,1539,2052,2053,2054,1025,1281,1537,515,513],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771],"RemoteAddr":{"IP":"45.83.126.4","Port":33988,"Zone":""},"LocalAddr":{"IP":"138.75.205.192","Port":443,"Zone":""}}}}	
2025-03-10T21:09:12	Debug	caddy	"debug","ts":"2025-03-10T13:09:12Z","logger":"dynamic_dns","msg":"no IP address change; no update needed"}	
2025-03-10T21:09:12	Debug	caddy	"debug","ts":"2025-03-10T13:09:12Z","logger":"dynamic_dns.ip_sources.simple_http","msg":"lookup","type":"IPv4","endpoint":"https://icanhazip.com","ip":"138.75.205.192"}	
2025-03-10T21:09:12	Debug	caddy	"debug","ts":"2025-03-10T13:09:12Z","logger":"dynamic_dns","msg":"looked up current IPs from DNS","lastIPs":{"*.tzbcloud.com":{"A":["138.75.205.192"],"AAAA":[""]}}}	
2025-03-10T21:09:12	Informational	caddy	"info","ts":"2025-03-10T13:09:12Z","logger":"dynamic_dns","msg":"domain not found in DNS","domain":"*.tzbcloud.com","type":"AAAA"}	
2025-03-10T21:09:12	Debug	caddy	"debug","ts":"2025-03-10T13:09:12Z","logger":"dynamic_dns","msg":"found DNS record","type":"A","name":"*","zone":"tzbcloud.com","value":"138.75.205.192"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"tls","msg":"finished cleaning storage units"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/var/db/caddy/data/caddy","instance":"e2bb264c-3556-4531-9f2b-ad4fd02a3496","try_again":"2025-03-11T13:09:10Z","try_again_in":86399.999999456}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","msg":"serving initial configuration"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","msg":"autosaved config (load with --resume flag)","file":"/var/db/caddy/config/caddy/autosave.json"}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"dynamic_dns","msg":"beginning IP address check"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}	
2025-03-10T21:09:10	Warning	caddy	"warn","ts":"2025-03-10T13:09:10Z","logger":"http","msg":"HTTP/3 skipped because it requires TLS","network":"tcp","addr":":80"}	
2025-03-10T21:09:10	Warning	caddy	"warn","ts":"2025-03-10T13:09:10Z","logger":"http","msg":"HTTP/2 skipped because it requires TLS","network":"tcp","addr":":80"}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"http","msg":"starting server loop","address":"[::]:80","tls":false,"http3":false}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"http","msg":"starting server loop","address":"[::]:443","tls":true,"http3":false}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{}]}},"http":{"grace_period":10000000000,"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","transport":{"protocol":"http","tls":{"insecure_skip_verify":true}},"upstreams":[{"dial":"192.168.1.50:30027"}]}]}]}]}]}],"match":[{"host":["nc.tzbcloud.com"]}]}]}],"terminal":true}],"tls_connection_policies":[{"match":{"sni":["*.tzbcloud.com"]},"certificate_selection":{"any_tag":["cert0"]}},{}],"automatic_https":{},"protocols":["h1","h2","h3"]}}}}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"http.auto_https","msg":"skipping automatic certificate management because one or more matching certificates are already loaded","domain":"*.tzbcloud.com","server_name":"srv0"}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"tls.cache","msg":"added certificate to cache","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"expiration":"2040-03-06T11:20:01Z","managed":false,"issuer_key":"","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800","cache_size":1,"cache_capacity":10000}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"events","msg":"event","name":"cached_unmanaged_cert","id":"538774a4-03c7-4cc2-92f5-5fa1e9a6684f","origin":"tls","data":{"sans":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"]}}	
2025-03-10T21:09:10	Error	caddy	"warn","ts":"2025-03-10T13:09:10Z","logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [cloudflare origin certificate *.tzbcloud.com tzbcloud.com]: no URL to issuing certificate"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0x870651980"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"admin","msg":"admin endpoint started","address":"unix//var/run/caddy/caddy.sock|0220","enforce_origin":false,"origins":["","//127.0.0.1","//::1"]}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"tls.cache.maintenance","msg":"stopped background certificate maintenance","cache":"0x86c6b4000"}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{}]}},"http":{"grace_period":10000000000,"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","transport":{"protocol":"http","tls":{"insecure_skip_verify":true}},"upstreams":[{"dial":"192.168.1.50:30027"}]}]}]}]}]}],"match":[{"host":["nc.tzbcloud.com"]}]}]}],"terminal":true}],"tls_connection_policies":[{"match":{"sni":["*.tzbcloud.com"]},"certificate_selection":{"any_tag":["cert0"]}},{}],"automatic_https":{},"protocols":["h1","h2","h3"]}}}}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"http.auto_https","msg":"skipping automatic certificate management because one or more matching certificates are already loaded","domain":"*.tzbcloud.com","server_name":"srv0"}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"tls.cache","msg":"added certificate to cache","subjects":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"],"expiration":"2040-03-06T11:20:01Z","managed":false,"issuer_key":"","hash":"1c03aa26c44d412a49774736da45e43da31e30fec146dd1d90da56c305105800","cache_size":1,"cache_capacity":10000}	
2025-03-10T21:09:10	Debug	caddy	"debug","ts":"2025-03-10T13:09:10Z","logger":"events","msg":"event","name":"cached_unmanaged_cert","id":"0a5781f4-2725-4135-8f8e-56776f481d29","origin":"tls","data":{"sans":["cloudflare origin certificate","*.tzbcloud.com","tzbcloud.com"]}}	
2025-03-10T21:09:10	Error	caddy	"warn","ts":"2025-03-10T13:09:10Z","logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [cloudflare origin certificate *.tzbcloud.com tzbcloud.com]: no URL to issuing certificate"}	
2025-03-10T21:09:10	Informational	caddy	"info","ts":"2025-03-10T13:09:10Z","logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0x86c6b4000"}

3. Caddy version:

os-caddy 1.8.2

4. How I installed and ran Caddy:

a. System environment:

OPNsense 25.1.2-amd64
FreeBSD 14.2-RELEASE-p2
OpenSSL 3.0.16

b. Command:

Installed from System > Firmware > Plugins

c. My complete Caddy config:

# DO NOT EDIT THIS FILE -- OPNsense auto-generated file


# caddy_user=root

# Global Options
{
	log {
		output net unixgram//var/run/caddy/log.sock {
		}
		format json {
			time_format rfc3339
		}
	}

	servers {
		protocols h1 h2 h3
	}

	dynamic_dns {
		provider cloudflare **Redacted**
		domains {
			tzbcloud.com *
		}
		versions ipv4
	}

	grace_period 10s
	import /usr/local/etc/caddy/caddy.d/*.global
}

# Reverse Proxy Configuration


# Reverse Proxy Domain: "b1aa3c42-65f6-44e4-bdc2-6972b44d47af"
*.tzbcloud.com {
	tls /var/db/caddy/data/caddy/certificates/temp/67ced8762406e.pem /var/db/caddy/data/caddy/certificates/temp/67ced8762406e.key

	@0467fbba-3ef2-4167-a674-b56e4ff4637d {
		host nc.tzbcloud.com
	}
	handle @0467fbba-3ef2-4167-a674-b56e4ff4637d {
		handle {
			reverse_proxy https://192.168.1.50:30027 {
				transport http {
					tls_insecure_skip_verify
				}
			}
		}
	}
}

import /usr/local/etc/caddy/caddy.d/*.conf

d. What I have done so far

  1. I have a domain registered with Cloudflare, which is configured for full (strict) SSL.
  2. I’ve generated an origin certificate from Cloudflare and imported it into OPNsense under System > Trust > Certificates, using the PEM and key text provided by Cloudflare.
  3. I followed the Caddy setup guide provided by the OPNsense documentation: OPNsense Caddy Guide. Mainly “Prepare OPNsense for Caddy After Installation”, “Creating a Simple Reverse Proxy”, “Dynamic DNS” and “Wildcard Domain with Subdomains”.
  4. I have set up DNS provider using Cloudflare API.

First things first: Redact your Cloudflare API token. You don’t want to publicly post that.

Also, that’s an insanely old version of Caddy. You should update it. Are you using Nextcloud AIO? How is Nextcloud configured to run?


I’m not quite sure why it has a handle directive inside the handle directive. Remove the handle inside the block.


That’s expected because you’re telling Caddy to ignore verifying the certificate. Nextcloud is using its own internal certificate. If you’re following Nextcloud instructions, that seems to be the domain for the AIO instance since you are using a certificate from Nextcloud. If it isn’t, I haven’t worked with the old Nextcloud because Nextcloud does not support the image anymore for Docker. They instead only work on the Nextcloud AIO image.


I need to know what exactly you are reverse_proxying to help you with that.

The latest caddy version is used in the OPNsense. They posted the plugin version which is a different package depending on the port.

Port:

Plugin:


The empty handle is in there due to the way the jinja2 template generation writes the Caddyfile.

It’s a valid configuration. It could be improved not to print it when certain conditions are met but there’s not much benefit in fixing this at the moment. Just to explain why the empty handle is there.

1 Like