Deploying Express.js on Hop3¶
This guide walks you through deploying an Express.js application on Hop3. By the end, you'll have a production-ready Node.js application running on your own infrastructure.
Prerequisites¶
Before you begin, ensure you have:
- A Hop3 server - Follow the Installation Guide if you haven't set one up yet
- The Hop3 CLI - Installed on your local machine
- Node.js 18+ - Install from nodejs.org or via your package manager
- npm - Comes with Node.js
- Git - For version control and deployment
Verify your local setup:
Step 1: Create a New Express Application¶
Create the project directory and initialize it:
Install Express and production dependencies:
Step 2: Create the Application¶
Create the main application file:
const express = require('express');
const app = express();
// Parse JSON bodies
app.use(express.json());
// Welcome route
app.get('/', (req, res) => {
res.json({
message: 'Hello from Hop3!',
timestamp: new Date().toISOString()
});
});
// Health check endpoint for Hop3
app.get('/up', (req, res) => {
res.status(200).send('OK');
});
app.get('/health', (req, res) => {
res.json({
status: 'ok',
uptime: process.uptime(),
memory: process.memoryUsage()
});
});
// Example API route
app.get('/api/info', (req, res) => {
res.json({
name: 'hop3-tuto-express',
version: '1.0.0',
node: process.version,
env: process.env.NODE_ENV || 'development'
});
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
module.exports = app;
Step 3: Add Development Scripts¶
Update package.json with useful scripts:
{
"name": "hop3-tuto-express",
"version": "1.0.0",
"description": "Express.js application for Hop3",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "node --watch app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.0"
},
"engines": {
"node": ">=18.0.0"
}
}
Step 4: Verify the Application Works¶
Test locally (skipped in automated tests - local server tests are flaky):
Check the package structure:
Step 5: Create Deployment Configuration¶
Create a Procfile¶
Create a Procfile in your project root:
Create hop3.toml¶
Create a hop3.toml for advanced configuration:
[metadata]
id = "hop3-tuto-express"
version = "1.0.0"
title = "My Express Application"
[build]
before-build = ["npm install"]
packages = ["nodejs", "npm"]
[run]
start = "node app.js"
[env]
NODE_ENV = "production"
[port]
web = 3000
[healthcheck]
path = "/up"
timeout = 30
interval = 60
Verify the deployment files exist:
Step 6: Initialize Git Repository¶
Create a .gitignore file:
# Dependencies
node_modules/
# Logs
logs/
*.log
npm-debug.log*
# Environment
.env
.env.local
.env.*.local
# OS files
.DS_Store
Thumbs.db
# IDE
.idea/
.vscode/
*.swp
*.swo
# Build output
dist/
build/
Initialize the repository:
Step 7: Deploy to Hop3¶
The following steps require a Hop3 server. Set the HOP3_SERVER environment variable to your server address before running these commands.
Configure the CLI¶
If this is your first deployment, initialize Hop3:
Deploy¶
Deploy the application (first deployment creates the app):
Set Hostname¶
Configure the hostname for nginx proxy:
Wait for Process Stop¶
Wait for the previous deployment to fully stop:
Apply Configuration¶
Redeploy to apply the hostname configuration:
Step 8: Verify Deployment¶
Check your application status:
Managing Your Application¶
Restart the Application¶
Run Commands in the Application Context¶
View and Manage Environment Variables¶
# List all variables
hop3 config:show hop3-tuto-express
# Set a variable
hop3 config:set hop3-tuto-express NEW_VARIABLE=value
# Remove a variable
hop3 config:unset hop3-tuto-express OLD_VARIABLE
Scaling¶
# Check current processes
hop3 ps hop3-tuto-express
# Scale web workers
hop3 ps:scale hop3-tuto-express web=2
Advanced Configuration¶
Adding a Database (PostgreSQL)¶
Install the PostgreSQL client:
Create a database configuration file:
// db.js
const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false
});
module.exports = {
query: (text, params) => pool.query(text, params),
pool
};
Attach a database addon:
hop3 addons:create postgres hop3-tuto-express-db
hop3 addons:attach hop3-tuto-express hop3-tuto-express-db
Adding Redis for Sessions/Caching¶
Install Redis client:
Configure session middleware:
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');
const redisClient = createClient({ url: process.env.REDIS_URL });
redisClient.connect();
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}));
Attach a Redis addon:
hop3 addons:create redis hop3-tuto-express-redis
hop3 addons:attach hop3-tuto-express hop3-tuto-express-redis
hop3 config:set hop3-tuto-express SESSION_SECRET=$(openssl rand -hex 32)
Using PM2 for Process Management¶
For more robust process management, use PM2:
Create ecosystem.config.js:
module.exports = {
apps: [{
name: 'hop3-tuto-express',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
env_production: {
NODE_ENV: 'production'
}
}]
};
Update Procfile:
TypeScript Support¶
For TypeScript projects, add build configuration:
Update package.json:
Update hop3.toml:
CORS Configuration¶
For API servers accessed from different domains:
const cors = require('cors');
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
Request Logging with Morgan¶
const morgan = require('morgan');
// Use 'combined' format in production for detailed logs
app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));
Troubleshooting¶
Application Won't Start¶
Check the logs for errors:
Common issues:
- Missing dependencies: Ensure npm install runs during build
- Wrong Node.js version: Check engines field in package.json
- Port binding: Ensure you use process.env.PORT
Memory Issues¶
Node.js can consume significant memory. Set limits:
Module Not Found Errors¶
Ensure all dependencies are in dependencies (not devDependencies) if needed in production:
Slow Startup¶
For faster cold starts:
- Minimize dependencies
- Use lazy loading for heavy modules
- Consider using esbuild or webpack to bundle your app
Next Steps¶
- CLI Reference - Complete command reference
- hop3.toml Reference - Full configuration options
- Backup and Restore Guide - Protect your data
Example Files¶
Complete hop3.toml for Express¶
# hop3.toml - Express.js Application
[metadata]
id = "hop3-tuto-express"
version = "1.0.0"
title = "My Express Application"
author = "Your Name <you@example.com>"
[build]
before-build = ["npm install --production"]
packages = ["nodejs"]
[run]
start = "node app.js"
[env]
NODE_ENV = "production"
[port]
web = 3000
[healthcheck]
path = "/up"
timeout = 30
interval = 60
[[provider]]
name = "postgres"
plan = "standard"