🚀 How to Host Website Using Node.js

• Originally published on old blog

Note: This post was originally published in 2014. While the core concepts remain valid, some examples may use older Node.js syntax. Modern Node.js development often uses frameworks like Express.js and deployment platforms like Vercel, Netlify, or cloud providers.

Node.js has revolutionized web development by allowing developers to use JavaScript on both the client and server side. In this guide, I'll show you how to create a simple web server using Node.js and host your website.

Prerequisites

  • Node.js installed on your system
  • Basic knowledge of JavaScript
  • A text editor (VS Code, Sublime Text, etc.)

Step 1: Create Your Project Structure

First, create a new directory for your project and initialize it:

mkdir my-website
cd my-website
npm init -y

Step 2: Create the Basic Server

Create a file named server.js with the following content:

const http = require('http');
const fs = require('fs');
const path = require('path');

const PORT = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
    let filePath = '.' + req.url;
    
    if (filePath === './') {
        filePath = './index.html';
    }
    
    const extname = path.extname(filePath);
    let contentType = 'text/html';
    
    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;
        case '.jpg':
            contentType = 'image/jpg';
            break;
    }
    
    fs.readFile(filePath, (error, content) => {
        if (error) {
            if (error.code === 'ENOENT') {
                res.writeHead(404);
                res.end('File not found');
            } else {
                res.writeHead(500);
                res.end('Server error: ' + error.code);
            }
        } else {
            res.writeHead(200, { 'Content-Type': contentType });
            res.end(content, 'utf-8');
        }
    });
});

server.listen(PORT, () => {
    console.log(`Server running at http://localhost:${PORT}/`);
});

Step 3: Create Your HTML File

Create an index.html file in your project directory:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Node.js Website</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            line-height: 1.6;
        }
        .header {
            background-color: #f4f4f4;
            padding: 20px;
            border-radius: 5px;
            margin-bottom: 20px;
        }
        .content {
            background-color: white;
            padding: 20px;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>Welcome to My Node.js Website</h1>
        <p>This website is hosted using Node.js!</p>
    </div>
    
    <div class="content">
        <h2>About This Site</h2>
        <p>This is a simple website created and hosted using Node.js. The server handles:</p>
        <ul>
            <li>Static file serving</li>
            <li>Content-Type detection</li>
            <li>Error handling</li>
            <li>Basic routing</li>
        </ul>
        
        <h2>Features</h2>
        <ul>
            <li>Lightweight and fast</li>
            <li>Easy to customize</li>
            <li>Cross-platform compatibility</li>
            <li>No external dependencies</li>
        </ul>
    </div>
</body>
</html>

Step 4: Run Your Server

Start your server by running:

node server.js

Your website will be available at http://localhost:3000

Step 5: Adding More Features

Let's enhance the server with some additional features:

Enhanced Server with Logging

const http = require('http');
const fs = require('fs');
const path = require('path');

const PORT = process.env.PORT || 3000;

// Simple logging middleware
function logRequest(req, res, next) {
    const timestamp = new Date().toISOString();
    console.log(`[${timestamp}] ${req.method} ${req.url}`);
    next();
}

const server = http.createServer((req, res) => {
    // Log the request
    logRequest(req, res, () => {});
    
    let filePath = '.' + req.url;
    
    if (filePath === './') {
        filePath = './index.html';
    }
    
    const extname = path.extname(filePath);
    let contentType = 'text/html';
    
    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;
        case '.jpg':
            contentType = 'image/jpg';
            break;
        case '.ico':
            contentType = 'image/x-icon';
            break;
    }
    
    fs.readFile(filePath, (error, content) => {
        if (error) {
            if (error.code === 'ENOENT') {
                res.writeHead(404, { 'Content-Type': 'text/html' });
                res.end('<h1>404 - Page Not Found</h1><p>The requested page could not be found.</p>');
            } else {
                res.writeHead(500, { 'Content-Type': 'text/html' });
                res.end('<h1>500 - Internal Server Error</h1><p>Something went wrong on the server.</p>');
            }
        } else {
            res.writeHead(200, { 'Content-Type': contentType });
            res.end(content, 'utf-8');
        }
    });
});

