15%

Save 15% on All Hosting Services

Test your skills and get Discount on any hosting plan

Use code:

Skills
Get Started
09.10.2024

How to Configure Nginx to Listen on Multiple Ports

Nginx can listen on multiple ports simultaneously by adding multiple `listen` directives inside one or more `server` blocks within its configuration. Each `listen` directive binds Nginx to a specific IP/port combination, allowing a single server instance to handle HTTP, HTTPS, and custom application traffic on distinct ports without running separate processes.

This capability is essential for multi-tenant environments, staging/production port separation, reverse proxy architectures, and microservice routing — all from a single VPS Hosting instance.

Prerequisites

Before proceeding, confirm the following:

  • Nginx is installed and the service is active (`systemctl status nginx`)
  • You have `root` or `sudo` privileges on the server
  • You understand the difference between `/etc/nginx/nginx.conf` (global configuration) and `/etc/nginx/sites-available/` (per-site configuration blocks)
  • Firewall rules (`ufw`, `iptables`, or a cloud security group) permit traffic on the ports you intend to open
  • Valid SSL certificates are available if configuring HTTPS ports (self-signed or CA-issued)

Nginx Configuration Architecture: What You Need to Know First

Nginx uses a hierarchical configuration model: the `http` context contains one or more `server` blocks, each of which can contain one or more `listen` directives. Understanding this hierarchy prevents the most common misconfiguration mistakes.

Key directives involved:

  • `listen [address:]port [ssl] [http2] [default_server]` — binds the server block to a specific port and optional IP
  • `server_name` — matches the `Host` header to route requests to the correct block
  • `default_server` — designates which server block handles requests that match no other `server_name`

Configuration file locations by distribution:

DistributionMain ConfigSite Configs
Ubuntu / Debian`/etc/nginx/nginx.conf``/etc/nginx/sites-available/`
CentOS / RHEL / AlmaLinux`/etc/nginx/nginx.conf``/etc/nginx/conf.d/`
Arch Linux`/etc/nginx/nginx.conf``/etc/nginx/sites-available/`
Docker (official image)`/etc/nginx/nginx.conf``/etc/nginx/conf.d/`

On Debian-based systems, files in `sites-available/` must be symlinked to `sites-enabled/` to take effect:

“`bash

sudo ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/

“`

Step 1: Open the Nginx Configuration File

For a global change affecting all virtual hosts:

“`bash

sudo nano /etc/nginx/nginx.conf

“`

For a site-specific configuration (recommended for production):

“`bash

sudo nano /etc/nginx/sites-available/example.conf

“`

Using site-specific files is strongly preferred. It isolates changes, simplifies rollback, and prevents a single misconfiguration from taking down all hosted services.

Step 2: Configure Multiple listen Directives in a Single Server Block

The simplest multi-port setup binds one server block to several ports. Nginx will apply identical routing logic regardless of which port the client connected through.

“`nginx

server {

listen 80;

listen 8080;

server_name example.com;

root /var/www/html;

index index.html index.htm;

location / {

try_files $uri $uri/ =404;

}

access_log /var/log/nginx/example_access.log;

error_log /var/log/nginx/example_error.log warn;

}

“`

What this does:

  • `listen 80;` — accepts standard HTTP traffic
  • `listen 8080;` — accepts traffic on the alternate HTTP port (common for development environments, internal APIs, or load balancer health checks)
  • Both ports serve identical content from `/var/www/html`

Edge case — binding to a specific IP address: On a server with multiple network interfaces (e.g., a public IP and a private LAN IP), you can restrict which interface Nginx listens on:

“`nginx

listen 192.168.1.10:8080;

listen 0.0.0.0:80;

“`

This is critical in multi-homed server configurations to prevent unintended public exposure of internal services.

Step 3: Configure HTTPS on Multiple Ports

HTTPS requires the `ssl` parameter on the `listen` directive and valid certificate/key paths. The following example binds HTTPS to both the standard port 443 and a custom port 8443:

“`nginx

server {

listen 443 ssl;

listen 8443 ssl;

server_name example.com;

ssl_certificate /etc/nginx/ssl/example.com.crt;

ssl_certificate_key /etc/nginx/ssl/example.com.key;

Modern TLS hardening

ssl_protocols TLSv1.2 TLSv1.3;

ssl_ciphers HIGH:!aNULL:!MD5;

ssl_prefer_server_ciphers on;

ssl_session_cache shared:SSL:10m;

ssl_session_timeout 10m;

root /var/www/html;

index index.html;

location / {

try_files $uri $uri/ =404;

}

}

“`

