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
Is it correct, that if I add rules to the LAN interface, that I can replace any for source with LAN net? I ask, because the instruction states to use the same rules for WAN for LAN.

Yes you can if you want. Though it does not really matter since only the LAN interface receives pakets from the LAN anyway already.
Hardware:
DEC740

Quote from: Monviech on July 27, 2024, 07:21:45 AM
Sorry I don't know then. Without some debug logs its uncertain what happens there. I need some info that is not anynomized so theres no mistakes due to wrong omissions.

- Check your DNS, does "nslookup yoursubdomainname" really resolve to the IP address of the OPNsense?

- If Yes, Whats the output of "curl -v subdomainname"

- What do the debug logs show when you try to reach it?

- Which kind of application is listening there? Is it a HTTP or HTTPS application.

- If the application demands a HTTPS connection, did you enable "TLS Insecure Skip Verify" like I asked?

- When you deactivate the handler for the subdomain AND disable "abort", do you at least see an empty webpage and the certificate?

If its a very complex issue, you can also go to https://caddy.community and fill out their help template. Show your old nginx configuration, and your current Caddyfile. That way they can see if theres a mistake.

So, thanks for the heads up! I finally managed to make it work.
As every time something ain't working in networking... its always dns !

For DNS resolving, i'm using pi-hole > unbound > DoT

Pi-hole was not resolving the "local" domain and was throwing "non-existing domain"

Adding a local dns record thru pihole, pointing to the firewall made it resolve.

Now works as intended !

Good job, yeah DNS is tricky sometimes. Great it works :D
Hardware:
DEC740

Would you happen to know where the www folder for caddy is located?
I'd like the main domain to point to a single html file inside caddy

something like this :

<!DOCTYPE html>
<html>
  <body style="overflow:hidden; margin:0; text-align:center;">
    <img src="image.jpg" style="height:100vh; max-width:100%; object-fit: contain;">
  </body>
</html>

The plugin is not set up for it. It only serves as reverse proxy.

Though, you can read the documentation here:

https://caddyserver.com/docs/caddyfile/directives/file_server

You would need to set up a "root path". I would suggest to put it somewhere inside "/var/db/caddy/data/caddy/..."

To configure the file_server, you could then use the import statements. The *.conf file can set it up inside the site block. https://docs.opnsense.org/manual/how-tos/caddy.html#custom-configuration-files

I actually never used Caddy as a static web server before, only as reverse proxy. So, I'm not much of help here. Good luck though, shouldn't be too hard.

Also, I do not recommend to serve files from the firewall itself.  ;)
Hardware:
DEC740

Here is a new video that shows off the Layer4 routing of the next plugin version os-caddy-1.6.2

It remains very simple to configure, which is the main focus of this plugin.

https://www.youtube.com/watch?v=1IykZemclVA
Hardware:
DEC740

The first version of the Layer4 feature is now complete and will be in the next plugin version. Additional Traffic matchers have been added.

https://github.com/opnsense/plugins/pull/4133

This means as an example:

The firewall only has port 443 open and Caddy listens there with its new Layer 4 module.

- SSH can be sent from port 443 to 192.168.1.1:22
- At the same time, RDP can be sent from 443 to 172.16.100.99:3389
- A TLS connection for OpenConnect VPN matched by SNI "vpn.example.com" can be sent to 127.0.0.1:8443
- The normal reverse Proxy can continue to work and serve any number of HTTPS Domains.

Since this is quite new in this form in Caddy, feedback is valuable.
Hardware:
DEC740

Hi Monviech, thank you very much for this great plugin. I would have a suggestion for improvement for the documentation "Reverse Proxy the OPNsense WebGUI". I followed the description to secure my subdomain. Therefore, I followed the description from the point of view that it is not about the OPNsense WebGUI for me: "The same approach can be used for any upstream destination using TLS and a self-signed certificate." From my point of view, it was difficult for me to get started in the section "Add a new HTTP Handler with the following options" because at first I didn't realize that "TLS Server Name: OPNsense.localdomain" should also be entered here for my case.

Background why I wanted to do this: I have the Unify Controller running via Docker in a DMZ and wanted to access it via the URL unify.example.com.

In Caddy I created
- a wildcard domain: "*.example.com"
- a subdomain "unify.example.com" with access list at 192.168.1.0/24
- a handler
  - with Upsteam domain and port to the Docker host of the Unify Controller
  - set "TLS Insecure Skip Verify" [ x ], otherwise the subdomain would not work
  - activated TLS under "Trust"

So today I went to unify.example.com and was greeted with a different interface. The interface belonged to a "securepoint utm v12". That set my alarm bells ringing. With "nslookup unify.example.com" I saw that numerous IP addresses lead to the subdomain, but only one of the listed ones was the current IPv4 of my Internet connection. I don't know if the settings for Unbound could have anything to do with it, so I suspect that I was allowed to see a live application of a man-in-the-middle attack.

So I followed the documentation. I went to the IP address of my Unify controller, clicked on the 🔒 lock, which was crossed out, and obtained the .pem file. I added the contents of the file under System ‣ Trust ‣ Authorities as "Import an existing Certificate Authority" in Certificate data. Including "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----". As I didn't have any "Private key data" and didn't know what to enter for "Serial for next certificate", I left this blank.

Under the handler, I adjusted the settings under "Trust", for "TLS Trust Pool" my created "Authorities" and under "TLS Server Name: OPNsense.localdomain". I would have thought that I could uncheck "TLS Insecure Skip Verify", but then the page remains blank/white.

The steps led to the Unify controller actually being displayed again.

https://forum.opnsense.org/index.php?topic=38714.msg190745#msg190745

The tls server name is not always "opnsense.local". It is actually the SAN (subject alternative name) of the certificate you add into system - trust - authorities.

You have to check the certificate in the browser to find it out.

If both the certificate and the name are correct, then the connection works without tls insecure skip verify.

If you want something improved, feel free to open an issue here, or even better create a pull request and improve the section in the docs.

https://github.com/opnsense/docs
Hardware:
DEC740

Thank you, for the explenation and the link. I edited the handler, and now it works without "TLS Insecure Skip Verify".

QuoteThe tls server name is not always "opnsense.local". It is actually the SAN (subject alternative name) of the certificate you add into system - trust - authorities.
Personally, I would be satisfied with the information or the sentence in the tip box.

I did not find the word SAN explicitly in Firefox, but only under "Security" "Validated by: CN=unifi" and under "Show certificate" only the owner or issuer name unify. I therefore did not see the connection to SAN here. If you could improve this part and put it in the green tip box, I'd be fine.


I think it happens automatically as soon as you configure "trusted proxies" in the General Settings (advanced view)

Hardware:
DEC740

This looks fantastic, but somehow it has managed to feel more complicated to setup than just a small VM with Caddy on it lol. Followed the instructions for the firewall and everything else for the initial setup, added my DNS provider with all the keys. I did turn off the ability to automatically create records, as many of my services I absolutely don't want accessible from off the network.

Despite having a functional A record in my DNS, I see a bunch of errors from Let's Encrypt claiming that there are no valid A or AAAA records for the domain I had entered. It actually errored enough times before I noticed that I got locked out.

Also, I've definitely never needed an email for Let's Encrypt before, not sure what that's about if I'm being honest, but whatever. Really I'd like to figure out why they're claiming there are no valid records despite having been perfectly fine on my VM that I paused 10 minutes before setting up.

The email has been changed to required since there are two issuers inside. ZeroSSL requires an Email, Let's Encrypt does not. If one fails the other is tried automatically.

To keep it simple I required the Email. Just put in whatever ;D
Hardware:
DEC740