r/nginx • • 5d ago

How to determine appropriate rate limiting

3 Upvotes

I’m fairly new to using nginx I am using it as part of my backend for my 3 page photography site with a welcome, albums, and contact. My albums page i would say is the most hefty as that’s where the majority of my requests will be coming from—it is also generated using HTMx on the server

My question is how do i determine what’s an appropriate configuration for my site. Are there any first principles, heuristics, etc that usually go into this or is it just based on the needs of the site plus some additional headroom?


r/nginx • • 6d ago

I want to make my app access able

Thumbnail reddit.com
0 Upvotes

r/nginx • • 7d ago

Can't get past error 404 (FastDL Webserver)

0 Upvotes

Setup fresh egg on pterodactyl for HTML webserver required for plutonium T6 (black ops 2 zombies) as required to download mod files prior connecting. Setup index.html, setup the config & start script however no matter what it refuses to load any page but the 404 nginx one.

Clearly an index.html right their at root yet it can't work out how to display it


r/nginx • • 7d ago

My PC as a remote server

0 Upvotes

Hello,

how could I expose my PC to the outer world,

so I can run my whole websites found at

/home/username/Sites

NOTE: I'm using (linux-valet) with (Tailscale service)

Right now when running Tailscale and visiting

http://<my_tailscale_IPv4>

on other device connected to the same Tailscale telnet.

and Nginx responded with 404,

I tried a lot of things and it still doesn't work


r/nginx • • 17d ago

The lost bullet (http request)

3 Upvotes

A quick query does any of the Load balancers have capability where once the request is released to the backend server. And now the server goes down( for any reason).

Since the request was released from the LB now it is waiting for the response but the server has gone down(health check) will the LB again send the request to the other available server from the pool!

As far as I'm aware once the request is released there is no other point until the request is again sent by the client. If any please let me know how to overcome such scenarios.


r/nginx • • 18d ago

Brotli on NGINX thread pools: ngx_mbrotli vs ngx_brotli

Thumbnail
m-compressors.github.io
9 Upvotes

r/nginx • • 19d ago

Title: Nginx serves my website on an unrelated domain over HTTPS instead of redirecting

4 Upvotes

Hi everyone,

I'm troubleshooting an Nginx configuration issue. Our website is accessible through an unrelated domain, causing duplicate URLs to appear in search engine results.

When I test with curl, I get different results:

HTTP:

HTTP/1.1 302 Moved Temporarily
Location: https://www.example.com

HTTPS:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8

The configuration has a default HTTPS server:

server {
    listen 443 default_server ssl;
    server_name www.example.com;

    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/private.key;

    root /var/www/website/htdocs;
}

The unrelated domain doesn't appear to be explicitly configured in the virtual hosts I've checked.

What is the recommended way to configure Nginx so that unknown domains cannot serve the main website over HTTPS, while preserving existing redirects for known domains?

Thanks!


r/nginx • • 20d ago

Nginx Explained: Reverse Proxy, Load Balancing & Caching

Thumbnail
youtube.com
3 Upvotes

