- Force PM2 to use fork mode instead of cluster mode - Disable wait_ready to avoid startup issues - Add PM2 ready signal to simple-website server - Add PM2 status check after startup - Set NODE_ENV=production for PM2 startup The cluster mode was causing the UID 1002 error. Fork mode runs the process directly as the specified user without additional permission complications. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Cloud Node Container
This is a base container for running Node.js applications, supporting multiple Node.js versions (18, 20, 22). The default is Node.js 20. The container is based on AlmaLinux 9 and uses Nginx as a reverse proxy with SSL. It is designed for both development and production use.
You must have Docker or compatible containerization software running.
What's Included?
- Multiple Node.js Versions: 18, 20, 22 (set with
NODEVER
or-a
flag) - PM2 Process Manager: For production-grade Node.js application management
- Nginx Reverse Proxy: SSL-enabled reverse proxy with automatic HTTP to HTTPS redirect
- Development Features: Memcached for sessions, automatic backups, log rotation
- Health Monitoring: Built-in
/ping
endpoint for health checks
Quick Start: Local Development with local-dev.sh
The easiest way to start a local development environment is with the provided local-dev.sh
script. This script automates container setup, volume creation, log directories, and creates a sample Node.js application.
Usage Example
./local-dev.sh -n local-dev
Flags:
-n
Name of the container (required)-p
HTTP port (default: 80)-s
HTTPS port (default: 443)-r
Root path for files (default: current directory)-a
Node.js version (default: 20; options: 18, 20, 22)-v
Enable verbose mode-h
Show help
The script will:
- Create a user directory and log folders
- Create a default Node.js Express application if none exists
- Start the container with the correct environment variables
- Generate helper scripts in your root path:
instance_start
– Start the containerinstance_stop
– Stop the containerinstance_logs
– View container logsinstance_shell
– Access container shell
Manual Docker Usage
You can also run the container manually:
mkdir -p local-development/domain.tld
cd local-development/domain.tld
mkdir user
mkdir -p user/{app,logs/{nginx,nodejs}}
docker run -d -p 80:80 -p 443:443 -e NODEVER=20 -e environment=DEV --mount type=bind,source="$(pwd)"/user,target=/home/$(whoami) -e uid=$(id -u) -e user=$(whoami) -e domain=localhost --name local-dev repo.anhonesthost.net/cloud-hosting-platform/cnoc:latest
Accessing the Container
docker exec -it local-dev /bin/bash
For Users: How to Deploy Your Application
Step 1: Prepare Your Node.js Application
Your Node.js application needs just two files to get started:
Required Files:
package.json
- Describes your app and its dependencies- A main JavaScript file (usually
server.js
orindex.js
)
Optional Files:
public/
folder for static files (HTML, CSS, images)ecosystem.config.js
for advanced PM2 configuration (auto-generated if not provided)
Step 2: What Users Need to Do
If you're not familiar with Node.js, here's what you need to know:
- Create a
package.json
file - This tells Node.js about your app:
{
"name": "my-website",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2"
}
}
- Create your main server file - This runs your application:
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.use(express.static('public')); // Serve static files
app.get('/', (req, res) => {
res.send('<h1>My Website is Running!</h1>');
});
app.get('/ping', (req, res) => {
res.json({ status: 'ok' }); // Health check for the container
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
-
Put your files in the right place:
- Copy your
package.json
andserver.js
touser/app/
- Put HTML, CSS, images in
user/app/public/
- Copy your
-
Start the container:
./local-dev.sh -n my-app
That's it! The container will:
- Install your dependencies automatically
- Generate PM2 configuration from your package.json
- Start your application with PM2
- Handle SSL and reverse proxy
- Provide health monitoring
Important package.json fields:
- name: Used as the PM2 process name (defaults to 'node-app')
- main: Entry point file (defaults to 'index.js')
- scripts.start: Alternative way to specify entry point (e.g., "node server.js")
The container automatically generates an ecosystem.config.js file from your package.json if you don't provide one.
Step 3: Example Applications
See the examples/
directory for complete working examples:
Simple Website (examples/simple-website/
):
- Static HTML pages with navigation
- CSS styling
- Express.js server for routing
API Server (examples/api-server/
):
- REST API with CRUD operations
- JSON responses
- In-memory data storage
What Happens Automatically
When you place your app in user/app/
, the container automatically:
- Runs
npm install
to install dependencies - Starts your app with PM2 process manager
- Sets up Nginx reverse proxy with SSL
- Configures logging and health checks
- Starts Memcached for session storage (in DEV mode)
Troubleshooting for New Users
- App won't start? Check that your
package.json
has a valid "start" script - Can't access your site? Make sure your app listens on port 3000 and has a
/ping
endpoint - Dependencies missing? List all required packages in your
package.json
dependencies section - Static files not loading? Put them in a
public/
folder and useapp.use(express.static('public'))
Features
- Multiple Node.js Versions: 18, 20, 22 (set with
NODEVER
environment variable) - Process Management: PM2 for production-grade Node.js application management
- Reverse Proxy: Nginx handles SSL termination and proxies requests to Node.js
- Automatic Backups: Application files backed up every 30 minutes in DEV mode
- Log Management: Log rotation compresses logs older than 3 days, deletes after 7 days
- Session Storage: Memcached available in DEV mode for session management
- SSL: Self-signed certificate enabled by default with automatic HTTP→HTTPS redirect
- Health Checks:
/ping
,/info
endpoints for monitoring - Static Files: Nginx serves static files from
/home/$user/app/public/
Environment Variables
Required:
uid
– User ID for file permissionsuser
– Username for file permissionsdomain
– Primary domain for configuration
Optional:
environment
– Set toDEV
to start Redis and enable development featuresserveralias
– Comma-separated list of alternative hostnamesNODEVER
– Node.js version (18, 20, 22)
Default Application Endpoints
The default Express.js application provides:
/
– Basic application info and status/ping
– Health check endpoint (JSON response)/info
– Detailed system information/session
– Session demo endpoint (shows Memcached sessions working)
Helpful Notes
- To restart the instance:
./instance_start
ordocker start {container-name}
- To stop:
./instance_stop
ordocker stop {container-name}
- To view logs:
./instance_logs
ordocker logs -f {container-name}
- To access shell:
./instance_shell
ordocker exec -it {container-name} /bin/bash
- To delete a container:
docker rm {container-name}
(does not delete user files) - Application logs are in
/home/$user/logs/nodejs/
- Nginx logs are in
/home/$user/logs/nginx/
System Requirements
Memory Requirements
- Minimum RAM: 256MB (basic applications)
- Recommended RAM: 512MB (standard applications)
- Development: 512MB-1GB (with all services enabled)
The container is optimized for memory efficiency with automatic memory management and process restarts. See MEMORY-GUIDE.md
for detailed memory optimization information.
Performance Features
- Automatic application restart at 256MB memory usage
- V8 heap limited to 200MB by default
- Nginx optimized for single-worker, low-memory operation
- Memcached limited to 32MB cache size
Troubleshooting
- The first run may take a few minutes as Node.js and dependencies are installed
- If you need to change Node.js version, stop and remove the container, then recreate with the desired version
- For custom applications, ensure your
package.json
has a valid start script - Check
/home/$user/logs/nodejs/error.log
for application errors - The health check endpoint
/ping
should return a 200 status when the application is running properly - Memory issues: Run
/scripts/memory-info.sh
inside container to check memory usage - Process monitoring: Use
pm2 monit
to watch application performance