this service is integral to making everything work together, and securing exposed services. what i mean is that, with a reverse proxy, when visitors visit your services web page, they first go through your public ip address on port 443, then from there is a port forwarding rule to forward all https requests to the reverse proxy. npm then has proxy hosts configured, where if traffic matches a specific subdomain or apex domain, it will send the visitor to the correct service. this makes for a more secure infrastructure. obviously, port forwarding is still not ideal as it exposes ports on your public ip address.
i mean, it is better than just exposing certain ports on your public ip address that goes straight to the server. take for example a minecraft server. you would have to expose ports 25565 and or 19132 on your public ip address which then are forwarded to your minecraft server. when giving your minecraft server to others, you will have to expose your public ip address. you can setup dns records with a domain, but the dns a record will still resolve to your public ip address.
which is why playitgg exists and why server hosting exists, whether you host it yourself in the cloud or a minecraft server provider.
a critical feature that npm offers is the use of lets encrypt ssl certificates for your web services. this is one hundred percent free so long as you have a valid and registered domain name. by using a dns01 challenge to your domain, whether it be through acme records or an api key, it will prove that you are the owner of a domain. from this, you can generate a wildcard certificate, meaning that you can create several subdomains under your domain with a single certificate, instead of multiple certificates for each service. this simplifies certificate management, and with npm, it will automatically renew your certificates.
you can combine this in two ways: local ssl certificates and public ssl certificates. what does this mean?
local ssl certificates: two ways
- first solution
- create an a record in your domain dns settings that points to your reverse proxy’s local ip address. then create a wildcard cname record, essentially points * to the a record created as the target. so whenever a service is accessed, it will point to your reverse proxy, and because you created and assigned wildcard certificates that are linked to your verified domain, it will propagate within your local network.
- second solution
- this is the way i do it since my apex domain is pointed to github pages.
- setup a dns server, i use adguard since it comes with dns rewrites. the setup is the same where you generate a wildcard certificate with a dns01 challenge in npm. where you create the dns entries is with your dns server. in adguard i simply add the fully qualified domain name (service.domain.com) and that is rewritten to the local ip address of npm. this will provide the same functionality as above. this works well as you want control over which services you want to expose to the internet versus locally.
- bonus solution
- if you do not have a domain, you can use a free dns service like duckdns. the process is the same, you create an duckdns dns record that points to your npm local ip address. when generating a wildcard certificate, you can include the apex domain as well. in the dns01 challenge, select the provider as duckdns and paste in your token from your duckdns dashboard. create your proxy hosts, add the ssl certificate and force ssl. dns server is not needed as the duckdns domain you created already points to npm. which means that wildcard certificates are super helpful for simple deployments.
public ssl certificates: a few ways
- first solution
- if you have a cloudflare domain like me, you can utilize their zero trust free tier to create cloudflared tunnels. simply go to your dashboard and on the left side you should see zero trust. click that and it will take you to their zero trust dashboard. then click on networks, then tunnels. from there create a new tunnel, selected cloudflared, and give your tunnel a name. then the next option allowed you to install the connector, you can decide which one you want, i go with either debian or docker install. once installed, it will show below that it is connected. from there you can create a public hostname, this is similar to the proxy hosts in npm. enter the local ip address of your service and the port, and enter the subdomain or apex domain you would like the service to be available on. if your service has https, be sure to go to additional settings and select the no tls verify button. now, depending how fast dns propagates with cloudflare’s dns servers, your service is now “exposed” behind their proxy servers.
- now that the service is exposed, we can force https for all of our services and cloudflare will generate a free ssl certificate for us. go to ssl/tls overview section and configure to use the full configuration. then within the same section go to the edge certificates and check these options: always use https, opportunistic encryption, tls 1.3, and automatic https rewrites.
- second solution
- if you want to expose services without a cdn proxy like cloudflare you can go with this. first you have to figure out port-fowarding on your router. i can not speak for all routers since we may have different ones, but refer to your router’s manual and documentation. you will want to forward the ports 443 and 80, it should be something like source ip and source port. source ip will be 0.0.0.0 meaning any ip address. source port will be 443 and 80, if your router has an option for type, use tcp. then the destination ip address will be your npm or reverse proxy server, and destination port will be 443 and 80. unless you have a custom configuration, those will be the defaults for the destination. next the process is the same, create a dns a record in your domain’s dns settings. subdomain pointing to your public ip address. now this part can be in two:
- if you want to avoid “exposing” your public ip address with an a record, you can setup a cname record that points to another domain. this can be through duckdns, where you can create a new subdomain under their domain to point to your public ip address. the setup would be to create a cname record that creates a subdomain that points to the subdomain of your duckdns domain. you should have configured a name for the cname record, and a target, which is your duckdns domain.
- the other way would just be creating a separate a record that points to your public ip address and then using that a record as the target for your cname record. example: a record name “cname.domain.com”, and then a cname record “server.domain.com” target=”cname.domain.com”. works the same, but you are eliminating the use of duckdns. your public ip will still be exposed regardless, but jut another way.
- okay now that we figured out which subdomains are accessible publicly, we still have to configure npm’s proxy hosts. same process, create a proxy host, assign the same a or cname record subdomain, the local ip address and port of the service, assign the wildcard certificate by using a dns01 challenge, and force ssl.
- if you want to expose services without a cdn proxy like cloudflare you can go with this. first you have to figure out port-fowarding on your router. i can not speak for all routers since we may have different ones, but refer to your router’s manual and documentation. you will want to forward the ports 443 and 80, it should be something like source ip and source port. source ip will be 0.0.0.0 meaning any ip address. source port will be 443 and 80, if your router has an option for type, use tcp. then the destination ip address will be your npm or reverse proxy server, and destination port will be 443 and 80. unless you have a custom configuration, those will be the defaults for the destination. next the process is the same, create a dns a record in your domain’s dns settings. subdomain pointing to your public ip address. now this part can be in two:
- second and a half solution
- this solution pretty much is the second one, but if you want to use cloudflare’s proxy servers, but do not have access or do not want to install their cloudflared connector, this is the way. set everything up exactly from the second solution, but when creating your cname or a record for your exposed service, check the proxy status button. this will proxy traffic to their servers then to your local service.
this is the whole structure that we are trying to secure with a reverse proxy:
visitor goes to your website.
the request gets forwarded to your public ip address, either directly or through cloudflare’s cdn proxy.
then the request goes from your router to your reverse proxy, either from your public ip or a cloudflare proxy ip.
your reverse proxy checks the subdomain or domain of the service, then points to the local service.
this setup is crucial as you want your data protected with https ssl/tls encryption, but also your site viewers as well.
the best case scenario is to not expose anything at all, which is why creating local ssl certificates with a domain name and then using a vpn to have remote access to your network is a safer alternative. this still means exposing the vpn port for wireguard, openvpn, l2tp, p2p, ipsec, or whatever you use, but it is better than exposing more ports.
the only use case that i see fit to expose a service using npm and no proxy or vpn would be maybe exposing a next cloud instance. you would want as much bandwidth to upload your files, and if you’re routing your traffic through a vpn or cloudflare’s cdn proxy network, it will slow it down.