DEV Community

linou518
linou518

Posted on

How Hardcoded Private IPs Killed Our Production Frontend

A hardcoded private IP buried in the frontend source was silently breaking all external access. Here is the full story.

Background

We had an internal ERP system (Vite + React frontend, Express backend) that worked perfectly on the LAN. When we tried to expose it externally via a public domain, nothing worked.

The Configuration Problem

  • The nginx config for the domain:
    • /api/ -> 127.0.0.1:3210 (backend) OK
    • / -> 127.0.0.1:3101 (frontend) - nothing was running on this port
  • The frontend was actually being served by a Vite dev server on a different machine (LAN-only)

The Vite dev server was being used as the production server.

The Real Killer: Hardcoded IPs

Private IPs were scattered throughout the frontend source:

const BASE_URL = 'http://192.168.x.x:8520/api';
fetch('http://192.168.x.x:8520/api/sales/report/ledger', ...)
Enter fullscreen mode Exit fullscreen mode

Browsers on the LAN could reach these IPs directly. External browsers cannot. Even after vite build, these IPs were baked into the bundled JS.

Result: Every API call from external access returned ERR_CONNECTION_TIMED_OUT.

The Fix

1. Replace Hardcoded IPs with Relative Paths

// Before
const BASE_URL = 'http://192.168.x.x:8520/api';
// After
const BASE_URL = '/api';
Enter fullscreen mode Exit fullscreen mode

2. Create .env.production

VITE_API_URL=/api/v1
VITE_ERP_URL=/api
Enter fullscreen mode Exit fullscreen mode

3. Fix Nginx Configuration

# Serve built static files directly
location / {
    root /www/apps/erp-admin;
    try_files $uri $uri/ /index.html;
}
location /api/ {
    proxy_pass http://127.0.0.1:3210;
}
Enter fullscreen mode Exit fullscreen mode

4. Build and Deploy

npm run build
scp -r dist/* user@web-server:/www/apps/erp-admin/
ssh user@web-server 'nginx -t && nginx -s reload'
Enter fullscreen mode Exit fullscreen mode

The Vite Dev Proxy Trap

server.proxy in vite.config.ts only works during development (npm run dev). It has zero effect on the production build. This is a common source of works-in-dev-breaks-in-production bugs.

Lessons Learned

  1. Never hardcode private IPs in frontend code. Use relative paths or environment variables.
  2. Never use Vite dev server in production. npm run build with nginx static serving is the way.
  3. server.proxy is dev-only. Production reverse proxy belongs in your web server config.
  4. Works on LAN is not a valid test. You will not catch hardcoded IPs without testing external access.

Start with grep 192.168 in your codebase.

Top comments (0)