← Back to all docs

How to Replicate This Setup

Step-by-step guide to set up a Node.js web app on a Windows machine, served via nginx, and exposed to the public internet using Tailscale Funnel.

Prerequisites


Step 1: Install Node.js

Download and install from nodejs.org (LTS version recommended).

Verify:

node --version
npm --version

Step 2: Install nginx

  1. Download the Windows zip from nginx.org/en/download.html
  2. Extract it to your project folder (e.g., C:\myapp\nginx-1.30.0\)

No installer needed — nginx on Windows runs as a plain executable.


Step 3: Create the Node.js App

Create server.js in your project folder:

const http = require("http");
const os = require("os");

const PORT = 3000;

const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/html" });
  res.end(`<h1>Hello from ${os.hostname()}</h1><p>${new Date()}</p>`);
});

server.listen(PORT, "127.0.0.1", () => {
  console.log(`Running on http://127.0.0.1:${PORT}`);
});

Binding to 127.0.0.1 (not 0.0.0.0) keeps Node localhost-only. nginx handles external traffic.


Step 4: Configure nginx

Edit nginx-1.30.0\conf\nginx.conf. Find the location / block inside the server {} block and replace it:

location / {
    proxy_pass         http://127.0.0.1:3000;
    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;
}

Step 5: Open Port 80 in Windows Firewall

Run in an elevated (admin) PowerShell or CMD:

netsh advfirewall firewall add rule name="nginx HTTP 80" dir=in action=allow protocol=TCP localport=80

Or via GUI: Windows Defender Firewall → Advanced Settings → Inbound Rules → New Rule → Port → TCP 80 → Allow.


Step 6: Start Everything

Open a terminal in your project folder:

# Start Node app (keep this terminal open, or use a background method)
node server.js

# Start nginx (open a second terminal, cd into nginx folder)
cd nginx-1.30.0
nginx.exe

Verify both are working:

curl http://127.0.0.1:3000   # Node directly
curl http://127.0.0.1:80     # Through nginx

Step 7: Enable Tailscale Funnel (Public Internet)

tailscale funnel --bg http://127.0.0.1:3000

This outputs your public URL, e.g.:

Available on the internet:
https://your-machine.taileeca1e.ts.net/

Check status anytime:

tailscale serve status

Your app is now publicly accessible at that HTTPS URL — no port forwarding, no DNS setup, no SSL certificate management needed.

Note: Tailscale Funnel must be enabled for your account/tailnet. Check under your Tailscale admin panel → DNS → HTTPS Certificates if it's not working.


Verify Everything

Check Command
Node is running curl http://127.0.0.1:3000
nginx is proxying curl http://127.0.0.1:80
Tailscale network access curl http://<tailscale-ip>
Public internet curl https://<your-machine>.ts.net

Keeping It Running After Reboot

Tailscale Funnel persists automatically. For Node and nginx, you have two options:

Option A — Task Scheduler (simple)

Create two scheduled tasks (one for node server.js, one for nginx.exe) set to run at startup. Use Windows Task Scheduler GUI or:

# Example for Node (run as admin, adjust paths)
$action = New-ScheduledTaskAction -Execute "node.exe" -Argument "C:\myapp\server.js" -WorkingDirectory "C:\myapp"
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName "NodeApp" -Action $action -Trigger $trigger -RunLevel Highest

Option B — NSSM (Non-Sucking Service Manager)

Install NSSM and wrap Node/nginx as proper Windows services:

choco install nssm   # or download from nssm.cc
nssm install NodeApp "C:\Program Files\nodejs\node.exe" "C:\myapp\server.js"
nssm install nginx "C:\myapp\nginx-1.30.0\nginx.exe"
nssm start NodeApp
nssm start nginx

Troubleshooting

nginx won't start — port 80 in use

netstat -ano | findstr :80
taskkill /PID <pid> /F

Tailscale Funnel not working

Node app not responding

netstat -ano | findstr :3000   # confirm it's listening