If you have a domain name of your own & a way to keep it pointed at your home's dynamic IP address (or your own static IP address) then "the internet" can find you. The problem is that if you run more than one app that is exposed to the internet that you need to be able to direct incoming traffic to the correct part of your self hosted setup.
You could do that by using ports (numbers which link to a specific "lane" in your internet traffic). You're almost certainly connected to this web page using port 443 on whichever IP address my home currently has assigned (or at least you think that you are, we'll get to this later). If I had another service running on port 12345 then you could be could be connecting to a different piece of software using that port,  & the 2 connections to my home IP address would run in their different lanes without interfering with each other.
N.B. some ports are specific to certain services, such as 110 for email.
You connect to a specific port by using the port number after the IP address/domain name, with a ":" between them
<Home IP>:12345
<Home domain name>:443

There are 2 problems with using ports. Firstly some of the services expect to be running on specific ports (which can be a problem of you want a web server & Nextcloud at the same time - they both like port 443). Secondly, in order to access your different ports from outside of your home you'll need to poke a hole in your firewall to match all of the different ports that you want to be able to access.

This isn't ideal, so there is an alternative.... a reverse proxy. What a reverse proxy does is to take your incoming connections & translates them so that they get to the correct IP address (& port number) inside your LAN. It doesn't need the ports opened to the outside, as long as it can tell where things are supposed to be going, which means that you can use the domain name (& sub-domains) to do the same job - at least as far as connecting from outside goes.
For example:
domainA could be pointed at the web server machine's IP, with domainB pointing at the IP which hosts Nextcloud, so that I use a different domain to connect to each service
domainA:80 could be pointed at the webserver & domainA:443 could point to Nextcloud  (this is bascially the same as not using the reverse proxy although you could map )
OR (subdomains)
www.domainA could point to the webserver & nextcloud.domainA could point to the Nextcloud instance in the LAN

There's another advantage (at least as far as using Caddy goes, & that's what I'm talking about here) - https! Ordinary http connections (on port 80) are transmitted unencrypted, which means that they can be read & altered en route. https uses a security certificate to "prove" that the communication came from the place that you think that it did. Caddy will obtain & maintain the certificates that you need for your domain, automagically.

That's the preamble, now down to how to set things up.


Conveniently Caddy runs from a docker container, so we can get it up & running using Portainer. It will need a place for persistent storage - which I keep in my /home directory, in a directory called Caddy.

Here's the portainer stack, but don't launch it until you've read the rest of this page.

version: "2"
    container_name: Caddy
    image: caddy:latest
      driver: json-file
      options: {}
      - 443:443/tcp
      - 80:80/tcp
      - ~/Caddy/data:/data
      - ~/Caddy/config/Caddyfile:/etc/caddy/Caddyfile
      - ~/Caddy/config:/config

So, we launch Caddy & tell it to keep the config & data in my home/Caddy directory. Within the Caddy/config directory is the Caddyfile (a text document that tells caddy how we want things to be connected/redirected)

So, before Caddy is launched we need to get that Caddyfile set up...

nano ~/Caddy/config/Caddyfile
Edit the Caddyfile

There are a huge number of things that you can do with Caddy, but for my purposes it's mainly the same thing, for each piece of software/app that I want to be able to access via the internet I set up a subdomain CNAME (which "points" to my dynamic DNS domain, which "points" to my home IP address). That gets traffic to the router, which is set up to pass this to Caddy as if that were the only thing in my whole system that is listening to traffic.
Caddy then reads the incoming request & redirects it, depending on where it is really supposed to go. The Caddyfile tells Caddy how to map the incoming requests to the internal IP address & port that they need to reach.
Let's add a single service/CNAME to the Caddyfile & work through it {
log {
    output file /config/www_macklin_co.txt {
    roll_size 10mb
    roll_keep 3
    roll_keep_for 2160h

What this does it to set Caddy to look for incoming requests aimed at (which it automatically sets up with an https SSL certificate).
The specification of what it does when it gets one of these requests is inside the {}.
The first chunk asks Caddy to keep logs, to save them in the output file specified & to rotate the logs (just keep the newest entries) as shown.
Then comes the important part - it redirects the incoming traffic to the IP address & port on the LAN which runs the web server. Which is how you are reading this now.

Adding another service is as easy as duplicating this block & changing the relevant bits to match the new service (i.e. the subdomain, the logfile name & the IP address:port.

Don't forget to reload the Caddyfile when you've edited it.

sudo docker exec <Caddy Container name> caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile