{"post":{"slug":"how-to-set-up-nginx-2026","title":"How to set up Nginx in 2026: reverse proxy, HTTPS, and performance basics","excerpt":"Nginx is still the default reverse proxy for most production stacks in 2026. This guide covers installation, virtual hosts, HTTPS via Certbot, and tuning.","category":"code","date":"March 16, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">N</span>ginx handles more than a third of the web's traffic in 2026 — it is the default choice for reverse proxying Node, Python, and Go applications, for SSL termination, and for serving static assets. Five years of container-native tooling haven't replaced it; they've wrapped it (most Kubernetes ingress controllers run Nginx under the hood). Here is how to set it up correctly.\n\n## What changed in 2026\n\n- **HTTP/3 (QUIC) support is stable** in Nginx 1.27+. You can enable it with a few lines; it noticeably improves high-latency mobile connections.\n- **Nginx Unit** (the dynamic app server from the Nginx team) gained traction as an alternative to the static config model, but classic Nginx still dominates reverse-proxy use.\n- **Let's Encrypt wildcard certs** via Certbot DNS plugins are now well-supported and preferred for multi-subdomain setups.\n- **Brotli compression** ships in more distro packages; use it alongside gzip for modern browsers.\n\n## Installation\n\nInstall from the official Nginx mainline repo to get current features:\n\n```bash\n# Ubuntu/Debian\ncurl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor \\\n  -o /usr/share/keyrings/nginx-archive-keyring.gpg\necho \"deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \\\n  http://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx\" \\\n  | sudo tee /etc/nginx/nginx.list\nsudo apt update && sudo apt install nginx -y\nsudo systemctl enable --now nginx\n```\n\nVerify: `nginx -v` — you should see 1.27 or later.\n\n## Basic reverse-proxy config\n\n```nginx\n# /etc/nginx/sites-available/myapp\nserver {\n    listen 80;\n    server_name myapp.example.com;\n\n    location / {\n        proxy_pass http://127.0.0.1:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection 'upgrade';\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_cache_bypass $http_upgrade;\n    }\n}\n```\n\nEnable it: `sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/` then `sudo nginx -t && sudo systemctl reload nginx`.\n\n## HTTPS with Let's Encrypt (Certbot)\n\n```bash\nsudo apt install certbot python3-certbot-nginx -y\nsudo certbot --nginx -d myapp.example.com\n# Follow prompts; Certbot rewrites the server block automatically\n```\n\nCertbot installs a systemd timer that auto-renews certificates before expiry. Verify renewal works:\n\n```bash\nsudo certbot renew --dry-run\n```\n\nAfter Certbot, your config will have `listen 443 ssl` and the `ssl_certificate` directives added. Keep a backup.\n\n## HTTP/3 (QUIC)\n\n```nginx\nserver {\n    listen 443 ssl;\n    listen 443 quic reuseport;   # HTTP/3\n    http2 on;\n    add_header Alt-Svc 'h3=\":443\"; ma=86400';\n    # ... rest of your config\n}\n```\n\nOpen UDP port 443 in your firewall: `sudo ufw allow 443/udp`.\n\n## Performance tuning\n\n```nginx\n# /etc/nginx/nginx.conf\nworker_processes auto;          # matches CPU cores\nworker_rlimit_nofile 65535;\n\nevents {\n    worker_connections 4096;    # per worker; total = workers × connections\n    use epoll;\n    multi_accept on;\n}\n\nhttp {\n    sendfile on;\n    tcp_nopush on;\n    tcp_nodelay on;\n    keepalive_timeout 65;\n    gzip on;\n    gzip_types text/plain text/css application/json application/javascript;\n    gzip_min_length 256;\n}\n```\n\n## Config comparison at a glance\n\n| Scenario | Directive |\n| --- | --- |\n| Proxy to Node/Python app | `proxy_pass http://127.0.0.1:PORT` |\n| Serve static files | `root /var/www/html; try_files $uri $uri/ =404;` |\n| WebSocket support | `proxy_set_header Upgrade $http_upgrade; Connection 'upgrade'` |\n| Rate limiting | `limit_req_zone` + `limit_req` |\n| Load balance upstream | `upstream` block with `server` entries |\n| Basic auth | `auth_basic` + `auth_basic_user_file` |\n\n## How to pick between Nginx and alternatives\n\n| Tool | Best for |\n| --- | --- |\n| Nginx | General-purpose reverse proxy, static files, SSL termination |\n| Caddy | Zero-config HTTPS, smaller setups, automatic cert management |\n| Traefik | Kubernetes/Docker-first, dynamic config via labels |\n| HAProxy | High-throughput TCP/HTTP load balancing |\n| Apache | Legacy PHP apps, `.htaccess` workflows |\n\n## Common mistakes\n\n**Not testing config before reloading.** Always run `sudo nginx -t` — a syntax error takes down the server on reload.\n\n**Forgetting to forward the real IP.** Without `X-Forwarded-For` and `X-Real-IP` headers your app sees `127.0.0.1` for every request. Pass them explicitly.\n\n**Default `worker_connections 768`.** On modern hardware, 4096–8192 per worker is common. Profile your actual concurrency.\n\n**Serving large uploads through Nginx without tuning `client_max_body_size`.** The default is 1 MB. Override per location for file upload endpoints.\n\n**Using `if` in location blocks.** Nginx's `if` directive has well-known bugs — use `map` or `try_files` instead.\n\n## What to skip\n\n- **Nginx Plus** unless you need the dashboard, active health checks, or OIDC module — the open-source version handles 99% of use cases.\n- **Complex Lua logic** in OpenResty unless you know what you're doing; reach for application-layer middleware instead.\n- **Manual certificate management** — Certbot or Caddy handle this for you.\n\n## FAQ\n\n**How do I reload Nginx without downtime?**\n`sudo systemctl reload nginx` sends SIGHUP, which reloads config gracefully without dropping connections.\n\n**Where do I put per-domain configs?**\n`/etc/nginx/sites-available/<domain>` with a symlink from `sites-enabled/`. Never edit `nginx.conf` for per-site settings.\n\n**How do I debug a 502 Bad Gateway?**\nCheck `sudo journalctl -u nginx` and your app's logs. Usually the upstream process crashed or is not listening on the expected port.\n\n**How do I set up a subdomain redirect?**\nAdd a separate `server` block with `server_name sub.example.com;` and use `return 301 https://www.example.com$request_uri;`.\n\n## Where to go next\n\n- [How to set up SSL in 2026](/blog/how-to-set-up-ssl-2026)\n- [How to containerize an app in 2026](/blog/how-to-containerize-an-app-2026)\n- [How to set up a dev environment in 2026](/blog/how-to-set-up-a-dev-environment-2026)","hue":308,"metaTitle":"How to Set Up Nginx in 2026: Reverse Proxy and HTTPS Guide","metaDescription":"Set up Nginx in 2026 — install, configure virtual hosts, enable HTTPS with Let's Encrypt, and tune performance. Step-by-step for production use.","keywords":["how to set up nginx 2026","nginx reverse proxy tutorial","nginx https certbot 2026","nginx virtual hosts configuration","nginx performance tuning","nginx server block example","nginx ubuntu 2026","nginx configuration best practices","nginx upstream proxy","nginx ssl termination"],"tldr":["**Install from the official Nginx repo** — distro packages lag behind by months and miss security patches.","**One server block per domain** — separate files in `/etc/nginx/sites-available/` keep configs readable.","**Use Certbot for HTTPS** — Let's Encrypt certificates are free, auto-renew, and handle the config edits.","**Set `worker_processes auto`** and tune `worker_connections` for your traffic — defaults are conservative.","**Skip:** putting application logic in Nginx config with Lua unless you have strong reasons — keep it as a proxy, not an app server."],"readTime":"4 min read","wordCount":845},"related":[{"slug":"how-to-set-up-ssl-2026","title":"How to set up SSL in 2026: TLS, certificates, and HTTPS done right","excerpt":"HTTPS is non-negotiable in 2026 — browsers flag plain HTTP, and search engines penalize it. Here is how to get certificates, configure TLS, and stay secure.","category":"code","date":"April 3, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":309},{"slug":"nginx-vs-apache-2026","title":"Nginx vs Apache 2026: Which Web Server Wins?","excerpt":"Nginx and Apache still run most of the web in 2026. Here is a plain-language look at where each one actually wins, and how to choose without the flame wars.","category":"code","date":"June 25, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":158},{"slug":"reverse-proxies-explained-2026","title":"Reverse proxies explained in 2026","excerpt":"Reverse proxies sit between clients and your servers, enabling TLS termination, caching, rate limiting, and routing in one place. Here is the 2026 guide.","category":"code","date":"April 21, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":308}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"how-to-set-up-game-streaming-2026","title":"How to set up game streaming in 2026: local and cloud options explained","excerpt":"Game streaming lets you play on any screen in your home or away without a gaming PC at every location. Here is how to set it up correctly in 2026.","category":"tech","date":"March 16, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":250},"older":{"slug":"how-to-set-up-pi-hole-2026","title":"How to set up Pi-hole in 2026: network-wide ad blocking in 30 minutes","excerpt":"Pi-hole blocks ads and trackers for every device on your network without touching individual browsers. Here is how to install and configure it in 2026.","category":"tech","date":"March 16, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":242}}