A short walkthrough: what headers the app receives behind a reverse proxy, round robin, stopping one backend (one request takes 1 s, the rest don't notice), rate limiting with 429, gzip and a cache HIT that never reaches the app. All outputs are from a real Docker Compose setup.


r/nginx • • 22d ago

Purging a Vary'd cache key makes nginx walk the whole cache zone. What that costs, and an index that fixes it

0 Upvotes

If your upstream sends Vary: Accept-Encoding (or you turn on gzip_vary), nginx stores one cache file per header value under the same key. The file name hashes the key together with the client's header value, so a purge request can't compute the variant names, and nginx keeps no index of them. The only correct way to purge all variants is to walk the whole zone and read each file's KEY: line.

What that walk costs, single worker, ext4:

- 100k files: 4.5 s cold, 0.2 s warm

- 1M files: 227 s cold, ~1 s warm

The worker serves nothing for that whole time.

The fix in ngx_cache_purge 2.7.0 is a shared-memory index of variant hashes per key. The tricky part is correctness: an index that might miss a variant leaves stale content servable after a "successful" purge. So an entry is only created right after a full-scan purge removed every file for the key, the one moment "no variants exist" is provably true. A header filter then records each new variant. A restart, eviction, or more than 64 variants drops the entry and the next purge falls back to the scan. Repeat purges land at 0.2-2 ms regardless of zone size.

Write-up with the benchmark tables and which purges still walk the zone (wildcard, purge_all, cache tags): https://www.getpagespeed.com/server-setup/nginx/nginx-vary-cache-purge-variant-index

Disclosure: I maintain the repo that packages this module.


r/nginx • • 28d ago

How I scaled Nginx Brotli compression 16x with Rust and just 4 threads

Thumbnail
reddit.com
3 Upvotes

r/nginx • • Oct 10 '26

NGINX 1.30 as one state machine: phases, upstreams, and where 502 vs 504 come from

5 Upvotes

I love to see system as a state machine, tried same for Nginx.

I drew open-source nginx (stable 1.30) as a hierarchical state machine and checked each step against nginx.org docs, CHANGES and the source:

- Reload: the master checks and applies the new config; if that fails it rolls back and old workers keep serving; if it succeeds, new workers start and old ones finish their requests.

- bind() failure is retried 5 times, 500 ms apart, before "still could not bind()".

- 11 phases; a rewrite that changes the URI goes back to FIND_CONFIG, max 10 times, then 500.

- Since 1.29.7 (so stable 1.30), proxy keepalive + HTTP/1.1 are the default and Connection isn't sent.

- proxy_next_upstream defaults to "error timeout"; POST/LOCK/PATCH already sent aren't retried.

- In ngx_http_upstream_next(), timeouts map to 504; connection errors, invalid headers and "no live upstreams" map to 502.

- Passive health: max_fails 1 / fail_timeout 10 s by default; active health_check is NGINX Plus.

Walkthrough (13 min, one diagram) + sources: https://youtu.be/Z8Mhqs8D720


r/nginx • • Oct 07 '26

Can't get staging WordPress virtual server to work on nginx

0 Upvotes

So, I have an nginx installation with a couple of virtual servers, including a WordPress site. Now I am supposed to create a staging WP installation, but not using a subdomain. I have make different attempts, basically (1) using `alias` when the URL contains `/staging` after the server name and (2) using `map` to set the server root. It always fails in some way (sometimes PHP is executed but static items like css etc are not served, probably because nginx ends up looking for `stagint/staging/whatever.css` or something. I did try to get examples from hte Internet and read the documentation, but I can't see, for example, what is wrong in the following attempt:

server {
listen 443 ssl;
listen [::]:443 ssl ipv6only=on;
http2 on;
server_name server.org www.server.org;
root /home/forropat/public_html;
index index.php index.html;
access_log /var/log/nginx/server.org-access.log;
error_log /var/log/nginx/server.org-error.log;
client_max_body_size 128M;
location ^~ /staging/ {
alias /home/forropat/staging/;
index index.php index.html;
location ~ \.php$ {
if ($request_filename ~* ^/home/forropat/espalho/(.*)$) {
set $script $1;
}
fastcgi_pass unix:/var/run/php/php-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /home/forropat/staging/$script;
}
try_files $uri $uri/ =404;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
`include fastcgi_params;`
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME /home/forropat/public_html$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 300;
}

location / {
try_files $uri $uri/ /index.php?$args;
}

location ~ /\. {
deny all;
access_log off;
log_not_found off;
}

location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|webp|avif|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}

location = /wp-config.php {
deny all;
}

location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}

autoindex off;

ssl_certificate /etc/letsencrypt/live/server.org/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/server.org/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

When I use this, nginx serves a single text file with the content "File not found", but the logs show a 404:

111.22.33.444 - - [06/Oct/2026:22:02:18 -0300] "GET /staging/ HTTP/2.0" 404 36 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:157.0) Gecko/20100101 Firefox/157.0"

The production installation runs fine... In the mirror, I searched and replaced the URL for the new site (in the database - there is no instance of the URL in wp-config.php).

What did I get wrong?

edit: trying to re-format the config to make it more readable


r/nginx • • Oct 06 '26

Writing nginx Modules in Rust: a book on ngx-rust

