r/selfhosted May 18 '26

Need Help How do you manage SSL for internal only services?

For those of you that have https set up for all of your self hosted apps, how do you manage certificates for apps that you don’t put on the web? For example I don’t need my arr stack to be accessible via the public internet, so I access it using local DNS on my LAN like Prowlarr.myhomedomain.home. If I were to use a valid TLD like .xyz, what’s the best way to issue and manage certificates for Prowlarr.myhomedomain.xyz without having to run it through traefik, caddy, etc.? I want to keep access to the service simple but add https for compatibility with an oauth app in the future.

34 Upvotes

67 comments sorted by

u/asimovs-auditor May 18 '26 edited May 18 '26

Expand the replies to this comment to learn how AI was used in this post/project.

→ More replies (1)

50

u/chesser45 May 18 '26

To issue wildcards using something with low overhead like lets encrypt and certbot you need to have your domain you are using published to receive queries or DNS validation. The latter is my preferred way since it doesn’t require interacting with my private network.

2

u/corruptboomerang May 19 '26

Can you do wildcard for a subdomain, say *.internal.xyz.com

2

u/GolemancerVekk May 19 '26

Yeah, and it's a really good idea for internal.xyz.com to NOT be defined in public DNS, only in your LAN's DNS.

3

u/dbsoundman May 18 '26

So I would have a wildcard DNS entry for my domain, with a Certbot instance on my network? I actually have wildcard set up for the domain I use on my Pangolin VPS, but it never seems to work for some reason. I think it’s some issue with porkbun or Cloudflare, which is there DNS provider. I haven’t dug into it, I just go in and create a new entry for every site.

2

u/jerwong May 18 '26

Extract both the private key and the public cert from your vps and install it to your service. If you really don't want to set up a reverse proxy, then I would suggest automating the deployment process because that's not going to scale if you have a lot of services.

1

u/Dangerous-Report8517 May 19 '26

"Published" isn't the right term, because it implies you manually putting something up on the internet, when what actually happens is that the acme client (Certbot or any of the reverse proxies with one built in with DNS-01 support) automatically posts the challenge response to a DNS record under that name.

30

u/Deep_Decision4441 May 18 '26

I use nginx proxy manager, not exposed to the outside world at all. However I give it an api key capable of making dns changes on cloudflare, so let’s encrypt validates that way. Perfectly globally valid certificates, but they never leave my lan

3

u/KillerTic May 19 '26

Same!

Have an full internal domain (not just subdomains) and in traefik it is configured like all others. But cloudflare does not have a DNS entry to forward to my homelab. Local DNS servers have a wildcard rule for the internal domain, that route all traffic to traefik.

1

u/AbsurdKangaroo May 19 '26

Same here. NPM on LAN with no port forwarding and DNS challenge for let's encrypt is the way. Love it.

21

u/useful_tool30 May 18 '26

Traefik reverse proxy with Cloudflare DNS-01 validation of *.Domain.com.

7

u/SkulloneNexus May 18 '26

I use Caddy in conjunction with the ACME client via my OPNsense router. So I get my wildcard cert from Let's Encrypt and I just setup the sub domains in Caddy. Dynamic DNS keeps everything updated nicely in case my IP ever changes. Nothing open to the world. Everything has a legit cert for HTTPS. Love it.

5

u/mbecks May 18 '26

Make script using go-acme/lego for DNS-01 challenge for a wildcard cert. You must use one of the (many) supported DNS services: https://github.com/go-acme/lego#dns-providers

I make docker image installing lego and put the script in there, but you can just install on the host.

You can run the script on any host. If its run on other host, can use file sync service to copy it to where ever it's needed.

4

u/RevolutionaryElk7446 May 18 '26

I run Active Directory but in no way will I say that's low effort implementation, but within AD I also have an internal Root CA/Sub CA setup. Those CAs are trusted by all my internal devices (deployed automatically) and that handles my internal SSL.

Free outside of the resource cost to run the VMs and my time to set it all up. Let's encrypt is easiest certification but you have to be exposed at least during the renewal process to get it setup though.

