this post was submitted on 05 May 2024
47 points (91.2% liked)

Selfhosted

40425 readers
517 users here now

A place to share alternatives to popular online services that can be self-hosted without giving up privacy or locking you into a service you don't control.

Rules:

  1. Be civil: we're here to support and learn from one another. Insults won't be tolerated. Flame wars are frowned upon.

  2. No spam posting.

  3. Posts have to be centered around self-hosting. There are other communities for discussing hardware or home computing. If it's not obvious why your post topic revolves around selfhosting, please include details to make it clear.

  4. Don't duplicate the full text of your blog or github here. Just post the link for folks to click.

  5. Submission headline should match the article title (don’t cherry-pick information from the title to fit your agenda).

  6. No trolling.

Resources:

Any issues on the community? Report it using the report flag.

Questions? DM the mods!

founded 2 years ago
MODERATORS
47
Reverse proxy (lemdro.id)
submitted 6 months ago* (last edited 6 months ago) by [email protected] to c/selfhosted
 

I have an openwrt router at home which also acts as my home server. It's running a bunch of services using docker (Jellyfin, Nextcloud, etc.)

I have set up an SSH tunnel between my openwrt router and VPS and can access jellyfin successfully.

I understand that I need to set up a reverse proxy to access multiple services and have https.

But I'm confused if I should set up this reverse proxy on the VPS or on the router itself. Is nginx the easiest option? Should i add subdomains in cloudflare for every service?

Pease don't recommend vpns since they are all blocked where i live (wireguard, tailscale openVPN, etc.) I'm limited to using ssh tunneling only.

Thanks

all 41 comments
sorted by: hot top controversial new old
[–] [email protected] 27 points 6 months ago (1 children)

I should also add something that lots of beginners miss.

The reverse proxy does not care what the domains that you define in it actually resolve to. It receives the domain name as a HTTP header which is completely at the whim of the client. As long as that domain name matches one of the domains defined in the proxy, it's all good.

You can successfully connect to a proxy with a domain name defined in the domain owner's DNS, or you can make up your own DNS that says whatever you want, or you can define any domain->IP association you want in your hosts file, or you can simply use curl or wget to connect directly to the proxy IP and lie about the domain in the HTTP headers without having it resolve in any DNS.

This means that yes, the proxy will happily serve your "private" *.local.example.com services to someone connecting from outside your LAN. All they have to do is figure out (or guess) your subdomain names. You need to add IP restrictions in the proxy (default deny from all + lan ip mask explicit exception) if you really want those services to be restricted to the LAN.

DNS is not security, it's a public service that maps domains to IPs.

TLS is only security in the sense it protects the connection en route from eavesdropping, but it doesn't restrict access.

[–] [email protected] 2 points 6 months ago (1 children)

Thanks I understand the theory behind this but I can't get it to work.

I have a jellyfin.mydomain.com subdomain pointing at my VPS ip. On my home server I have Nginx Proxy Manager listening to 192.168.8.1:8998 (http) and 8999 (https) From my home server I forward port 80 from the VPS to local port 8999 like this:

ssh -R 80:127.0.0.1:8998 root@vps-ip

Then on npm I define a proxy to localhost:8096 (jellyfin) for any traffic sent to jellyfinn.mydomain.com.

But I can't access jellyfin remotely.

[–] [email protected] 4 points 6 months ago

Check all the steps individually then:

  • check that the ip resolves to the VPS IP at the location you're testing this
  • set up the tunnel to bypass the proxy (connect it directly to jellyfin)
  • check that jellyfin works directly
  • check the proxy directly, with curl connected to the proxy with the header "Host" set to the domain
  • check that the VPS firewall didn't block port 80
  • normally you wouldn't be able to forward port 80 with a normal ssh user but I see you're logging in as root so it should be working
[–] [email protected] 9 points 6 months ago (1 children)

Maybe look into https://nginxproxymanager.com/ it makes it quite easy to set up.

[–] [email protected] 0 points 6 months ago

Thank you very much my question is should npm be installed on my VPS or my local server? What SSH command should I use to connect the two machines in a way that npm works?

[–] Neon 6 points 6 months ago (3 children)

If you are new i recommend "Caddy V2"

It is by far the easiest.

Wait with Nginx until you're better. (and even then, use linuxserverio/swag instead of nginx)

[–] [email protected] 5 points 6 months ago

Caddy was exactly what i needed. It magically solved the problem..

[–] [email protected] 3 points 6 months ago* (last edited 6 months ago) (1 children)

As someone who used caddy over years, I can't completely agree.