Why port 8443 is commonly used:

  • Allows HTTPS traffic on environments where port 443 is blocked by upstream firewalls
  • Used in development/staging to run a secure server without conflicting with a production service on 443
  • Required by some application frameworks (Tomcat, Node.js proxies) that expose HTTPS on non-standard ports

Critical pitfall: Omitting `ssl_protocols` and `ssl_ciphers` leaves Nginx using potentially weak defaults. Always explicitly define TLS parameters, especially on servers handling sensitive data. If you need a trusted certificate rather than a self-signed one, SSL Certificates from a recognized CA eliminate browser warnings and satisfy modern HSTS requirements.

Step 4: Serve Different Content on Different Ports

When ports must serve distinct applications — for example, a public website on port 80 and an internal admin panel on port 8080 — use separate `server` blocks:

“`nginx

server {

listen 80;

server_name example.com;

root /var/www/public;

index index.html;

location / {

try_files $uri $uri/ =404;

}

}

server {

listen 8080;

server_name example.com;

root /var/www/admin;

index index.html;

Restrict admin panel to internal network only

location / {

allow 10.0.0.0/8;

allow 192.168.0.0/16;

deny all;

try_files $uri $uri/ =404;

}

}

“`

Real-world use cases for port-based content separation:

  • Port 80/443: Public-facing website
  • Port 8080: Internal REST API or microservice endpoint
  • Port 8443: Secure admin dashboard restricted by IP allowlist
  • Port 9000: Metrics endpoint for Prometheus scraping (never exposed publicly)
  • Port 3000/5000: Reverse proxy to a Node.js or Python application

Step 5: Using Nginx as a Reverse Proxy on Multiple Ports

A common production pattern is using Nginx to proxy different ports to different backend application servers:

“`nginx

server {

listen 80;

server_name app.example.com;

location / {

proxy_pass http://127.0.0.1:3000;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection 'upgrade';

proxy_set_header Host $host;

proxy_cache_bypass $http_upgrade;

}

}

server {

listen 8080;

server_name app.example.com;

location / {

proxy_pass http://127.0.0.1:4000;

proxy_http_version 1.1;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

}

“`

This pattern is the backbone of containerized deployments on a Dedicated Server where multiple Docker containers run on different internal ports and Nginx acts as the single external entry point.

Step 6: Validate the Configuration

Never restart Nginx without first testing the configuration syntax. A syntax error will cause the service to fail to reload, taking down all hosted sites.

“`bash

sudo nginx -t

“`

Expected output on success:

“`

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

“`

If errors appear, the output will specify the file and line number. Fix all reported issues before proceeding.

For a zero-downtime reload (preferred over a full restart in production):

“`bash

sudo systemctl reload nginx

“`

A full restart is only necessary when changing the `worker_processes`, `user`, or other master-process-level directives:

“`bash

sudo systemctl restart nginx

“`

Step 7: Verify Nginx Is Listening on the Correct Ports

After applying the configuration, confirm that Nginx has bound to the expected ports using `ss` (preferred over the deprecated `netstat`):

“`bash

sudo ss -tlnp | grep nginx

“`

Sample output:

“`

LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6))

LISTEN 0 511 0.0.0.0:8080 0.0.0.0:* users:(("nginx",pid=1234,fd=7))

LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1234,fd=8))

LISTEN 0 511 0.0.0.0:8443 0.0.0.0:* users:(("nginx",pid=1234,fd=9))

“`

If a port does not appear, check:

  1. The `listen` directive syntax in the configuration file
  2. Whether another process is already occupying that port: `sudo ss -tlnp | grep :8080`
  3. Whether `nginx -t` passed without errors
  4. SELinux or AppArmor policies that may block non-standard port binding

Testing with curl from the command line (more reliable than a browser for debugging):

“`bash

curl -I http://example.com

curl -I http://example.com:8080

curl -Ik https://example.com

curl -Ik https://example.com:8443

“`

The `-I` flag fetches only headers. A `200 OK` or `301 Moved Permanently` response confirms the port is active and Nginx is responding correctly.

Step 8: Open Firewall Ports

Listening on a port in Nginx is insufficient if the host firewall blocks incoming connections. Ensure the ports are permitted:

UFW (Ubuntu/Debian):

“`bash

sudo ufw allow 80/tcp

sudo ufw allow 443/tcp

sudo ufw allow 8080/tcp

sudo ufw allow 8443/tcp

sudo ufw reload

“`

firewalld (CentOS/RHEL/AlmaLinux):

“`bash

sudo firewall-cmd –permanent –add-port=8080/tcp

sudo firewall-cmd –permanent –add-port=8443/tcp

sudo firewall-cmd –reload

“`

