Homelab: The OPNsense Gauntlet

- 16 mins read

Series: Homelab Series

Introduction

I don’t usually start these off with a disclaimer, but I definitely am this time. This post is an absolute doozy as we are configuring multiple services here on OPNsense. Each of these could be a separate post, but I decided to do this whole thing in one go. Now you are totally good to just skip to the sections you are interested in reading, in fact I encourage it. I just for whatever reason wanted this OPNsense setup to kinda be all in one go. Now there is also the assumption you have at least gone through the basic installation of OPNsense either in a virtual machine or on dedicated hardware. This setup was done on bare metal, so I apologize if there are any major differences I am not aware of, but whether you’re doing this for a local network or a virtual network it should be the same, or at least similar. Alrighty, with all of that out of the way, I suppose we can kick off this OPNsense gauntlet.

Setting Up Our Internal Domain

Pasted image 20260812175530.png Alright, here we are at our OPNsense main dashboard. There’s a lot of good information we can see right from here, such as stats for our interfaces, current network throughput, Firewall stats and CPU/memory utilization. Now, during some of these steps we may need to keep a second browser tab of OPNsense open just in case we get booted off. So just open a copy of the dashboard here. Alright first step, setting up our internal domain name. Pasted image 20260812180055.png So under: System -> Settings -> General. We can set our internal domain. Now it can’t actually be just whatever you want, expertly demonstrated by yours truly. .arpa is actually a reserved Top Level Domain (TLD) per RFC 3172 and can’t just be used willy nilly. Now, home.arpa has been approved for home network use (RFC 8375), but I want to be cringe and use my whole “karmicsecurity” naming scheme so I’m using .internal which is approved. Oh and then we change the hostname to whatever you want and then set the theme to dark because that’s why. Make sure to save and apply for every change we make as we go by the way, unless you want to do all of this twice. Pasted image 20260812180245.png Okay now we go to: Services -> Unbound DNS -> Query Forwarding. Then under Unbound you’re going to be clicking that orange plus sign. We will be clicking that button a lot as we go, so going forward, I will be saying click + as shorthand to save me cumulatively 5 minutes of typing or something. So click +. Pasted image 20260812180348.png Alright, put in your internal domain name and make sure your Server IP points to localhost and the server port is 53053. Hit Save. Pasted image 20260812180442.png Okay we also need a query-forwarding entry for the reverse-DNS zone. For my 192.168.50.0/24 network, the corresponding reverse zone is 50.168.192.in-addr.arpa. I enter that value in the Domain field and forward it to 127.0.0.1 on port 53053. Pasted image 20260812180525.png Okay after that, this is how my settings look. Let’s move onto the next step. Pasted image 20260812180624.png Under Services -> Unbound DNS -> Advanced, we’re going to add our internal domain to the Private Domains box. This tells Unbound that private address responses are expected for this namespace, preventing DNS protections from removing or rejecting those DNS answers. Should be all we need to do, friendly reminder to go ahead and save/apply. Pasted image 20260812180820.png Now go to: Services -> Dnsmasq DNS & DHCP -> General, and check Highlighted box as we do not want our DNS queries to our internal resources going to external DNS servers. Next. Pasted image 20260812181020.png Still in Dnsmasq, under the DHCP ranges tab, add the DHCP range of your local network and your internal domain. Mine starts at .3 because my Wi-Fi AP is statically assigned to .2. Do whatever is best for your situation. Pasted image 20260812181439.png Now under the Dnsmasq Hosts tab, add the hostname of your OPNsense box, internal domain and OPNsense’s local IP. Repeat for all devices. After you do that you’re doing to want to repeat that process for all the devices on your network you want to have domain names for. After you’re done it should look a little like… Pasted image 20260812182022.png This. Alright, all of mine are made. Now the next step for me is going to be to add some CNAME records to each host for each service I plan on running on that host. Pasted image 20260812183333.png So I add all of these CNAME records to my Latitude laptop. Now, full transparency we are probably just going to delete these later when we set up our HTTP reverse proxy. So you can choose to add these if you want to test your name resolution. Speaking of testing name resolution, let’s do that!
Pasted image 20260812183819.png So we run nslookup on a couple (sub)domains here, all specifying our OPNsense box as the DNS server to query. All the queries look good to me, so seems like we set up all our records correctly. Okay, so that’s super cool, although none of those URLs will get us to our the service we want to get to yet. There’s no way to forward to a specific port, so we’ll need a HTTP reverse proxy, such as Caddy. However, before we set up Caddy, we’re going to need to set up a Certificate Authority (CA) server for our local domain.