Caddy has some downsides (nextcloud needs special setup for example) and not everyone is familiar with writing a Caddyfile. (Json)

For someone new I would recommend "nginx proxy manager". Easy to install with docker and self explained through GUI.

[–] Neon 2 points 6 months ago (1 children)

i actually think NPM is more confusing. 1: there are practically always already finished Files for Caddy V2. Most of the times directly in the Repo of the Project. A lot of Devs use Caddy themselves. 2: NPM exposes a lot of Options additionally. This can confuse newcomers. With Caddy, all these extra options are invisible. you just write and see "reverse_proxy jellyfin" and that's it.

[–] [email protected] 2 points 6 months ago

Completely agree. I haven't used NPM since I started self hosting a few years ago, but I was never able to get it to work right. I ended up using apache2 as it was pretty well documented everywhere. Moved to caddy v1 when I found it as the config is so easy to write and understand. Moved to v2 when it was released and had no issues. Their forum is incredibly helpful if you run into any issues. At this point its a "relatively" mature platform and most projects I've setup have an example config (usually just 1 or 2 lines because that's all you need).

[–] [email protected] 2 points 6 months ago

Swag was my nginx introduction, and it was mildly confusing because I ran it on docker and didn't understand how to edit configs at the time. I'd recommend following a guide instead of winging it like I did 😅

[–] [email protected] 5 points 6 months ago

I know this isn't what you asked but I would move any hosted services outside of DNS to a separate device.

[–] [email protected] 4 points 6 months ago (1 children)

There are pros and cons to keeping the proxy on the VPS or at home.

If you keep it at home you will have end-to-end encryption from the browser to your home server. Downside, you will not get the IP of the remote client, just the IP of the router, so you won't be able to do IP blocking or diagnostics.

By putting the proxy on the VPS and decrypting HTTPS there you can add remote IPs to connections but you have to keep the TLS certificate on the VPS so in theory someone could mess with it.

A third option is to run a minimal passthrough proxy on the VPS that adds the remote IP to the HTTPS connections without decrypting them. To do this you must use the same proxy at both ends (home and VPS) and both must have the PROXY protocol enabled.

I would suggest doing just proxy at home to start with because it's simpler. If you want a GUI use NPM (Nginx Proxy Manager) it's super easy. If you prefer a proxy where you write config by hand use Caddy.

After you have it working at home you can consider adding the one on VPS and enabling the PROXY protocol. Although I'm not 100% sure Caddy supports it, look into it. You may have to use Nginx in both places I'd it doesn't.

You do not need to add subdomains in DNS, not unless you want to. You just need one domain to point an A/AAAA record at the VPS public IP, then you can make the subdomains a wildcard CNAME pointing at the base domain. So A/AAAA example.com -> IP, and CNAME *.example.com -> example.com. Or you can put the A in another domain and point the CNAME at that.

When requesting TLS certificates it's the same thing, you never ask for explicit certificates for each subdomain, you just ask for one wildcard certificate for *.example.com. Aside from the obvious benefit of not having to add and remove certificates every time you add or remove subdomains, there's the not obvious benefit of not having bots learn about your subdomains (certificate application are public records).

The subdomains do not need to resolve in DNS for this to work, the certbot verifies that you own the domain by using a DNS API key to create a temporary TXT on example.com; as long as that works it won't care what's actually defined in there.

[–] [email protected] 1 points 6 months ago (2 children)

Thanks for the detailed reply. But I'm still confused. Do I need a separate ssh tunnel for every single service I run on my local server?

[–] [email protected] 2 points 6 months ago

No, that's the magic of the reverse proxy. You can transport all HTTP services through just one port. It will route them to the correct service on your service based on the domain (which is passed through the HTTP headers).

It won't work for non-HTTP services, for those you'll have to make a separate ssh tunnel per port.

[–] [email protected] 1 points 6 months ago

The reverse proxy is going to have a config that says "for hostname 'foo' I should forward traffic to foo.example.com:port".

If you setup the rproxy at home then ssh just needs to forward all port 443 traffic to the rproxy. It doesn't care about hostnames. The rproxy will then get a request with the hostname in the data and forward it to the appropriate target on behalf of the requester.

If you setup the rproxy at the vps then yes - you would need to forward different ports to each backend target. This is because the rproxy would need to direct traffic to each target individually. And if your target is "localhost" (because that's where the ssh endpoint is) then you would differentiate each backend by port.

[–] [email protected] 3 points 6 months ago* (last edited 6 months ago)

Acronyms, initialisms, abbreviations, contractions, and other phrases which expand to something larger, that I've seen in this thread:

Fewer Letters More Letters
DNS Domain Name Service/System
HTTP Hypertext Transfer Protocol, the Web
HTTPS HTTP over SSL
IP Internet Protocol
SSH Secure Shell for remote terminal access
SSL Secure Sockets Layer, for transparent encryption
TLS Transport Layer Security, supersedes SSL
VPN Virtual Private Network
VPS Virtual Private Server (opposed to shared hosting)
nginx Popular HTTP server

10 acronyms in this thread; the most compressed thread commented on today has 6 acronyms.

[Thread #738 for this sub, first seen 5th May 2024, 12:15] [FAQ] [Full list] [Contact] [Source code]

[–] [email protected] 3 points 6 months ago (1 children)

How can something like Tailscale be blocked?

[–] bin_bash 3 points 6 months ago

Check "boring proxy" On github easy to install and configure and does https for you

[–] [email protected] 3 points 6 months ago (1 children)

Either you run the RP in the VPS and point to the ips on your server or you run it on the server and access it like you are accessing Jellyfin.

Easiest option is a container with Nginx proxy manager (imo) with NPM you can get free let's encrypt certs, but be aware, in case you want automated certificates, NPM will need to run on the machine pointed to by the DNS (in your case, your VPS I guess)

[–] pyrosis 2 points 6 months ago

Usually a reverse proxy runs behind the firewall/router. The idea you are pointing 80/443 at the proxy with port forwarding once traffic hits your router.

So if someone goes to service.domain.com

You would have dynamic DNS telling domain.com the router is the IP.

You would tell domain.com that service.domain.com exists as a cname or a record. You could also say *.domain.com is a cname. That would point any hosttname to your router.

From here in the proxy you would say service.domain.com points to your services IP and port. Usually that is would be on the lan but in your case it would be through a tunnel.

It is possible and probably more resource efficient to just put the proxy on the VPS and point your public domain traffic directly at the VPS IP.

So you could say on the domain service.domain.com points to the VPS IP as an a record. Service2.domain.com points to the VPS IP as another a record.

You would allow 80/443 on the VPS and create entries for the services

Those would look like the service.domain.com pointing to localhost:port

In your particular case I would just run the proxy on the public VPS the services are already on.

Don't forget you can enable https certificates when you have them running. You can secure the management interface on its own service3.domain.com with the proxy if you need to.

And op consider some blocklists for your vps firewall like spamhaus. It wouldn't hurt to setup fail2ban either.

[–] [email protected] 1 points 6 months ago

It depends where you want the complexity.

Since ssh is a layer4 tunnel if you don't run a proxy on your home box, you'll need a new network connection for each service, if you are fine with that, I would set it up only on the VPS. This means if the tunnel goes down, you should at least get 502 error rather than a timeout or connection refused.

Alternatively you could forward 80, 443 to a proxy service on the home server. That would require two ports for the ssh.

You can drop it to a single ssh connection by having a proxy on both and just have the VPS proxy Http and https to the same port on the home server.

[–] just_another_person -4 points 6 months ago* (last edited 6 months ago) (1 children)

Firstly...why are you routing your home stuff through a VPS? I'm confused on what is happening here.

If you just want to access your things remotely, setup a VPN server on the router, and connect to it that way. You also dont need a reverse proxy or SSL if you're already accessing things over a secured connection. Where did you get this info from?

[–] [email protected] 2 points 6 months ago (2 children)

Please read the post man, all VPNs are blocked on the protocol level

[–] [email protected] 0 points 6 months ago (1 children)

That's not how VPNs work, you can't just "block all of them". I think OP just needs to use a pure-TLS VPN solution (like SoftEther) or an obfuscated one like shadowsocks/obfs from a not-super-well-known provider (or self-host it on a VPS/etc.) and they should be golden.

[–] [email protected] 2 points 6 months ago (1 children)

They sniffing the traffic with DPI and block vpn tech on protocol level, so easy detectable things like OpenVPN, Wireguard and Tailscale doesn’t work anymore

[–] [email protected] 1 points 6 months ago

I understand, that's why I suggested some non-easily-detectable solutions.

[–] just_another_person 0 points 6 months ago* (last edited 6 months ago) (2 children)

That was added later, obviously. Even still, you don't need a VPS for this. This is overly complex .

If SSH works, just forward ports and be done with it.

[–] [email protected] 2 points 6 months ago (1 children)

I don't want to remember port numbers. I'm trying to give each service its own subdomain.

[–] just_another_person -3 points 6 months ago

Beggers CAN be choosers, apparently 🤦

[–] [email protected] 1 points 6 months ago

VPS

You should if your ip is private, not public.