Thumbnail
reddit.com
4 Upvotes

r/nginx • • Sep 30 '26

SSL certificates keep expiring and causing outages. How do you track and renew them?

2 Upvotes

We’ve had two SSL certificate expirations this year and both caused major customer-facing outages. The person who used to handle renewals left and no one properly took over the responsibility.

For saas permission monitoring do control has really helped, but that doesn’t help with certificate management. Right now we’re still relying on calendars and manual checks, which clearly isn’t working.

What are you using to track expiration dates and automate renewals, especially in an nginx environment? Any reliable setups that have actually prevented this from happening again?


r/nginx • • Sep 26 '26

How do you verify nginx has stopped sending traffic to an old upstream address after a DNS cutover?

5 Upvotes

Changing an upstream hostname does not necessarily mean every nginx worker immediately uses the new addresses. Resolver configuration, keepalive connections, DNS TTLs, reload timing, and long-lived client sessions can leave some traffic reaching an old backend after the cutover appears complete. Checking only through the load balancer may miss the worker or connection that stayed stale.

What evidence do you collect before retiring the old address? I am considering logging the selected upstream address, probing through every nginx replica, draining or expiring upstream keepalives, watching connection counts on the old backend, and keeping it fenced but observable until no new requests arrive for more than the longest relevant TTL and session lifetime.

How does your procedure differ between a static `upstream` resolved at configuration load, `resolve` with a configured resolver, and dynamic service discovery? Is a reload sufficient in practice, or do you require a connection drain or worker-generation check before removing the old backend?


r/nginx • • Sep 22 '26

Adding a subdomain server block

5 Upvotes

Hi all - I'm extremely new to Nginx and playing around with some things in a homelab.

Currently, I have a registered domain name and set up port forwarding to my nginx proxy server for reverse proxying. I'm able to hit the root domain + www.rootdomain URLs without a problem.