OPNsense CA Server

Okey dokey, time to deploy our own local PKI. Now you don’t have to do this, but one, I kinda want to and two I want all of my services to be rocking HTTPS, not just HTTP. It’s honestly not too bad, the first thing we need to do is create our local Root Certificate Authority (CA). Pasted image 20260831013610.png Alright, let’s navigate to: System → Trust → Authorities. We don’t have any CAs configured yet, so that should be blank. Let’s first add our Root CA. Pasted image 20260831013907.png Configuration should look a little something like this. This will be our Root CA. Make sure to save and apply. Now we’re going to want to make our Issuing CA which will be signed by our root CA. It’s bad practice to have the Root CA online, it’s typically used to sign the Issuing CA and then taken offline. Because this is just for my homelab, I am leaving it online, but you should export and store the root CA private key offline, then remove the private key of the root CA from OPNsense. Okay, with that being said, let’s make our Issuing CA. Pasted image 20260831014601.png And that’s our Issuing CA done. Awesome, now we’re going to create a couple certificates, not anymore CAs. So go ahead and under Trust, click on Certificates. Now, we’re going to create two certificates. One for OPNsense’s web GUI and another for Caddy that’s going to be a wildcard certificate. Caddy is going to point to several of our subdomains, hence the need for the wildcard. Let’s do Caddy first. Pasted image 20260901003922.png So we have the Issuing CA be the issuer for this cert and then use a wildcard for the subdomain so we can make as many as we want later. Next we need to make a certificate for the OPNsense web GUI itself. Let’s do that. Pasted image 20260901003728.png Pretty much the same as the Caddy certificate, except the domain name and this time we specify an IP address. Pasted image 20260831235959.png And here we have all of our certificates, yippee! Before we go ahead and apply these certificates to their respective services, we need to configure all of our local devices to trust the Root CA. I will demonstrate how to do this on my Windows host and I’ll link to a link for mobile devices, cause you probably want to access your services from your phone sometimes. In order to do this we will first need to download the Root CA file. Pasted image 20260901000353.png On the right side of your CAs you’ll see some icons, one being a little cloud, click the cloud on the row of your Root CA. That’ll be the first row for me. Pasted image 20260901000457.png File type Certificate and Download. Pasted image 20260901000549.png We will save this as a .pem file, save it somewhere you won’t forget. Okay now, from a Windows host, click Windows key + R on your keyboard at the same time. Pasted image 20260901000727.png Cool, enter certlm.msc and hit enter and click Yes at the system prompt. Pasted image 20260901000818.png Cool, here’s our certificate manager where we can see all of our trusted certs and what not. Pasted image 20260901000931.png Now we’re gonna go to Trusted Root Certification Authorities and right click on Certificates. Hover your mouse over All Tasks and click Import. Pasted image 20260901001319.png We want Local Machine and can’t change it anyhow so that’s perfect, Next. Pasted image 20260901001409.png Browse to the .pem file you saved. Perfect, Next. Pasted image 20260901001514.png This is fine, Next. Pasted image 20260901001532.png Verify your information and Finish. Pasted image 20260901001552.png Amazing. Okay we’re going to need to restart our browsers. Now certain browsers reference the Windows trust store by default, mainly Chromium based browsers, so I should be good. If you use Firefox you will need to do some additional steps, just google How to import CA Firefox or something. Okay, now, after our browsers restart keep your existing OPNsense login and open up another tab and login again. Pasted image 20260901002241.png Okay, from our second OPNsense tab, go to System -> Settings -> Administration. Pasted image 20260901004334.png And we actually change a few things here. For the SSL Certificate, choose the certificate we created. We’re going to change the Web GUI port to 8443 and check the box for Disable web GUI redirect rule. Also, for Listening interfaces there, change that to LAN instead of All. Don’t worry, your web GUI wasn’t exposed to the internet, default firewalls rules block access, but we’re disabling it anyways. Scroll down to the bottom and click Save. The web GUI will need to reload, but after it does… Pasted image 20260901005014.png Ayooo, HTTPS is rocking and rolling and our internal CA is trusted, you love to see it. Okay, now it’s time to install and configure Caddy.

Caddy Reverse Proxy Setup

