Free tools Windows power users keep installed
One-click scans. No signup required.
Set up NGINX in a private subnet, define an upstream group containing the backends’ private IP addresses or private DNS names, and send requests to that group with proxy_pass. Keep the backend firewall limited to NGINX’s security identity, add the required routes and return paths, and validate the configuration from both sides of the connection. For HTTP and HTTPS you configure the http context; for databases and other TCP or UDP services you use the stream module.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
A private design does not merely hide an address. NGINX, the clients, and the backend servers must have reachable private routes, and every subnet ACL, security group, network security group, host firewall, and health-probe rule must allow the intended flow. The backend machines can remain without public IP addresses when the network is designed correctly.
As an Amazon Associate I earn from qualifying purchases.
What a private NGINX load-balancer design looks like
The usual arrangement places NGINX and the application servers in a private virtual network. Clients reach a private NGINX listener directly, or reach an internal cloud load balancer that forwards to NGINX. NGINX then opens connections to backend addresses that are reachable only over the private network.
An internal load balancer is different from a public-facing load balancer: it has only private addresses, and its targets do not need public IP addresses. The same principle applies when NGINX itself is the private listener. Public exposure is optional and should be limited to a separate edge tier if internet users must access the application.
#1 Best Overall
| Design | Client-facing address | Backend address | When it fits |
|---|---|---|---|
| Private NGINX listener | Private IP or private DNS name | Private IP or private DNS name | Internal applications, corporate networks, service-to-service traffic |
| Internal cloud load balancer in front of NGINX | Private virtual IP | Private NGINX and backend addresses | Highly available private entry point managed by the cloud platform |
| Public edge plus private NGINX and backends | Public edge address | Private addresses after the edge | Internet applications that still need to keep application servers off the public internet |
Choose the network layout before writing NGINX configuration. Place the listener and targets in the same virtual network where practical. If they are in separate networks, provide peering, a VPN, or a private-link service, and verify that routes exist in both directions. Azure documentation notes that virtual-network peering can preserve more load-balancing capabilities for some scenarios than a private-link arrangement; the right choice depends on the topology and service you are publishing.
Prerequisites to check before configuring NGINX
Addressing and routes
- Reserve a private address for the NGINX listener, such as
10.0.1.10. - Assign private addresses or private DNS records to each backend, such as
10.0.2.11and10.0.3.11. - Confirm route-table entries from the client network to NGINX and from NGINX to every backend subnet.
- Confirm return routes from the backend subnets to the NGINX address. A one-way route can allow a TCP SYN to arrive while replies fail.
- If networks are connected through peering or a VPN, check that overlapping address ranges are not blocking the route.
DNS and naming
Private DNS names are preferable when instances are replaced or scaled. For example, an internal name such as app-1.internal.example can continue to identify a service while its private address changes. Test name resolution from the NGINX host itself; a name that resolves on an administrator’s workstation may not resolve in the NGINX subnet.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteFirewall identities
Allow clients to reach only the NGINX listener ports they need. On the backend side, allow the application and health-check ports from the NGINX security group, network-security-group identity, or tightly scoped private source ranges. Do not broadly allow an entire virtual network when a specific NGINX identity is available.
Health checks are a separate flow. If a cloud load balancer probes NGINX or a backend, its probe source and port must be allowed independently of normal application traffic. On Azure, health probes commonly use the AzureLoadBalancer service tag; host firewall policy may also need to account for 168.63.129.16. Restrict the rule to the probe ports rather than opening all backend ports.
Rank #2
Install NGINX and confirm the required module
Install a distribution package or a vetted build of NGINX on the private listener host. The HTTP reverse-proxy module is normally included in standard builds. TCP and UDP proxying requires the NGINX stream module, either compiled into the binary or loaded as a dynamic module. Verify the build before planning a non-HTTP service.
nginx -V
Review the output for the stream module or the module-loading configuration used by your operating system. Package names and module paths vary by distribution, so use the package manager and service layout documented for that host. Keep configuration files readable only by administrators, especially when they reference TLS private keys.
Configure an HTTP or HTTPS private upstream
1. Define the private upstream group
Create an upstream group in the top-level http context. Each server entry contains a private address and the application port. The example below uses illustrative addresses and values; replace them with addresses that exist in your network.
http {
upstream app_private {
server 10.0.2.11:8080 max_fails=3 fail_timeout=10s;
server 10.0.3.11:8080 max_fails=3 fail_timeout=10s;
# least_conn; # uncomment when connection duration varies
# ip_hash; # uncomment only when client affinity is required
}
server {
listen 10.0.1.10:443 ssl;
server_name app.internal.example;
ssl_certificate /etc/nginx/tls/app.crt;
ssl_certificate_key /etc/nginx/tls/app.key;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://app_private;
}
}
}
NGINX uses round-robin when no balancing method is specified. The proxy_pass directive references the upstream group by name, so a request arriving at the private listener is distributed among the configured servers. The forwarding headers preserve the original host, client address, proxy chain, and client-side protocol for applications that need them.
2. Choose the balancing behavior
| Method or option | Use it when | Important limitation |
|---|---|---|
| Round-robin (default) | Backends are comparable and requests have similar cost. | It does not account for long-lived or unusually expensive connections. |
least_conn; |
Connections remain open for different lengths of time, such as APIs with uneven work. | It balances connection counts, not the CPU or memory cost of each request. |
ip_hash; |
A session requires basic client-address affinity. | Distribution becomes less even, and clients behind a shared NAT address may be treated as one client. |
| Generic hashing | You need a stable key other than the client IP, such as a request attribute. | The selected key and failure behavior must match the application’s session model. |
| Weights | One server has more capacity than another. | A weight expresses relative traffic preference; it is not a performance guarantee. |
| Backup server | You want a standby node used only when regular peers are unavailable. | The standby is not receiving normal traffic, so capacity and failover behavior should be tested separately. |
Use one method deliberately. Affinity can be necessary for legacy sessions, but it also reduces the freedom to spread load and can concentrate traffic when many users share an address.
3. Bind only to the intended private address
The listen 10.0.1.10:443 ssl; line binds NGINX to the private address rather than every interface. If you need a private HTTP listener instead, use the appropriate private address and port. Make sure the address is actually assigned to the host or provided by the internal load balancer; otherwise NGINX will fail to bind during startup.
4. Protect the client-facing TLS endpoint
Install the certificate and key for the private name in paths readable by NGINX. Private DNS does not automatically provide encryption or identity. If clients validate the certificate, the certificate must contain the internal hostname they use. Restrict access to the listener with security-group or network-security-group rules even though the address is not public.
Configure TCP or UDP services with the stream module
HTTP directives cannot proxy a database, DNS service, LDAP endpoint, or another arbitrary TCP or UDP protocol. Define those services in a stream block. The protocol is selected at the listen level, and every upstream server must include an explicit destination port.
Rank #4
stream {
upstream db_private {
server 10.0.2.21:5432;
server 10.0.3.21:5432;
}
server {
listen 10.0.1.10:5432;
proxy_connect_timeout 5s;
proxy_timeout 60s;
proxy_pass db_private;
}
}
In a stream configuration, proxy_pass db_private; names the upstream group without an HTTP URL scheme. Set timeouts according to the protocol: a database session may need a longer idle timeout than a short request-response service, while an overly long connect timeout can delay failover.
Lock down security groups, NSGs, ACLs, and host firewalls
Client to NGINX
- Allow only approved client CIDRs to the private listener port, such as TCP 443 for HTTPS or the specific stream port.
- If an internal cloud load balancer fronts NGINX, allow the load balancer’s private source identity rather than arbitrary virtual-network traffic where the platform supports that control.
- Keep administrative ports separate and restricted to management networks.
NGINX to backends
- Allow the application port from the NGINX security group or private source range.
- Allow the health-check port from the actual probe source. A probe may use a different port from application traffic.
- Permit return traffic through subnet ACLs and host firewalls.
- Deny direct client access to backend ports unless a separate, documented workflow requires it.
A successful connection to NGINX proves only that the first network segment works. From the NGINX host, test each backend address and port. Then inspect backend logs to verify that the connection source is the NGINX private address or the expected translated address.
Encrypt and verify NGINX-to-upstream traffic
Private routing reduces exposure but does not make a network intrinsically trusted. Use TLS on the upstream hop when credentials, personal data, or service-to-service trust require encryption and authentication. Change the upstream URL to https:// and configure the internal certificate authority.
location / {
proxy_pass https://app_private;
proxy_ssl_trusted_certificate /etc/nginx/tls/internal-ca.pem;
proxy_ssl_verify on;
proxy_ssl_verify_depth 2;
proxy_ssl_protocols TLSv1.2 TLSv1.3;
}
proxy_ssl_trusted_certificate identifies the CA bundle used to validate backend certificates, while proxy_ssl_verify on; turns verification on. The certificate presented by each backend must chain to that CA and contain the name NGINX uses for verification. If the backends require mutual TLS, configure the corresponding client certificate and key as well. Test certificate expiry, hostname matching, and CA rotation before putting the pool into service.
Validate the configuration and private path
- Check syntax. Run
nginx -t. Review the expanded configuration if your installation supports a dump option, and correct missing semicolons, module errors, certificate paths, or duplicate listeners before reloading. - Reload safely. Use the service manager appropriate to the host operating system. On a systemd host, a common command is
sudo systemctl reload nginx; confirm the command and service name for your distribution. A reload should preserve existing connections while workers adopt the new configuration. - Test from an allowed client network. Resolve the private name, connect to the private listener, and send the expected
Hostheader. Confirm that the response and application logs show the forwarded client and protocol headers you configured. - Test each backend from NGINX. Open a TCP connection to every private address and port. For HTTPS upstreams, validate the certificate chain and hostname from the NGINX host, not just from a workstation.
- Exercise failure handling. Stop or isolate one backend and verify that requests continue through healthy peers. Restore it and observe that it re-enters service after the configured failure interval.
- Review telemetry. Inspect access and error logs, upstream status, connection time, response time, and failure counters. Alert on sustained upstream failures rather than a single transient error.
- Confirm the negative cases. Verify that public interfaces and direct backend ports are denied, while health probes and approved private clients still succeed.
Understand passive health behavior and its limits
Open-source NGINX uses passive failure handling in this configuration. With max_fails=3 and fail_timeout=10s, repeated unsuccessful attempts cause NGINX to avoid that peer temporarily according to those parameters. This is not the same as an independent, continuously running health check: a server that receives no traffic may not be tested until a request is sent.
Choose failure thresholds from the application’s behavior. A low threshold can remove a server during a short dependency outage; a high threshold can keep sending traffic to a broken node. NGINX Plus provides additional active-health and persistence capabilities, but those features and licensing are separate from the open-source passive model shown here.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Troubleshoot common private-network failures
| Symptom | Likely cause | Checks and correction |
|---|---|---|
NGINX will not start after adding listen |
The private address is not assigned, the port is already bound, or the stream module is unavailable. | Run nginx -t, inspect interface addresses and listeners, and verify module availability with nginx -V. |
| Clients can reach NGINX but receive 502 or 504 | Backend route, firewall, port, DNS, or application failure. | From NGINX, resolve the backend name and connect to its port. Check route tables, return routes, security rules, and backend logs. |
| Only one backend receives traffic | Other peers are failing, DNS resolves incorrectly, or affinity is enabled. | Inspect upstream error logs, test every address directly, and review whether ip_hash, weights, or backup status is intentional. |
| Health probe reports unhealthy while application tests pass | The probe source or port is blocked, or the probe path returns an unexpected status. | Allow the documented probe identity and port, including Azure probe requirements where applicable, and test the exact probe path. |
| Upstream TLS handshake fails | Untrusted CA, hostname mismatch, expired certificate, unsupported protocol, or missing client certificate. | Validate the chain and name from NGINX, check the configured CA file, and align protocol and mutual-TLS settings. |
| Connections hang intermittently | Asymmetric routing, restrictive ACLs, idle timeouts, or overlapping network ranges. | Trace both directions, compare subnet and host firewall rules, and adjust protocol-appropriate timeout values. |
| Backends are unexpectedly exposed | A broad security rule, public address, or route bypasses NGINX. | Remove public backend addresses where unnecessary and restrict backend ingress to the NGINX identity and required probe sources. |
Operational practices for a durable private balancer
Use names for changing pools
Private DNS lets you replace instances without editing every client. If your NGINX version and resolver design support dynamic name resolution, plan how records are refreshed and how stale addresses are removed. Otherwise, schedule controlled configuration updates when the pool changes.
Separate listener, application, and management planes
Use distinct security rules for client traffic, NGINX-to-backend traffic, health probes, and administration. This makes an accidental rule change less likely to expose a management port or a database listener.
Test failover during maintenance windows
Stopping a node is more informative than checking configuration syntax alone. Test one backend at a time, observe connection draining and application behavior, then restore the node and verify re-entry. Include the internal load balancer layer in the test if one fronts NGINX.
Monitor the path, not only the process
An NGINX process can be healthy while every upstream route is broken. Monitor listener reachability, backend connect failures, upstream latency, response status, certificate expiry, and health-probe state. Keep logs for enough time to correlate a network-rule change with an outage.
Recommended Free Tools
Quick Recap
Decision guide: which private setup should you choose?
- Internal HTTP application: Use an
httpupstream, round-robin by default, and TLS on the listener. Addleast_connfor uneven connection lifetimes or affinity only for a demonstrated session requirement. - Private database or other non-HTTP service: Use the stream module, specify every backend port, and set connect and idle timeouts for that protocol.
- Internet-facing application with protected servers: Keep the public edge separate, route into a private NGINX tier, and allow backend ingress only from that tier.
- Separate virtual networks: Use peering, VPN, or Private Link with explicit routes and return paths. Confirm which option preserves the load-balancing behavior your cloud platform requires.
- Sensitive data on the internal hop: Use verified upstream TLS rather than relying on private addressing as the only trust boundary.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




