Skip to content

Node + Nginx locally

cloud-node-container (image: cnoc) is the same Node + Nginx image we use for hosted Node sites. It’s based on AlmaLinux 9, ships with Node 18, 20, and 22 side-by-side (default 20), uses PM2 as the process manager, and fronts your app with Nginx (SSL + HTTP→HTTPS redirect).

  • Multiple Node versions — 18, 20, 22, switchable via NODEVER env var or the -a flag.
  • PM2 for production-grade process management — automatic restart, log rotation.
  • Nginx reverse proxy with SSL and HTTP→HTTPS redirect.
  • Memcached for sessions, automatic backups, log rotation.
  • /ping health endpoint baked into the proxy config.

Pull from repo.anhonesthost.net/cloud-hosting-platform/cnoc:<tag>. The most useful tags:

  • cnoc:latest — the default (Node 20).
  • Version-pinned tags follow the same pattern (cnoc:node18, cnoc:node20, cnoc:node22).

Check the repo for the current tag list.

The repo ships a local-dev.sh script that handles the Docker run, creates the bind-mount layout, generates helper scripts, and scaffolds a sample Express app if none exists.

  1. Clone the repo and cd in:

    Terminal window
    git clone https://repo.anhonesthost.net/cloud-hosting-platform/cloud-node-container.git
    cd cloud-node-container
  2. Start a local instance:

    Terminal window
    ./local-dev.sh -n local-dev
  3. The script will:

    • Create user + log directories (nginx/, nodejs/).
    • Scaffold a default Express app under user/app/ if you haven’t dropped your own in yet.
    • Start the container with the right env vars.
    • Generate helper scripts (instance_start, instance_stop, instance_logs, instance_shell).
  4. Open http://localhost/ in a browser — the sample Express app’s response page should be there. Or hit http://localhost/ping to confirm the health endpoint.

FlagPurposeDefault
-nContainer name (required)
-pHTTP port80
-sHTTPS port443
-rRoot path for filescurrent directory
-aNode version (18, 20, 22)20
-vVerbose modeoff
-hShow help

Example — run a Node 22 instance on port 3000:

Terminal window
./local-dev.sh -n my-node22-app -a 22 -p 3000 -s 3443
Terminal window
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
Terminal window
docker exec -it local-dev /bin/bash

Useful for running pm2 ls, pm2 logs, or npm commands against your bind-mounted app folder.

Your Node application lives at user/app/ on your laptop. Inside the container that’s /home/<user>/app/. The container is configured to run your app from there via PM2.

Minimum required files in user/app/:

  • package.json — describes your app and dependencies; must define a start command ("start": "node server.js" in scripts).
  • A main JavaScript file — typically server.js or index.js.

After dropping files in, restart the container so PM2 picks up the new app:

Terminal window
docker restart local-dev

Your app should bind to the port shown by the container’s env var (usually process.env.PORT). Nginx forwards traffic to that port internally and proxies SSL.

WhereWhat
user/logs/nginx/Nginx access + error logs
user/logs/nodejs/PM2’s stdout/stderr capture from your Node app

Tail them from your laptop:

Terminal window
tail -F user/logs/nodejs/*.log

Or via the helper script:

Terminal window
./instance_logs
Terminal window
./instance_stop # stop the container
./instance_start # start it again
./instance_logs # view container logs
./instance_shell # exec into the container

To wipe everything:

Terminal window
docker rm -f local-dev
rm -rf local-development/

cloud-node-container on Gitea — Dockerfile, Nginx + PM2 configs, entrypoint, and the local-dev.sh script.

Still stuck? Open a support ticket and our team will help.