Okay so, big part of our homelab configuration is this part right here. If you’ve been following along you know that most of our services are containerized. Which is great, love containers. Only issue is that DNS records don’t take port numbers. This is fine unless you are hosting a ton of stuff on the same machine. Now, at this point in our configuration, you could navigate to a service by going service.example.com:port. DNS resolves the domain name, but you still need to specify the port. To me, that makes the whole name resolution thing kinda pointless as it’s not the IPs I’m forgetting. So, we are going to fix this with Caddy, which can function as our HTTP reverse proxy. Forwarding our requests from it to the right IP and port number. Sounds cool? I think so, let’s get it running. Pasted image 20260812190029.png Under System Firmware Plugins, Enable Community Plugins in the top right and then search caddy. Click plus sign on far right. Pasted image 20260812190139.png Ah, it appears my firmware is out of date. Alright, quick update our firmware. Pasted image 20260812191913.png Hit check for updates and let it do its thing and then install Caddy by searching for it under System -> Firmware -> Plugins. Okay perfect, it should be available now after it’s done installing, but we need to enable it. Under Services -> Caddy -> General Settings. Pasted image 20260901010848.png Okay, we’re going to want to check the box next to Enable Caddy. We’re also going to want to change Auto HTTPS from On to Disable Certs Pasted image 20260901011027.png Click Apply. Now Caddy is actually running. Okay, time to actually configure the reverse proxy. Pasted image 20260901011342.png So under Caddy -> Reverse Proxy, click on the Access tab. On the right hand side, under the Access Lists section, click the orange +. Pasted image 20260901014309.png And this is what my settings look like. I call mine LAN-and-VPN, because when we configure remote access later we will need to add our VPN client addresses here. Click Save. Pasted image 20260901014425.png Looking good, alright time to create the wildcard domain. Click on the Domain tab there. Similar to the Access Lists, and then click + under Domains. Pasted image 20260901014712.png Make sure the box next to Enabled is checked, protocol is HTTPS. We have the domain set to our wildcard domain, the certificate is our Caddy Wildcard cert and the access list is the one we just set up. Click Save. Now here the fun begins. Still on the Domains page, we are going to add a subdomain for each of our services. So under Subdomain, click the orange +. Pasted image 20260901015109.png Here’s the config for our Grafana subdomain. Now we’re going to do this for every subdomain we want, so, I’ll be back in a second. Pasted image 20260901015601.png Okay, that is what we’ve got going on for now. Make sure to Save and Apply. Okay now we’re going to the Handlers tab to enable the HTTP reverse proxying. As we’ve been doing, orange +. Pasted image 20260901015953.png Choose the subdomain you want, protocol HTTP and the applicable port number in the Upstream Port box. And now repeat for each service. Pasted image 20260901020426.png Very cool, Apply. Okay after all of that, we now need to make local DNS records here on the OPNsense box. Pasted image 20260901020714.png Under Services -> Dnsmasq DNS and DHCP -> Hosts. We have some records setup from earlier, but with the Caddy reverse proxy now in play, it’s time to add some records. Orange +. Pasted image 20260901021002.png Our Host section will be the service we’re setting up the record for and Domain our local domain. Check the box next to Local so DNS queries for our subdomains don’t get forwarded to other DNS servers. Now, for all of these records the IP will be the IP of the OPNsense box. Caddy will forward requests to the appropriate service. Pasted image 20260901021554.png Looking good. Make sure to Apply. Okay, well, our HTTP reverse proxy should be up and running for the services we’ve configured thus far, let’s test it. Pasted image 20260901021705.png On our Windows host, let’s flush our DNS so we can reload our DNS settings. Okay, let’s see if our subdomains resolve. Pasted image 20260901021820.png Okay, that’s all correct. Time for the moment of truth. Pasted image 20260901022114.png Welp, that’s disappointing. Hold on, quick live troubleshooting. Pasted image 20260901022252.png Pro tip, still under DNS Hosts, make sure to clear all your CNAME records. You can even see it in our nslookup’s I just did a second ago. Perhaps writing blog posts at 3am isn’t the best idea. Ah well, delete any CNAMEs you have for the services you want proxied and save and apply. Okay let’s try those lookups again. Pasted image 20260901022826.png Okay better. Browser test? Pasted image 20260901022911.png Pasted image 20260901023006.png Okay so that’s Caddy done.

Installing and Configuring WireGuard