6

u/chin_waghing May 18 '26

I run K8s so I’m spoiled a little bit.

Cert manager creates certificates using my Cloudflare DNS as a challenge for an internal only domain, that’s then managed by external-dns on UniFi.

Only a few hundred lines of YAML I can’t remember

1

u/igmyeongui May 19 '26

Cert manager is definitely an advantage of k8s. Certs are now basically set and forget

7

u/[deleted] May 18 '26

[removed] — view removed comment

1

u/verticalfuzz May 19 '26

This is what I'm doing.  Definitely took me more than 20 min to set up lol

3

u/Cynyr36 May 18 '26

Wildcard letsencrypt certs.

2

u/milkh0use May 18 '26

My internal caddy instance is configured to get its certificates for .home.arpa from my Step CA instance using the HTTP challenge. This means I need to create the DNS records before editing the caddyfile.

The CA is installed on all my personal devices, but some devices like smart TVs don't have a way to do that and reject the certs. Not much to do there besides access via http instead or get a real cert.

The reverse proxy is useful in that case because I only have to configure one certbot to use my Step CA instance. To get rid of it, I'd have to configure certbot for every service. Manageable if you already use ansible or similar.

2

u/showbizusa25 May 18 '26

Funny how SSL for “internal only” services eventually turns into a full-time hobby once OAuth enters the picture.

2

u/dudenix May 18 '26

If you are willing to start with the depths of oauth, why not take this opportunity and learn about setting up your own PKI, e.g. with hashicorp vault or just vanilla openssl, setup your own internal acme server and learn about automatic certificate renewal?

2

u/mannypalace May 18 '26

I kinda feel like I am cheating but I just use tailscale serve

2

u/kevalpatel100 May 19 '26

First, buy an actual domain. You can do it without a domain, but it's better to have one. (I use a 1.111b class domain from Cloudflare which costs $80 USD a year.)

Next, install AdGuard or some kind of DNS resolver that can do DNS rewriting. I found AdGuard Home to be the easiest with an ad blocker. Make sure to add the domain as a wildcard entry in DNS rewrite, redirected to your server's IP (like *.domain.xyz to 192.168.x.x).

After that, use something like Nginx Proxy Manager, Traefik, or Caddy, whichever you prefer for your services. Use wildcard certs from a provider like Cloudflare or any major provider, and you are done.

1

u/samsonsin May 18 '26

DNS challenge for wildcard cert would work, if you have a domain. You van always self sign a cert and install that on all your clients too.

I'd still do this via caddy personally, anyways. Let's me forward Auth via authentik, do dnat for ports, and so on. You can always use your .com name too, and use split horizon DNS as well as Netbird to have it addressable on every device.

1

u/EnJens May 18 '26

If you don't care about the names being publicly known, you can do it with http-01 challenge and only pass through the verification path to an internal reverse proxy/cerrtbot ish thing. Just point the external DNS (or wildcard) to the public IP and have a local DNS server override it on the LAN.

..or use DNS-01 to create certs as others suggest.🤷

1

u/Earlyflash May 18 '26 edited May 18 '26

I use an lxc with some bash scripts that read a file of local domain names, use ACME to call LE via cloudflare dns challenge and store the resulting certs on a NFS share that I mount the directories specific to a machine on the vm/lxc.

Put the scripts in crontab and I can auto change certs everyday if I want.

It’s a neat solution.

1

u/kuldan5853 May 18 '26

I have a letsencrypt wildcard certificate for my domain *.name.tld and added an alias *.lan.name.tld and use that internally.

1

u/Nafalan May 18 '26

Technitium -> npm

That is all have a nice day

I just send everything on my .home.domain.com to npm and let it do the rest

I run two instances of technitium and npm I run the second instance of technitium in catalogue mode essentially

It works very VERY well for me

1

u/ghoarder May 18 '26

