Reverse proxy: hide my home ip

Continuing the discussion from Using Caddy as a reverse proxy in a home network:

Hi,

I use Caddy to serve my basic website on a mini cloud server (CentOS 7, using the Caddy repos), and btw it’s great! :smiley: But also while I have an understanding of roughly how these things work, I’m definitely more noob than pro.

I am starting to run some services on a home server (which would be some simple web apps as I learn, hopefully a Nextcould, and maybe parts of my website), but ideally I don’t want these pointing directly at my home ip address, because I do understand that this probably isn’t the most ideal thing to do, and there are benefits to having a static front-end ip.

So my question is: What ways can I use Caddy and the cloud server to be the front end and hide my home ip address?

  1. Don’t worry and just use my local IP and only port forward to Caddy.

  2. I assume bad - reverse proxy from cloud server Caddy to ports directly forwarded to the services.
    Here I am hiding my home IP, but have to have a number of open ports.

  3. Is this possible? - reverse proxy with some config from the cloud server Caddy to a single port that forwards to a home Caddy, which splits the traffic out to the services.

  4. You have a better idea!

From some experimentation (my server wasn’t expecting to be asked to return e.g. someservice.sambr.co.uk so I had to change the Host header to the local address it expected using header_up http:192.168.0.99:9999 in the reverse proxy directive) I realised that the Host header is not edited - so can you just reverse proxy one Caddy to another and extract the right url information?

Something like:

First Caddyfile on the cloud server

service.sambr.co.uk {
    reverse_proxy {
        to https://99.99.99.99 --- e.g. ip of my home
    }
}

Second Caddyfile on home server

service.sambr.co.uk {
    reverse_proxy {
        to http://192.168.0.99:9999 --- ip of the particular service on home network
        header_up Host http://192.168.0.99:9999
    }
}

I think this won’t work and auto https will fail - but is there a way to do this, ideally through one non-standard port, and be able to split the sub-domains and keep uri paths correct?

Thanks,
Sam

1 Like

Hi, so I think I’ve figured out how to do what I’m trying to do, let me know if you see any holes or issues:

I have:
Dynamic DNS subdomain pointed to my home server e.g. homecaddy.sambr.co.uk
Service subdomains pointed to my cloud server e.g. service1.sambr.co.uk / service2.sambr.co.uk

Cloud server caddyfile. Here I set the host header to homeserver.sambr.co.uk and another header ‘Endpoint’ to some identifier so I can split it out to the relevant service at the other end.

service1.sambr.co.uk {
    reverse_proxy {
        to homecaddy.sambr.co.uk
        header_up Host homecaddy.sambr.co.uk
        header_up Endpoint service1
    }
}

service2.sambr.co.uk {
    reverse_proxy {
        to homecaddy.sambr.co.uk
        header_up Host homecaddy.sambr.co.uk
        header_up Endpoint service2
    }
}

Then the home Caddy server. Here everything is received into the homecaddy.sambr.co.uk so the auto HTTPS is correct, then match the header used to identify where to send the request internally. (service2 has a self-signed certificate so needs to use the transport directive with tls and tls_insecure_skip_verify or it is blank I think).

homecaddy.sambr.co.uk {

    @service1 header Endpoint service1
    @service2 header Endpoint service2

    reverse_proxy @service1 {
        to http://192.168.0.999:9999
        header_up Host http://192.168.0.999
    }

    reverse_proxy @service2 {
        to https://192.168.0.888:8888
        header_up Host https://192.168.0.888:8888
        transport http {
            tls
            tls_insecure_skip_verify
        }
    }
}

This way my services have a static IP address, and everything external is https.
I am genuinely interested if this is worth it though or if anyone has any opinions on this. :man_shrugging:

Thanks,
Sam

1 Like

Howdy @sam-br!

This is, generally speaking, plenty secure. When you maintain your firewall such that Caddy is the only thing that is accessible from the outside, there’s basically no surface area to try and attack, for example.

Yes, this is much less than ideal. It is way less secure than option 1, because even though people don’t know your home IP address (that information is “obscured”), you’ve still got a large surface area on your firewall, so anyone who IP scans and stumbles into you will find all those open ports to all your apps.

Yes, quite possible, and I would definitely recommend this approach over option 2. You’ve experimented with one possible method for this (separate domains for the remote Caddy and the local Caddy). You’ve also found a rather clever approach with the headers, which looks pretty nice! That seems like a pretty simple, robust solution.

For the sake of academics, though - it’s possible to use the same domains for both if you wanted. You could have both Caddies validate separately (via DNS validation) or in a clustered manner (with both of them accessing certificates from a remote file system).

Wouldn’t say better, but an alternative -

If you’re running Linux servers on both ends (home and remote), set up a persistent SSH tunnel.

Make a tunnel user on both ends, with public keys exchanged, and set up a service on the local server (running all your apps) to maintain an SSH tunnel out towards your remote host.

With that SSH tunnel, add remote forwarding (e.g. -R 8080:localhost:8080 -R 8081:localhost:8081 etc), which expose ports locally on the target server that are forwarded back to the client. That means your home server reaches out through the internet, supplies access to the apps to your remote server for it to then serve via Caddy. Only one Caddy needs to be set up, you need exactly zero open ports on your home firewall, and as long as the tunnel is persistent Caddy won’t care where your home IP is - you don’t even need dynamic DNS.

2 Likes

Blockquote If you’re running Linux servers on both ends (home and remote), set up a persistent SSH tunnel.

Blockquote Make a tunnel user on both ends, with public keys exchanged, and set up a service on the local server (running all your apps) to maintain an SSH tunnel out towards your remote host.

Adding to this I can really suggest a wireguard tunnel (works great with roaming clients and such)

@Whitestrake, @conorlburns - thanks for the advice!

All these are linux, I’ve been trying out the ssh tunnel and will probably move to this instead of the dual Caddy, try to learn more ssh functionality, maybe look at wireguard if things get more complex.

Sam