What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
The production pattern is straightforward: build Angular into static files, let Nginx serve those files, and reserve an API path such as /api/ for requests that Nginx forwards to Node.js. Add an SPA fallback for Angular routes, pass the original host and client information in headers, terminate HTTPS at Nginx, and configure HTTP upgrade headers if the Node application uses WebSockets.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
This guide shows a complete baseline configuration, explains the URI behavior that commonly causes proxy bugs, and covers development proxies, TLS, scaling, caching, deployment, and diagnosis.
As an Amazon Associate I earn from qualifying purchases.
Recommended Free Tools
How the deployment is divided
Nginx is the public entry point. It listens on the web ports, serves Angular’s compiled HTML, JavaScript, CSS, and image files, and forwards only selected paths to Node.js. Node can therefore listen on a private interface and port such as 127.0.0.1:3000 instead of accepting Internet traffic directly.
A request for https://example.com/ is handled by Nginx’s static-file configuration. A request for https://example.com/api/orders is matched by the API location and sent to the Node upstream. A browser-side Angular route such as /reports/weekly is not a real file, so Nginx must internally serve index.html; otherwise refreshing that route returns a 404.
#1 Best Overall
Prerequisites and assumptions
- Nginx is installed on the server and can bind to ports 80 and, for production, 443.
- The Node.js application is running and listening on a known address and port. The examples use
127.0.0.1:3000. - You have built the Angular application and know the directory containing its generated
index.html. Recent Angular builds commonly place browser output below a path such asdist/my-app/browser; use the actual directory produced by your project. - Your DNS name, represented below by
example.com, resolves to the Nginx server. - You can edit the applicable Nginx server configuration and inspect both Nginx and Node.js logs.
The hostname, filesystem path, Node port, certificate paths, and API prefix in this article are examples. Replace them with values from your deployment.
Build Angular for production
Use the Angular build command defined by your project to create distributable browser assets. The important result is a directory containing index.html and the compiled assets, not the command name itself. After building, verify the output before changing Nginx:
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →- Locate the generated directory, for example
/var/www/angular/dist/my-app/browser. - Confirm that
index.htmlexists directly in that directory. - Copy or publish the complete directory to the server, preserving the asset subdirectories and filenames.
- Ensure the Nginx worker account can read the files and traverse every parent directory.
If index.html is nested one level deeper than expected, correct the Nginx root; do not try to compensate with unrelated rewrite rules.
Configure the Node upstream and Angular static site
Create an upstream group and a server block. This HTTP-only baseline is useful for initial validation:
upstream node_backend {
server 127.0.0.1:3000;
}
server {
listen 80;
server_name example.com;
root /var/www/angular/dist/my-app/browser;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://node_backend;
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;
}
}
Put the upstream block at the Nginx configuration level where upstream groups are allowed, not inside a location. The server_name, root, and port are deployment-specific.
Why the SPA fallback matters
try_files $uri $uri/ /index.html; first checks whether the requested path maps to a real file or directory. Existing JavaScript, stylesheets, images, and other assets are served normally. If no file exists, Nginx internally serves Angular’s entry document, allowing the Angular router to interpret the client-side URL. Without this fallback, direct navigation or a browser refresh on a route such as /settings usually produces a server-side 404.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Keep API matching ahead of the general site rule
Nginx chooses the most specific matching prefix, so location /api/ is selected for API requests even though location / is also present. Keep the API prefix distinct from paths used by Angular assets and routes. If your backend uses another prefix, change the location to match it consistently.
Understand proxy_pass URI behavior
The combination of location and proxy_pass determines the path Node receives. Nginx documents that placing a URI in proxy_pass changes how the part of the request URI that matched the location is replaced.
No URI in proxy_pass: preserve the original path
In the baseline configuration, proxy_pass http://node_backend; has no URI component. A request for /api/orders is forwarded upstream with the /api/orders path. Use this when Node routes include the /api prefix.
A trailing slash in proxy_pass: replace the matching prefix
With this alternative:
location /api/ {
proxy_pass http://node_backend/;
}
a request for /api/orders is forwarded as /orders, because the matched /api/ portion is replaced by /. Use this only when the Node application expects routes without the external prefix. Decide which form your framework routes require, then test a real endpoint through Nginx.
Forward the request context Node needs
Nginx changes some request headers by default. The explicit headers in the example preserve information that many Node frameworks use for logging, URL generation, access control, and secure-cookie decisions:
Hostcarries the public hostname.X-Real-IPcarries the directly observed client address.X-Forwarded-Forappends the client address to any existing proxy chain.X-Forwarded-Prototells Node whether the browser used HTTP or HTTPS.
Configure the Node framework to trust the proxy only according to your network topology. Blindly trusting arbitrary forwarded headers can allow clients to spoof their source address or scheme when Nginx is not the only trusted hop.
Rank #3
Enable HTTPS at Nginx
For production, terminate TLS at Nginx and redirect clear-text HTTP to HTTPS. The certificate authority, renewal process, operating-system paths, and permissions vary, so the certificate files below are placeholders.
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
root /var/www/angular/dist/my-app/browser;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://node_backend;
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;
}
}
The port-80 block returns a permanent redirect while preserving the requested path and query string. The TLS block contains the same static and API routing as the HTTP baseline. Install the complete certificate chain where required by your certificate setup, restrict the private-key file, and arrange renewal before it expires.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteProxy WebSockets correctly
WebSockets begin as HTTP requests and then upgrade the connection. A normal reverse proxy configuration does not forward that upgrade automatically. Define a connection map at the HTTP configuration level and add a WebSocket location:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
root /var/www/angular/dist/my-app/browser;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://node_backend;
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;
}
location /socket.io/ {
proxy_pass http://node_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 60m;
}
}
Change /socket.io/ to the path used by your application. The proxy_http_version 1.1, Upgrade, and Connection settings are essential. Nginx closes an idle proxied connection after 60 seconds without upstream data by default; use a longer proxy_read_timeout, such as 60m, when long idle periods are legitimate, or have the application send ping frames. A long timeout does not replace application-level disconnect and authentication handling.
Development proxy versus production proxy
Angular CLI’s proxyConfig option belongs to the development server. It diverts browser requests during local development so that a separate Node process can receive API calls without changing the production Nginx configuration.
A typical development proxy file is:
{
"/api": {
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true
}
}
Attach that file to the serve target in the project’s Angular configuration, using the exact option label supported by your Angular CLI version, then start the development server with that target. The production server still needs Nginx’s location /api/ and proxy_pass rules. Do not copy a development proxy file to the server and assume it controls Nginx.
Crashes, 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 minutePC 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 & 11Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Scale the Node upstream when necessary
The upstream group can contain multiple Node processes or hosts:
upstream node_backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
server 10.0.0.12:3000;
}
Nginx uses round-robin load balancing by default, sending successive requests across the available servers. Adding entries is not a complete high-availability plan. Decide how failed instances are detected, how deployments drain connections, and where sessions and uploaded files live. If sessions are stored only in one process’s memory, a later request routed to another process may appear logged out; use an appropriate shared session design or routing strategy for the application.
Choose caching deliberately
Nginx can cache eligible upstream responses and can serve static Angular assets efficiently, but API caching is a correctness decision rather than a universal optimization. Before enabling proxy caching, classify each endpoint:
- Public, immutable responses may be candidates for a defined cache policy.
- Personalized, permission-sensitive, or rapidly changing responses generally need bypass rules or explicit non-cache headers.
- Mutation requests such as writes should not be treated like repeatable public reads.
Cache headers, authentication behavior, invalidation, and stale-data tolerance must be agreed with the Node application. Start without API caching, measure the actual bottleneck, and add a narrowly scoped policy only when its behavior is understood.
Deploy the configuration safely
- Build Angular and identify the directory containing the intended
index.html. - Publish the files to the server and verify their ownership and read permissions.
- Confirm that Node is listening locally by calling an endpoint on its configured address and port from the server itself.
- Add the upstream and server blocks, replacing every example hostname, path, port, and certificate filename.
- Check that the API path and the Node router agree about whether the
/apiprefix is preserved. - Validate syntax with
nginx -t. Treat any reported error as a deployment blocker. - Reload Nginx using the service-management method provided by your operating system, then test the site over its public hostname.
- Test an asset, the root document, a deep Angular route, a successful API request, an API error, and—if applicable—a WebSocket connection.
- Watch Nginx error logs and Node application logs together while testing. The pair usually reveals whether a failure occurred before proxying, during the upstream connection, or inside Node.
Diagnose common failures
The homepage is 404 or shows the wrong files
Check that root points to the directory containing index.html, not its parent or a source directory. Confirm the active server block matches the requested hostname and that another default server is not answering first. Verify file and directory permissions.
Refreshing an Angular route returns 404
Confirm the general location contains try_files $uri $uri/ /index.html;. Test a deep route directly in a new browser request, not only by clicking links after the application has loaded.
Best Value
API requests reach Angular instead of Node
Check the request path, the exact location prefix, and the hostname-selected server block. A request to /api without the trailing slash can behave differently from /api/ depending on the other locations in your configuration; test both forms and add an intentional redirect or matching rule if your API requires one.
Node receives an unexpected path
Inspect whether proxy_pass ends with a URI slash. No URI preserves the original request path; a URI replaces the part matched by the location. Align that choice with the backend router and test a concrete endpoint such as /api/health.
The backend returns 502 Bad Gateway
Test the Node listener locally on the Nginx host, then verify the upstream address and port, process state, firewall rules, and Node logs. A 502 means Nginx could not obtain a valid upstream response; it does not by itself identify whether the process is stopped, unreachable, or closing the connection.
Secure redirects or cookies behave incorrectly
Ensure the HTTPS server sets X-Forwarded-Proto $scheme and that the Node framework’s proxy-trust setting recognizes Nginx. Without the original scheme, an application may generate HTTP URLs or decline to mark cookies secure.
WebSockets disconnect after about a minute
Verify that the WebSocket location is actually selected, that HTTP/1.1 and both upgrade headers are present, and that the Node endpoint accepts the requested path. If the connection is simply idle, increase proxy_read_timeout appropriately or send application ping frames. Review both sides’ logs for close codes and authentication failures.
Static Angular files versus server-side rendering
The configurations in this guide assume a browser build that Nginx can serve as files. That is the simplest and most common arrangement for an Angular single-page application. Server-side rendering is a different topology: a Node-based rendering server must generate HTML for incoming page requests, so those requests cannot all be satisfied by Nginx’s try_files fallback. Keep static assets at Nginx when possible, but design the render-server locations and process lifecycle separately. Do not apply the static-only configuration unchanged to an SSR deployment.
Quick Recap
Operational checks that prevent regressions
- Keep the public API prefix, Angular routing base, and Node route definitions documented together.
- After every Angular release, check that the deployed directory contains the new asset filenames and that the HTML references them.
- After every Nginx change, run
nginx -tbefore reloading. - Exercise both a client-side deep link and a direct API URL in automated smoke tests.
- Monitor upstream latency, 4xx/5xx rates, open WebSocket connections, certificate expiry, and disk space used by releases and logs.
- When adding upstream servers, test graceful shutdown and session behavior before sending production traffic to all processes.
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.




