Tutorial: Caddy (Reverse Proxy) + Let's Encrypt Certificates + Dynamic DNS

Started by Monviech (Cedrik), February 09, 2024, 01:31:44 PM

Previous topic - Next topic
If you do a dig or nslookup and your FQDNs always point to the correct IP address with your current setup, you do not need to configure dynamic dns in the caddy plugin, it's that simple.
Hardware:
DEC740

Im having a heck of a time getting opnsense caddy plugin working with immich. The logs are stating that CORS is failing. Immich states that all i should need to do is set the reverse_proxy (https://immich.app/docs/administration/reverse-proxy#caddy-example-config) which i have done but it fails on CORS requests. I was able to add 4 or 5 additional headers (more here: https://forum.opnsense.org/index.php?topic=46177.msg239034#msg239034) but its stating that the preflight response was a non 2xx response. Any help would be greatly appreciated.

Just spent a couple hours debugging a reload(not restart) of the caddy service from the acme client and gave up.
I'll try to briefly summarize the problem/observed behaviour.
System is on 25.1.8_1
Caddy package is 2.0.1
Caddy is setup to run as www and runs nicely.

- Checking /var/run/caddy after restarting the service via GUI shows caddy.sock owned by www:www with 0220
- Applying caddy config from GUI changes that to root:www with 0220
- Restarting the service via GUI changes that back to www:www with 0220

So far so good besides the strange ownership discrepancies between applying config and restarting via GUI.

Setting up an automation in ACME to reload(!) caddy is where things get strange and I can't figure out why.
- Reload fails with log:
"loading config: loading new config: starting caddy administration endpoint: unable to set permissions (--w--w----) on /var/run/caddy/caddy.sock: chmod /var/run/caddy/caddy.sock: operation not permitted"
- Ownership/permission on caddy.sock after running that automation are root:www with 0220 regardless what they where before.

If I use a caddy restart automation in ACME, everything is fine, ownership/permissions after run are www:www with 0220.

As soon as the ownership/permission on caddy.sock is root:www with 0220 running "service caddy reloadssl" fails with the same error, "service caddy restart" reverts ist back to www:www with 0200 after which "service caddy reloadssl" also works fine from the CLI.
So something goes wrong when "service caddy reloadssl" is run via an ACME automation, at least I think that is also run via the system action from within ACME.

I failed digging through all the scripts and includes and system actions etc to identify the cause and now had to give up due to time constraints, am now using caddy restart action from ACME which is fine for now.

Hopefully this helps someone way more knowledgeable then me in all the internals of the system to narrow down the issue.



Thanks for the report, if I have time I will look into it.

Best would be an issue in https://github.com/opnsense/plugins
Hardware:
DEC740

Hi all, I'm setting up Caddy behind OPNsense and running into an issue that I suspect is either a misconfiguration on my part or a misunderstanding of how NAT and Caddy work together.

Setup details:

- OPNsense as the router
  - VLAN 20 for LAN
  - VLAN 50 for servers

Caddy is configured and successfully issues Let's Encrypt certificates

The upstream service (Minio) is running over HTTP on port 9001

I created a NAT rule to forward HTTPS traffic to port 9001 on the server, but I'm getting a ERR_SSL_PROTOCOL_ERROR. If I create a NAT rule for plain HTTP instead, it works fine.

A few questions:

- Has anyone experienced this behavior with Minio over HTTP? Could Minio be rejecting the SSL termination from Caddy?

- I assumed that once a handler is set up in the Caddyfile, Caddy would take care of routing automatically—but it seems like it doesn't touch NAT rules. Is that correct?

Any guidance or clarification on how Caddy and OPNsense should interact in this case would be greatly appreciated!

Thanks in advance.

Hi,

I have setup Caddy exactly as described in OPNsense documentation.
I changed the OPNsense https port to 8443, checked the Disable web GUI redirect rule.
I have created the WAN and LAN rules for This firewall destination.
Enabled Caddy, supplied e-mail, Auto HTTPS is ON.
Domain is https://test.duckdns.org. Certificate is Auto HTTPS.
Handler: Domain is https://test.duckdns.org, Directive: reverse_proxy
Upstream:
Protocol: http://
Upstream domain: 192.168.250.162
Upstream port: 2283
Access list private_ipv4 created as per documentation and added to the domain access list

OPNsense runs on a dedicated hardware box, WAN and LAN interfaces only. Dynamic DNS is configured in OPNsense to use DuckDNS. I can do nslookup test.duckdns.org and it resolves to my WAN IP address, no problem. If I access https://test.duckdns.org from within my local network, it can access the server on 192.168.250.162:2283 without any issues. But when I access from internet, I get the error:

net::ERR_HTTP2_PROTOCOL_ERROR


The Caddy file is:

# 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
   }

   email xyz@gmail.com
   grace_period 10s
   import /usr/local/etc/caddy/caddy.d/*.global
}

# Reverse Proxy Configuration


test.duckdns.org {
   @c1ac6e21-c93d-461e-8546-246789993f33_testduckdnsorg {
      not client_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8
   }
   handle @c1ac6e21-c93d-461e-8546-246789993f33_testduckdnsorg {
      abort
   }

   handle {
      reverse_proxy 192.168.250.162:2283 {
      }
   }
}

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


I have done Google search but nothing. I have read all 21 pages of this thread but no matching issue. Caddy is getting certificate from Lets Encrypt. Any help would be appreciated.

OPNsense 25.1.9_2-amd647
os-caddy 2.0.1

Thanks,
Arun

Update: Issue resolved. The documentation is not good. It did not say when to stop creating reverse proxy. It went to configure access list for local access only. I did that and it blocked access from internet. I had to remove the access list from the domain and then reverse proxy started to work from internet. The documentation of Caddy needs to be revised as some options do not exist in OPNsense. It also needs to be made more descriptive to describe so many other options available.

I was able to fix it, it was a bad config on the DNS, it was pointing to the server IP instead of OPNsense IP to handle the reverse proxy correctly.

Quote from: lucasconde on June 28, 2025, 06:07:54 AMHi all, I'm setting up Caddy behind OPNsense and running into an issue that I suspect is either a misconfiguration on my part or a misunderstanding of how NAT and Caddy work together.

Setup details:

- OPNsense as the router
  - VLAN 20 for LAN
  - VLAN 50 for servers

Caddy is configured and successfully issues Let's Encrypt certificates

The upstream service (Minio) is running over HTTP on port 9001

I created a NAT rule to forward HTTPS traffic to port 9001 on the server, but I'm getting a ERR_SSL_PROTOCOL_ERROR. If I create a NAT rule for plain HTTP instead, it works fine.

A few questions:

- Has anyone experienced this behavior with Minio over HTTP? Could Minio be rejecting the SSL termination from Caddy?

- I assumed that once a handler is set up in the Caddyfile, Caddy would take care of routing automatically—but it seems like it doesn't touch NAT rules. Is that correct?

Any guidance or clarification on how Caddy and OPNsense should interact in this case would be greatly appreciated!

Thanks in advance.

Quote from: Monviech (Cedrik) on May 04, 2025, 04:47:53 PMI evaluated it and its possible but very brittle. So it's not going to be included in the plugin.
Thank you for taking the time to look into this matter!

QuoteThe build will be thinned out soon to only include cloudflare, which will make caddy add-package less prone to fail.
Good to hear! I finally got around to using DNS-01 challenge with Porkbun DNS, so had to rebuild caddy 2.10.1 with porkbun module using xcaddy. go124 upgrade was done implicitly. Slightly painful but works. Thank you for writing such a helpful plugin!

How to use environment variables with caddy?

I had a need to reuse certain parameters in different reverse proxy handler blocks. The manual way of duplicating the same value in multiple places works ofcourse. It'd be easier to use environment variables. So, I tried add caddy.conf in /usr/local/opnsense/service/conf/configd.conf.d with content like so

CADDY_RESOLVERS_DNS_TLS=149.112.112.112 1.1.1.1 8.8.8.8 8.8.4.4

followed by

service configd restart
configctl caddy restart
caddy environ

startup fails w/ the environment variable value not found. Perhaps a wiser being could tell me whether there is a trick to this getting the env variables working?