Need Help: Configure Nginx Reverse Proxy for Node.js App (Nginx + Apache2 Setup)

Hello community,

I’ve created a Node.js application that currently runs on port 9000. Right now, I can access it at:

mydomain.com:9000/api

However, I want to configure it so that:

  1. I don’t need to open port 9000 in my firewall
  2. Users can access it directly at: mydomain.com/api
  3. Keep my current Nginx + Apache2 setup intact

Current Setup:

What I’ve Tried:

I understand this requires configuring Nginx as a reverse proxy to forward requests from /api to localhost:9000, but I’m not sure how to properly configure this with my existing Nginx + Apache2 setup.

I attempted to create a custom web template for my Node.js application by creating .tpl and .stpl files in /usr/local/hestia/data/templates/web/nginx/, but when I try to apply the template using:

bash

v-change-web-domain-tpl user domain.com nodejs-template

I get the error: “nodejs-template web template doesn’t exist” even though the files are present with correct permissions.

Questions:

  1. How should I configure the Nginx location block for /api requests?
  2. Will this interfere with my existing Apache2 configuration?
  3. Should I handle this at the Nginx level or Apache2 level?
  4. Any security considerations I should be aware of?

Environment:

  • Operating System: Linux
  • Web Server: Nginx + Apache2
  • Application: Node.js (Express)
  • Control Panel: HestiaCP (if relevant)

Any guidance or configuration examples would be greatly appreciated! I want to ensure I’m following best practices for security and performance.

Thanks in advance for your help!

HestiaCP Custom Nginx Proxy Template Tutorial

I managed to solve this issue, and I’m sharing here a simple step-by-step approach on how to resolve it correctly.

1 - Creating the Template

Create the HTTP template file:

vim /usr/local/hestia/data/templates/web/nginx/myproject-3001.tpl

File content (make sure to change the naming and port):

# Custom PM2 Template for HTTP
server {
    listen %ip%:80;
    server_name %domain_idn% %alias_idn%;
    error_log /var/log/%web_system%/domains/%domain%.error.log error;
    location ~ /\.(?!well-known\/|file) {
        deny all;
        return 404;
    }
    location / {
        proxy_pass http://127.0.0.1:3001; # Internal app port
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade; # WebSocket support
        proxy_set_header Connection "upgrade"; # WebSocket support
        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 /error/ {
        alias %home%/%user%/web/%domain%/document_errors/;
    }
    include %home%/%user%/conf/web/%domain%/nginx.conf_*;
}

2 - Creating the HTTPS Template

Now let’s create the HTTPS modification:

vim /usr/local/hestia/data/templates/web/nginx/myproject-3001.stpl

File content (make sure to change the naming and port):

# Custom PM2 Template for HTTPS
server {
    listen %ip%:443 ssl;
    server_name %domain_idn% %alias_idn%;
    error_log /var/log/%web_system%/domains/%domain%.error.log error;
    ssl_certificate %ssl_pem%;
    ssl_certificate_key %ssl_key%;
    ssl_stapling on;
    ssl_stapling_verify on;
    location ~ /\.(?!well-known\/|file) {
        deny all;
        return 404;
    }
    location / {
        proxy_pass https://127.0.0.1:3001; # Internal app port (adjust as needed)
        proxy_ssl_server_name on;
        proxy_ssl_name $host;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade; # WebSocket support
        proxy_set_header Connection "upgrade"; # WebSocket support
        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 /error/ {
        alias %home%/%user%/web/%domain%/document_errors/;
    }
    include %home%/%user%/conf/web/%domain%/nginx.ssl.conf_*;
}

3 - Restart Nginx

After doing this, restart nginx:

service nginx restart

4 - Apply the Template

That’s it! Now you just need to choose the template by editing the domain in proxy model.

Hope this helps!

3 Likes

This is great that you solved your own problem! My solution would’ve been to actually use Cloudflare Tunnels. That instead of worrying about all this, you can just install Cloudflare Tunnel on your server and then configure the hostname using Cloudflare zero trust dashboard and without opening the port.

1 Like

Thank you so much for the tip. The bigger issue is that all my DNS records are tied to government entities, so switching to Cloudflare would be a bit messy—I depend not only on third parties but also on the government, lol.
But thank you anyway. I’m sure your approach is much simpler, and I’m certain our thread will help a lot of people who are dealing with this headache, lol.

oh! Govt :slight_smile: Yes - I hear you man!
I completely agree, your solution is definitely more useful when one can’t depend on third party solutions like Cloudflare.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.