Every failed NPM install that 'should work' usually fails at the same invisible step: the domain name never actually pointed at the server. DNS is five minutes of work that decides everything after it.
Nginx Proxy Manager routes traffic by name, and Let's Encrypt issues certificates only for names that provably point at your machine. So before containers and certificates, the name has to resolve. This page covers the one DNS record you need, how to prove it works before you continue, and the two home-internet traps — dynamic IPs and CGNAT — that make honest setups fail for reasons that have nothing to do with NPM.
Log in wherever your domain is managed — the registrar or a DNS host like Cloudflare — and add an A record. The Name is the subdomain word only (app, photos, files), and the Value is your server's public IP address. Every service gets its own record, and they can all point at the same IP — that is normal and expected. Set a short TTL like 300 seconds while you are testing, so mistakes fade in minutes instead of hours; you can lengthen it later.
The address you need is the one the internet sees, not the 192.168 address of the server. From any device on the same network, open a 'what is my IP' page, or run curl ifconfig.me in a terminal. Then compare it with the WAN address shown in your router's status page. If the two numbers differ, stop — your connection is behind CGNAT, explained below, and no DNS record can fix that. If they match, that is the value for your A record.
Never guess that DNS has propagated — check it. Run nslookup app.yourdomain.com or, cleaner, nslookup app.yourdomain.com 1.1.1.1 to ask a public resolver directly. The answer must be your public IP. Also test from your phone with Wi-Fi off, because your home router may answer differently inside the house. Only when an outside network resolves the name to your IP is it safe to create the proxy host and request a certificate. Requesting a certificate against broken DNS wastes Let's Encrypt attempts, and repeated failures can rate-limit you for hours.
Many home ISPs now place whole neighbourhoods behind one public address — carrier-grade NAT. Your router's WAN address is then a private address (often in the 100.64 range), port forwarding on your router forwards nothing, and your A record points at an address shared with strangers. Symptoms: DNS is correct, ports are 'open', and nothing ever arrives. The honest options are to ask the ISP for a public or static IP (sometimes a small fee), rent a tiny VPS and proxy from there, or use a tunnel service that dials out instead. NPM itself cannot fix CGNAT, and no setting inside it will.
If your public IP changes whenever the router reconnects, your A record quietly points at a stranger's connection. The fix is a dynamic DNS updater: a small program on the server or a setting in the router that watches the public IP and rewrites the DNS record when it changes. Many registrars and DNS hosts provide this free. Set it up on day one, not after the first mysterious outage — with a dynamic IP, 'the site broke overnight' almost always means 'the address moved and DNS did not follow'.
The video shows the complete flow from a fresh server to a working name with HTTPS — watch the order the steps are done in, because the order is the lesson.
▶️ Watch Full VideoWith a short TTL, usually minutes; occasionally up to a few hours at slow resolvers. Check against a public resolver like 1.1.1.1 — if it answers correctly, the record is live and any remaining problem is local caching.
Yes — a wildcard record (*.yourdomain.com) points every subdomain at your IP at once. Handy in a lab, but an explicit record per service is clearer and avoids surprise names resolving.
Edit where the nameservers point — that is the DNS host that actually answers queries. If your domain uses Cloudflare nameservers, the record must be added in Cloudflare, not at the registrar.