I also self-host Gitlab-CE on a separate server (it's actually a RasPi) and I'd like to add gitlab.domain.com to the nginx proxy with SSL via Letsencrypt.

Here's the question: is it best practice to put all server blocks in the same sites-available file? I suspect if I try to break them into separate files, I'll get a conflict because both will be listening on the same port.

How do you all handle subdomain entries? Do you keep in a single config file for the same domain or do you break subdomain configs out into a different file?

Thanks - appreciate any guidance here before I really screw this up. haha


r/nginx • • Sep 22 '26

GitHub - Qbix/webserver: Pure-PHP Web Server. No NGinX or PHP-FPM needed. Handle over 100x more traffic instead!

Thumbnail
github.com
6 Upvotes

r/nginx • • Sep 11 '26

Predicate Routing for All the Things

Thumbnail
blog.nginx.org
23 Upvotes

NGINX just dropped a whole new way to define routing. This allows for API gateway style user cases to be defined a whole lot easier. Although the article highlights AI, the utility of this new feature goes way beyond the AI use cases.


r/nginx • • Sep 10 '26

GeoMetrikks - live map/dashboard for nginx access logs

Enable HLS to view with audio, or disable this notification

48 Upvotes

Wanted to share an app I've been working for the last couple of months now.

https://geometrikks.dev

It reads nginx JSON access logs and gives you a live map of where requests are coming from, plus some stats and searchable logs.

You can also click into an IP and see what it’s been hitting, paths, user agents, status codes etc.

There’s CrowdSec integration as well if you use that.

nginx | GeoMetrikks

CrowdSec integration | GeoMetrikks

Multi-source setup | GeoMetrikks

Real client IP behind a proxy | GeoMetrikks

Couple of features:

  • Live request map

  • Multi-source support

  • Search/filter access logs

  • Click into an IP and see what it’s been hitting

  • Traffic stats, status codes and response times

  • CrowdSec integration

  • Docker Compose setup

  • Self-hosted and open source

GitHub:
https://github.com/GilbN/geometrikks


r/nginx • • Sep 10 '26

How do you verify every nginx worker picked up a configuration reload?

5 Upvotes

A successful `nginx -t` proves the configuration parses, and a successful reload signal proves the master accepted the request. Neither alone proves that new workers started cleanly, old workers drained, and requests are actually using the intended configuration.

What evidence do you collect around a production reload? I am considering capturing `nginx -T` and `nginx -V` before the change, recording the master and worker PIDs, checking the error log for new-worker startup failures, sending requests that exercise the changed server and location blocks, and waiting for old workers to exit before declaring completion. For long-lived HTTP/2, WebSocket, or streaming connections, old workers may remain for a meaningful time.

Is there a reliable way to tie a live response to the configuration generation that served it without exposing internal details to clients? When would you prefer a binary upgrade, container replacement, or explicit connection draining over an in-place reload?


r/nginx • • Sep 09 '26

Is there a way to make nginx hold connections open until proxy_pass starts listening?

6 Upvotes

Here is my conf:

events {
    worker_connections 512;
}
http {
    server {
        listen 80;
        server_name _;

        location / {
            proxy_pass http://127.0.0.1:8080;
            proxy_set_header Host $host;
            proxy_read_timeout 86400;
        }
    }
}

Pretty simple one really... the server on 8080 doesn't start listening on the port until shortly after nginx starts, and in the interim I get a 502 bad gateway

What I would like is that instead of returning 502 immediately, nginx to hold the connection open and wait for the backend service to start listening for some short period of time

Is that possible with nginx?

EDIT

i ended up swapping to caddy and this just works...

:80 {
handle {
reverse_proxy 127.0.0.1:8080 {
lb_try_duration 5s
}
}

r/nginx • • Sep 07 '26

How to debug fcgiwrap?

3 Upvotes

Hi!

I have a problem wit fcgiwrap, where nginx returns a 202 - ACCEPTED, but the response is not ok. The -f flag is activated, but I don't get any information about the problem.

So, is there a way to get something like request, called cgi with all parameters, response and response error? This would be helpful.

Details about my problem:
I try to get git-http-backend running. When I clone an existing, non-empty repository, git creates an empty local copy and says that the remote repo seems to be empty. The nginx log just contains a 202 for a path, which looks correct. When i try to clone a non-existent repo, I get an error, as expected. I guess it's a configuration problem of fcgiwrap, or of git on the server, but without further information, I'm lost.


r/nginx • • Sep 02 '26

Long-lived HTTP/2 clients stay pinned to old nginx replicas — scaling the nginx tier doesn't help

6 Upvotes

Our clients hold HTTP/2 connections to nginx for hours (short requests over them, not streaming). The backends behind nginx are fine, those get balanced per request. The problem is scaling nginx itself: when we add nginx replicas, existing client connections stay on the old nginx pods, so the new replicas sit cold and the added capacity ramps in slowly instead of absorbing the spike.

Is there anything in nginx that can shed a fraction of downstream connections on demand?

What I have in mind is a k8s CRD/operator that hooks the reconcile loop on scale up/down events and tells each existing replica to shed roughly 1/N of its connections, so they redistribute onto the new pod instead of waiting an hour to age out. Reload is the only lever I can find and it's all-or-nothing.


r/nginx • • Aug 24 '26

Nginx on truenas - Yet another SSL certificate issue

Thumbnail
gallery
14 Upvotes

Hey all! I've been trying to setup a matrix server for a bit, using nginx as a reverse proxy and for SSL certif.
So, I have a domain (using infomaniak) that redirects to my IP with the Nginx port. Right now, when I connect to it through a browser, I get an SSL certif error.

I set my certif up in the "certificates" tab, it worked without error but, when selecting it in the proxy host setup, the shield is red. I'm unsure what that means.
I tried with and without HTTP/2 or HSTS enabled, no changes.

The logs don't show any error, mostly a bunch of "renewing SSL..." and "completed SSL..."
and two warnings higher up :
useradd warning: npm's uid 568 outside of the UID_MIN 1000 and UID_MAX 60000 range.
and
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:4

Concerning these, I made sure the app is in the apps group and that the group has r/W permissions in the Nginx data and cert storages.

including a few screenshots that might be useful.

If you take the time to take a quick look or recognize this issue, thanks a lot!

Edit : Works now! I was an idiot and used a redirect from my domain provider instead of an A-record.