Okay so under VPN -> WireGuard -> Instances is where we’re going to set this up, no need to install a plugin. Pasted image 20260901154141.png Shouldn’t be anything here yet. Alright let’s check the Enable WireGuard box and then click orange + to set up a new instance. Pasted image 20260901154856.png Okay awesome. Now we’re going to go to Interfaces -> Assignments. Pasted image 20260901174511.png And we can see that OPNsense already wants to add our WireGuard interface (wg0). Go ahead and give it a description and click Add. Pasted image 20260901174627.png Cool. We’re now going to want to click on the interface to configure it, so I will click on WG_REMOTE. Pasted image 20260901174832.png And then we configure with our desired settings. Pasted image 20260901183306.png Should look something like this. I’m leaving the MTU at the WireGuard default of 1420 to account for tunnel overhead. VPNs by their nature add additional headers and whatnot to network packets, so whenever you’re configuring any VPN solution, you should keep that in mind. Click Save and then Apply when prompted. After that go back to Interfaces -> Overview to verify the interface is up and has the right info. Pasted image 20260901183600.png Awesome. Now we’re actually going to back to our main dashboard to restart the Unbound DNS service so our new interface registers with it. Pasted image 20260901183943.png Alright, time to configure the firewall to allow WireGuards traffic into our LAN. So under Firewall -> Rules -> WAN Pasted image 20260901190123.png Right hand side orange + Pasted image 20260901193610.png Firewall wall rule should something look like this. Save and Apply. Alright, now we need to make a couple rules for our WireGuard clients to access DNS via the tunnel interface and then access to the internal network. Here’s my config for allowing DNS traffic to the tunnel interface: Pasted image 20260901195359.png And now for LAN access: Pasted image 20260901195806.png This one is pretty simple, just from WG_REMOTE to LAN network. Now this configuration is giving all of my VPN clients complete access to the LAN. If you want them to only have access to specific hosts, you’ll need to specify that. Alright let’s take a peak at our firewall rules thus far.Pasted image 20260901195843.png And a quick glance to make sure everything looks okay. Our firewall rules should be good now, let’s go to Caddy and add an access rule there. Pasted image 20260901200045.png Back to Services -> Caddy -> Reverse Proxy under the Access tab, add our remote client network. Save and Apply. Alright now we just need to go back to the main dashboard again and restart Unbound DNS yet again. Now, after we do that, we should be good to add our first VPN client. If we go VPN -> WireGuard -> Peer generator. Now I am not showing my config for this, but I will break down what the fields should be.

Field Value
Instance RemoteClients or something
Name Hostname of your client
Address IP of client with a 32 bit mask
DNS Servers Should be your tunnel interface IP
Endpoint IP of your WAN interface:51820
Allowed IPs Remote client IP network and LAN network
Keepalive 25
Preshared key Generate one, if offered
Store private key Leave unchecked
After you configure all of that, make sure to Apply. Okay so after that, there’s that little QR code there. If you’re configuring WireGuard on your smartphone go ahead and download the mobile app now. When you do it’ll ask if you want to Add a tunnel. Yes we do, click that and it will prompt you for how you want to create the tunnel. In this case choose QR code. It’ll then ask you to name the tunnel.
Now back on OPNsense make sure to click the checkmark next to Store and generate next. You should now see our peer under the peers tab.
Pasted image 20260901204253.png
Epic. Now on my mobile device, I am going to disable Wi-Fi and turn on the VPN client. After we turn on the tunnel, if we go to VPN -> WireGuard -> Status we should see our new peer!
Pasted image 20260901204712.png
Dammit. One second. Okay, for some reason, under my Peers tab, my Endpoint Address and Port settings got blown up, so double check that they are set. Now if we enable the tunnel…
Pasted image 20260901205002.png
You love to see it. And if I navigate to any of the subdomains we configured with Caddy earlier, I am able to access them from my cellular network. Let’s. Go. Now, granted I do need to import our internal Root CA onto my phone so I don’t get the associated errors when navigating to internal URLs. But hey, we set up internal DNS and PKI, an HTTP reverse proxy and then set up remote access. I think that’s all for tonight folks.

Conclusion

Good lord that was a lot. I will say though we have a pretty sleek setup going on at this point. Now, the kicker is, there’s so much more you can do with OPNsense, but that’s all we’ll be doing for now. I have nothing clever to say after all that, k thx bye.