iptables (direct):

“`bash

sudo iptables -A INPUT -p tcp –dport 8080 -j ACCEPT

sudo iptables -A INPUT -p tcp –dport 8443 -j ACCEPT

“`

On cloud infrastructure (AWS EC2, DigitalOcean, Hetzner), you must also update the security group or cloud firewall rules at the provider level — host-level firewall changes alone are not sufficient.

Comparison: Single-Port vs. Multi-Port Nginx Configurations

FeatureSingle PortMultiple Ports (Same Block)Multiple Ports (Separate Blocks)
Configuration complexityLowLowMedium
Content isolationNoneNoneFull
Access control per portNot applicableNot possibleFully supported
Use caseSimple websitesDev/staging mirrorsMicroservices, admin panels
Reverse proxy per portSingle upstreamSingle upstreamIndependent upstreams
SSL terminationPer blockShared certIndependent certs per block
Log separationSingle logSingle logPer-port log files

Common Pitfalls and How to Avoid Them

Port conflict with existing services: Port 80 may already be in use by Apache. Run `sudo ss -tlnp | grep :80` before configuring. Stop conflicting services or reconfigure them to use different ports.

`default_server` conflicts: If multiple server blocks omit `default_server` or multiple blocks claim it for the same port, Nginx will use the first block in file order. Be explicit:

“`nginx

listen 80 default_server;

“`

IPv6 not covered: Adding `listen 80;` only binds to IPv4. For dual-stack servers, add:

“`nginx

listen [::]:80;

listen [::]:8080;

“`

SELinux blocking non-standard ports: On RHEL/CentOS with SELinux enforcing, Nginx cannot bind to ports not in its policy without explicit permission:

“`bash

sudo semanage port -a -t http_port_t -p tcp 8080

sudo semanage port -a -t http_port_t -p tcp 8443

“`

Forgetting to reload after changes: Configuration edits have no effect until Nginx reloads. Automate this in CI/CD pipelines with a post-deploy `nginx -t && systemctl reload nginx` step.

Practical Decision Matrix

Use this checklist to determine the right multi-port configuration pattern for your scenario:

  • Same content, multiple ports — Use multiple `listen` directives in a single `server` block
  • Different content per port — Use separate `server` blocks with distinct `root` directories
  • Different backend applications per port — Use separate `server` blocks with `proxy_pass` pointing to different upstream addresses
  • Secure a non-standard port — Add `ssl` to the `listen` directive and reference your certificate paths; ensure the certificate's SAN covers the domain
  • Restrict a port to internal traffic — Add `allow`/`deny` directives or bind `listen` to a private IP only
  • Running on a VPS with cPanel — Verify cPanel's built-in Apache/Nginx configuration does not conflict; use cPanel's "Include Editor" or a dedicated Nginx config drop-in directory
  • Managing multiple control panel options — Review available VPS Control Panels to find one that exposes Nginx port management through a GUI

FAQ

Can Nginx listen on the same port across multiple server blocks?

Yes. Multiple `server` blocks can share the same port. Nginx differentiates between them using the `server_name` directive, which matches the HTTP `Host` header. If no `server_name` matches, the `default_server` block handles the request.

Does adding more listen ports affect Nginx performance?

The overhead is negligible. Each `listen` directive adds a file descriptor to the Nginx master process. The practical limit is the system's open file descriptor ceiling (`ulimit -n`), not the number of ports. For high-traffic deployments, tune `worker_rlimit_nofile` and `worker_connections` in `nginx.conf`.

How do I redirect all traffic from port 8080 to port 80?

Use a dedicated server block with a `return` directive:

“`nginx

server {

listen 8080;

server_name example.com;

return 301 http://example.com$request_uri;

}

“`

Why is Nginx not listening on a port even though the configuration looks correct?

The four most common causes are: (1) the configuration was not reloaded after editing, (2) another process is already bound to that port, (3) a firewall rule is blocking the port, or (4) SELinux/AppArmor is preventing binding. Work through each cause systematically using `ss -tlnp`, `nginx -t`, and firewall status commands.

Can I use different SSL certificates for different HTTPS ports on the same domain?

Yes. Each `server` block has its own `ssl_certificate` and `ssl_certificate_key` directives. Two server blocks can listen on ports 443 and 8443 respectively and reference entirely different certificate files, even for the same `server_name`. This is useful when rotating certificates or running a legacy certificate alongside a new one during a transition period.

15%

Save 15% on All Hosting Services

Test your skills and get Discount on any hosting plan

Use code:

Skills
Get Started