← Back to list

From Localhost to Production: The Ultimate Guide to Deploying a JMS on Windows Server

Deploying a full-stack application isn’t just about moving code from one machine to another; it’s about orchestrating environment…

Kaletsidik Ayalew (Kal) · 2026-05-01 20:14 · 0 claps · 3.5 min read
#deployment #journal-management #full-stack #nextjs #prisma-orm
Open on Medium ↗
Wiki topics: BIZ · Business Strategy 🌐 · Web Development

From Localhost to Production: The Ultimate Guide to Deploying a JMS on Windows Server

Deploying a full-stack application isn’t just about moving code from one machine to another; it’s about orchestrating environment variables, security protocols, and network routing to ensure 24/7 availability. After successfully taking the Journal Management System (JMS) live at Addis Ababa University, I’ve documented every technical hurdle and configuration detail to serve as a roadmap for similar enterprise-grade deployments.

Phase 1: Building from the Ground Up

Before we talk about servers, we need a stable codebase. The JMS project is built with a React (Vite) frontend, a Node.js (Express) backend, and a PostgreSQL database managed via Prisma ORM.

1. Backend Foundations

The server-side logic handles authentication, manuscript submissions, and database interactions.

  • Initialization: We start by setting up a Node environment and installing core dependencies: express, @prisma/client, cors, dotenv, jsonwebtoken, and bcrypt.
  • Database Schema: Using Prisma, we define our data models (Users, Manuscripts, Reviews) in schema.prisma.
  • Environment Configuration: A .env file is created to store sensitive strings like DATABASE_URL and JWT_SECRET.

2. Frontend Development

The frontend is built for speed using the Vite build tool.

  • API Integration: The frontend communicates with the backend via Axios. A critical step here is setting the VITE_API_URL to point to our backend port (defaulting to 4000 in dev).
  • Production Build: When ready, we run npm run build, which compiles the React code into a highly optimized dist folder ready to be served by a web server.

Phase 2: Preparing the Windows Server Environment

Windows Server requires specific modules to act as a modern web host. You cannot simply run npm start and call it a day.

1. The Software Stack

A fresh Windows Server needs the following installed:

  • Node.js (v18+ LTS): The runtime for our backend.
  • PostgreSQL: Our relational database engine.
  • IIS (Internet Information Services): The primary web server for Windows.
  • NSSM (Non-Sucking Service Manager): A tool to run the Node.js script as a background service.

2. IIS Feature Activation

You must enable specific features within the “Turn Windows features on/off” menu:

  • IIS Web Server: Ensure “Static Content” and “Default Document” are checked.
  • URL Rewrite Module: (Manual install) Essential for handling React Router and Proxy rules.
  • Application Request Routing (ARR) 3.0: Required to turn IIS into a Reverse Proxy.

Phase 3: The Deep-Dive Deployment Process

This is where the magic happens. We need to bridge the gap between the internal Node process and the public-facing internet.

1. Running the Backend as a Windows Service (NSSM)

In production, if the server reboots or the Node process crashes, it must restart automatically.

  • Installation: Open PowerShell and run C:\nssm\nssm.exe install JMS-Server.

Configuration:

  • Path: C:\Program Files\nodejs\node.exe.
  • Startup Directory: C:\jms\server.
  • Arguments: server.js.
  • Persistence: Set the service to SERVICE_AUTO_START to ensure zero manual intervention after power cycles.

2. Mastering the IIS Reverse Proxy

Since our backend runs on port 4000 and IIS runs on port 80/443, we use ARR to tunnel traffic.

Step A: Enable Proxy in IIS Navigate to Server > Application Request Routing Cache > Server Proxy Settings. Check Enable Proxy and Reverse rewrite host in response headers.

Step B: The web.config Masterpiece Place this file in your frontend dist folder. It handles three vital tasks:

  1. API Proxying: Redirects /api requests to localhost:4000.
  2. HTTPS Redirection: Forces all traffic to be secure.
  3. React Router Support: Redirects all non-file requests to index.html to prevent 404 errors on page refresh.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="API Proxy" stopProcessing="true">
          <match url="^api/(.*)" />
          <action type="Rewrite" url="http://localhost:4000/api/{R:1}" />
        </rule>
        <rule name="React Routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Phase 4: Networking, DNS, and the SSL Mystery

One of the biggest hurdles in university-scale deployments is the “Split-Horizon” network architecture.

1. Solving the “Failed to Fetch” SSL Error

During deployment, background API calls often fail even if the main page loads. This is usually due to SSL Termination.

  • The Problem: If you use a self-signed certificate, the browser trusts the page but blocks background fetch() calls.
  • The Solution: The university uses a Central Gateway Proxy (e.g., 213.55.95.87) that handles SSL. Our internal IIS server communicates via the internal IP (10.4.9.100), but the Gateway presents a trusted, CA-signed certificate to the public.

2. DNS and IP Mapping

Your server has several identities:

  • Internal IP: 10.4.9.100 (Used for departmental access).
  • Inbound Gateway: 213.55.95.87 (Where sinet.aau.edu.et points).
  • Outbound Interface: 196.189.55.75 (How the server sees the internet).

A tracert command reveals the complex path data takes through the university fiber backbone and Ethio Telecom routers before reaching the global web.

Troubleshooting & Troubleshooting Tips

  • “wants to access local network” Popup: This happens if your frontend .env is still pointing to the 10.x.x.x IP instead of the official domain.
  • Port 80 Conflict: Ensure no other site in IIS is using “All Unassigned” port 80 if you have multiple bindings.
  • Prisma Errors: If the DB fails to connect, verify that your Windows Firewall allows inbound traffic on port 5432.

Future Works and Scaling

Now that Sinet-JMS is live and stable, the roadmap for expansion includes:

  1. Amharic AI Integration: Building on local research to provide automated sentiment analysis for Amharic manuscript summaries.
  2. Dockerization: Moving to a container-based deployment to allow other colleges to spin up their own instances in minutes.
  3. Real-time Monitoring: Implementing Grafana dashboards to track server health and request latency.

Final Status: Live, Secure, and Persistent.


메타데이터
post_id
6d2e99cd1439
slug
from-localhost-to-production-the-ultimate-guide-to-deploying-a-jms-on-windows-server-6d2e99cd1439
url
https://medium.com/@alexkalalw/from-localhost-to-production-the-ultimate-guide-to-deploying-a-jms-on-windows-server-6d2e99cd1439
canonical_url
https://medium.com/@alexkalalw/from-localhost-to-production-the-ultimate-guide-to-deploying-a-jms-on-windows-server-6d2e99cd1439
author_url
https://medium.com/@alexkalalw
status
ok
fetched_at
2026-07-11 20:55:18