server.listen(PORT, () => {
    console.log(`🚀 Server running at http://localhost:${PORT}/`);
    console.log(`📁 Serving files from: ${__dirname}`);
});

Step 6: Adding API Endpoints

You can also add simple API endpoints to your server:

const http = require('http');
const fs = require('fs');
const path = require('path');

const PORT = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
    const url = req.url;
    const method = req.method;
    
    // API endpoints
    if (url === '/api/status' && method === 'GET') {
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({
            status: 'OK',
            timestamp: new Date().toISOString(),
            uptime: process.uptime()
        }));
        return;
    }
    
    if (url === '/api/hello' && method === 'GET') {
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({
            message: 'Hello from Node.js!',
            timestamp: new Date().toISOString()
        }));
        return;
    }
    
    // Handle POST requests
    if (url === '/api/echo' && method === 'POST') {
        let body = '';
        req.on('data', chunk => {
            body += chunk.toString();
        });
        req.on('end', () => {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
                message: 'Echo response',
                data: body,
                timestamp: new Date().toISOString()
            }));
        });
        return;
    }
    
    // Serve static files (existing code...)
    let filePath = '.' + url;
    
    if (filePath === './') {
        filePath = './index.html';
    }
    
    const extname = path.extname(filePath);
    let contentType = 'text/html';
    
    switch (extname) {
        case '.js':
            contentType = 'text/javascript';
            break;
        case '.css':
            contentType = 'text/css';
            break;
        case '.json':
            contentType = 'application/json';
            break;
        case '.png':
            contentType = 'image/png';
            break;
        case '.jpg':
            contentType = 'image/jpg';
            break;
    }
    
    fs.readFile(filePath, (error, content) => {
        if (error) {
            if (error.code === 'ENOENT') {
                res.writeHead(404, { 'Content-Type': 'text/html' });
                res.end('<h1>404 - Page Not Found</h1>');
            } else {
                res.writeHead(500, { 'Content-Type': 'text/html' });
                res.end('<h1>500 - Internal Server Error</h1>');
            }
        } else {
            res.writeHead(200, { 'Content-Type': contentType });
            res.end(content, 'utf-8');
        }
    });
});

server.listen(PORT, () => {
    console.log(`🚀 Server running at http://localhost:${PORT}/`);
    console.log(`📡 API endpoints available:`);
    console.log(`   GET  /api/status - Server status`);
    console.log(`   GET  /api/hello  - Hello message`);
    console.log(`   POST /api/echo   - Echo POST data`);
});

Step 7: Production Deployment

For production deployment, consider these options:

Using PM2 (Process Manager)

# Install PM2 globally
npm install -g pm2

# Start your application
pm2 start server.js --name "my-website"

# Monitor your application
pm2 monit

# View logs
pm2 logs

# Restart application
pm2 restart my-website

# Stop application
pm2 stop my-website

Using Environment Variables

// Create a .env file
PORT=3000
NODE_ENV=production

// Install dotenv
npm install dotenv

// Update server.js
require('dotenv').config();

const PORT = process.env.PORT || 3000;
const NODE_ENV = process.env.NODE_ENV || 'development';

console.log(`Environment: ${NODE_ENV}`);
console.log(`Port: ${PORT}`);

Step 8: Package.json Configuration

Update your package.json with scripts:

{
  "name": "my-website",
  "version": "1.0.0",
  "description": "A simple Node.js website",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": ["nodejs", "website", "server"],
  "author": "Your Name",
  "license": "MIT",
  "dependencies": {
    "dotenv": "^16.0.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  }
}

Best Practices

  • Use environment variables for configuration
  • Implement proper error handling for production
  • Add logging for debugging and monitoring
  • Use a process manager like PM2 for production
  • Implement security headers and input validation
  • Use HTTPS in production

Common Issues and Solutions

  • Port already in use: Change the PORT environment variable
  • File not found errors: Check file paths and permissions
  • Memory leaks: Use proper cleanup in event listeners
  • Performance issues: Implement caching and compression

Key Takeaways

  • Node.js provides a simple way to create web servers
  • Static file serving is straightforward with the built-in modules
  • You can easily add API endpoints to your server
  • Use process managers like PM2 for production deployment
  • Environment variables help with configuration management