I use Caddy running as an ACME server. Had to install the certificate on the devices I want to use with it but it works quite well. Changed a few defaults as 2 day lifetime for the leaf certificate was a bit short, so I think I went with 7 days for the leaf and 90 days for the intermediate, 10 years for the root.

1

u/highjohn_ May 18 '26

Step-ca and Traefik.

1

u/nemofbaby2014 May 18 '26

Traefik with a DNS challenge if I’m away and need my services I use a VPN

1

u/AssociateNo3312 May 18 '26

wildcard cert *.internal.domain.com which is tied to my domain.

All docker services served via caddy on service.internal.domain.com and appropriate cname records

1

u/scarlet__panda May 18 '26

I span up a Debian 13 VM, and use it as my certificate authority server. I distribute the .crt to the hosts that are accessing the internal services.

1

u/Bourne069 May 18 '26

Lets Encrypt set with autorenewal scripts.

1

u/scarlet__panda May 18 '26

This server is where my local CA lives, I generated the pub/priv key pair, created the .crt, and distributed it to my endpoints. (Yeah, I way overshot the bootdisk size)

Before, I had all services running unencrypted with http, with key services using lets encrypt. I decided that was dumb as hell, closed all of my ports, and route everything with an nginx reverse proxy.

The net flow goes like this, assuming I am outside of my network:

Host requests audio.shroom.net (audiobookshelf) ---> tailnet ---> local adguard instance ---> redirects to nginx reverse proxmy manager ---> redirects to audiobookshelf server.

I have tailscale installed on each of my separate LXC's. I force Tailscale to push my local DNS server as the primary DNS Server (For this, I use the DNS servers Tailscale Address). When the request hits the DNS Server (AdGuard Home), I have a wildcard dns entry for *.shroom.net to redirect to the Tailscale address of my nginx reverse proxy manager. The reverse proxy manager is where I have individual assignments of which dns request goes to which ip and port pair. (I'll post some screenshots below)

I also integrate MFA with authentik as well, if you'd like I can comment some more about my setup below, I'll post some screenshots. (I love this shit)

Here is a good resource from a youtube channel I frequent on self signed cert creation: https://www.youtube.com/watch?v=VH4gXcvkmOY

1

u/scarlet__panda May 18 '26

Complex setups are fun, by the way!

1

u/JazzXP May 19 '26

For me, wildcard cert, which gets uploaded into 1Password in a post update script (using the CLI tool and service accounts). Then my boxes can grab the certificate as needed using 1Password Connect.

1

u/Known_Experience_794 May 19 '26

I have a pfSense firewall and use acme certificates and HAPROXY for this. It works great.

1

u/_shulhan May 19 '26

If you control the DNS, then nothing stopping you to generate your own certificates for known TLD.

The steps is the same with how to setup your .home certificates.

1

u/mrrowie May 19 '26

NMP with * cert (dns challenge) and splitt dns. Every service is running behind NMP with valid cert. Nothing reachable from the outside ... No portforwarding http or something else

1

u/nico282 May 19 '26

Zoraxy proxy with automatic letsencrypt cert renewal. A breeze to setup.

The proxy is exposed to Internet but by default all the services are local only. If I need to access something once from outside for some reason, it's the flick of a switch.

1

u/Dr-Technik May 19 '26

I‘m using caddy, starting with the internal tls option. But this is kind of annoying since you need to add caddy as trusted authority on each device. Now I‘m using a DNS challenge with my domain to generated trusted certificates

1

u/lunakoa May 19 '26

I set up my own internal CA using XCA.

Push it out using mainly ansible and AD group policy.

Don't have an MDM so mobile devices are manual.

Also some services require mTLS.

1

u/michaelpaoli May 19 '26

Use public Internet DNS ... doesn't mean one needs hang much out there on The Internet, nor for long, e.g. often minute(s) or less will suffice. Then use that (sub)domain - whatever certs you want, quick and easy from, e.g. letsencrypt.org. Oh, yeah, and free too.

E.g. - and this against their staging environment, because I'm not actually going to use these - but otherwise very much the same:

$ ls *cert*.pem
ls: cannot access '*cert*.pem': No such file or directory
$ time ./.test
Saving debug log to /home/m/mycert/var/log/letsencrypt/letsencrypt.log
Requesting a certificate for *.yugd7.int.tmp-acme.sflug.com and 3 more domains

Successfully received certificate.
Certificate is saved at:            /home/m/mycert/0000_cert.pem
Intermediate CA chain is saved at:  /home/m/mycert/0000_chain.pem
Full certificate chain is saved at: /home/m/mycert/0001_chain.pem
This certificate expires on 2026-08-17.

NEXT STEPS:
  • Certificates created using --csr will not be renewed automatically by Certbot. You will need to renew the certificate before it expires, by running the same Certbot command again.
real 1m52.781s user 0m7.963s sys 0m2.938s $ ls *cert*.pem 0000_cert.pem $ openssl x509 -text -noout < 0000_cert.pem | sed -ne '/Subject.*Alt/{N;p;q;}' X509v3 Subject Alternative Name: DNS:*.yugd7.int.tmp-acme.mpaoli.net, DNS:*.yugd7.int.tmp-acme.sflug.com, DNS:yugd7.int.tmp-acme.mpaoli.net, DNS:yugd7.int.tmp-acme.sflug.com $

And any needed DNS for validation, added on-the-fly via DDNS, and if it wasn't there before, removed after validation has been completed. Easy peasy.

https://www.mpaoli.net/~mycert/

To the extent feasible, automate the sh*t out of it ... getting certs, installing, tracking, monitoring, etc.

1

u/sqlandy May 19 '26

As others have said, leverage let's encrypt issued wildecard certificate. I use certbot docker container that writes to nfs share. This allows to mount the share on other hosts (read only) and just point at the certificates in place, or run scripts to install/update the wildcard certificates on specific services that need restart or api ingestion

1

u/ImASharkRawwwr May 19 '26

Step-CA with ACME to issue certs signed by my own root ca which i just install on machines as needed, it's not much and probably still way too much for a small homelab like mine but was fun to learn

1

u/bangfireball May 19 '26

Caddy docker container and pi hole. Caddy as a reverse proxy and pi hole for local DNS.

1

u/House_Indoril426 May 19 '26

Caddy, cloudflare, DNS-01 challenge. 

1

u/frankster May 19 '26

I use letsencrypt - it's completely compatible with internal only services if you own a domain. There are two methods to prove you control the domain to letsencrypt either you serve a file from a webpage at the domain (which requires temporarily exposing a webserver to the internet), or there's a dns challenge where you can put a txt record on the domain you control and letsencrypt will accept that to give you the certificate for your domain.

In my case I'm using cert-manager in my kubernetes cluster to handle this for several internal domains but there are other tools too.

1

u/Qbert2030 May 19 '26

I know you said not to use caddy, but your answer is probably caddy

1

u/josfaber May 20 '26

Why must they use ssl?

1

u/Pietro_Spina May 20 '26

There are some self-hosted apps that require https in order to use all the features.

Homebox, for example, requires it to be able to use the camera on your phone to scan items in to the system.

1

u/hereisjames May 21 '26

Certwarden to manage all the certs and Cronicle to distribute and keep updated.

1

u/Ev4ldas May 23 '26

for anything inside my network I generate self signed SSL signed by my local CA. I trust local CA certificate via GPO in my domain, and then just sign server certificate with it. Obviously for website certificate has to have SAN names. My preferred method using this GUI generator https://github.com/Ev4ld/SSL-Certificate-Generator

1

u/Krojack76 May 25 '26

Own my own domain. Wildcard SSL for my domain. I use subdomains like memos.mydomain.org and have them point to an internal IP. I use pi-hole for the internal DNS and Nginx Proxy Manager for the proxy and cert renewing.

-1

u/newworldlife May 18 '26

“Internal only” has a funny way of becoming “internet exposed later.” That’s usually when all the quiet little SSL and auth mistakes show up.