Files
cloud-node-container/README.md
jknapp 2029c8821e
All checks were successful
Cloud Node Container / Build-and-Push (18) (push) Successful in 1m48s
Cloud Node Container / Build-and-Push (20) (push) Successful in 1m48s
Cloud Node Container / Build-and-Push (22) (push) Successful in 1m51s
Add comprehensive troubleshooting section and clarify user permissions
- Clarified that uid/user must match host system values
- Added note that PM2 runs as specified user for security
- Created troubleshooting section with common issues:
  - 502 Bad Gateway errors
  - Permission errors
  - App not starting
- Provided specific commands for debugging each issue

This documentation helps users understand and resolve common
container deployment issues.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-24 10:24:42 -07:00

10 KiB
Raw Permalink Blame History

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 container
    • instance_stop Stop the container
    • instance_logs View container logs
    • instance_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 or index.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:

  1. 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"
  }
}
  1. 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}`);
});
  1. Put your files in the right place:

    • Copy your package.json and server.js to user/app/
    • Put HTML, CSS, images in user/app/public/
  2. 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.

PM2 Configuration Notes:

  • The auto-generated PM2 config uses fork mode (not cluster mode) for simplicity and compatibility
  • wait_ready is set to false by default - your app doesn't need to send any special signals to PM2
  • PM2 runs as the specified user (not root) for security - ensure your uid and user match your host system
  • If you need advanced PM2 features, you can provide your own ecosystem.config.js file

Advanced Usage: If you want to use PM2's wait_ready feature for health checking:

  1. Create your own ecosystem.config.js with wait_ready: true
  2. Add process.send('ready') in your app when it's ready to accept connections:
    app.listen(port, () => {
      console.log(`Server running on port ${port}`);
      if (process.send) {
        process.send('ready');
      }
    });
    

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:

  1. Runs npm install to install dependencies
  2. Starts your app with PM2 process manager
  3. Sets up Nginx reverse proxy with SSL
  4. Configures logging and health checks
  5. 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 use app.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 permissions (must match your host user ID)
  • user Username for file permissions (must match your host username)
  • domain Primary domain for configuration

Optional:

  • environment Set to DEV to start Redis and enable development features
  • serveralias Comma-separated list of alternative hostnames
  • NODEVER 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 or docker start {container-name}
  • To stop: ./instance_stop or docker stop {container-name}
  • To view logs: ./instance_logs or docker logs -f {container-name}
  • To access shell: ./instance_shell or docker 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

Common Issues and Solutions

502 Bad Gateway errors:

  • Check if your app is running on port 3000 (or the PORT environment variable)
  • Look at nginx error logs: /home/$user/logs/nginx/error.log
  • Verify PM2 status: docker exec <container> su - <user> -c "pm2 status"

Permission errors:

  • Ensure uid and user environment variables match your host system
  • Use $(id -u) and $(whoami) in your docker run command
  • Files should be owned by your user, not root

App not starting:

  • Check PM2 logs: /home/$user/logs/nodejs/error.log
  • Verify your package.json has correct main or scripts.start field
  • Ensure all dependencies are listed in package.json