--- title: Node + Nginx locally description: Run the cloud-node-container image on your laptop for Express, custom Node apps, and PM2-managed processes. sidebar: order: 3 --- import { Steps, Aside } from '@astrojs/starlight/components'; import Support from '~/content/partials/support-link.mdx'; [`cloud-node-container`](https://repo.anhonesthost.net/cloud-hosting-platform/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)**. ## What's included - **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. ## Image tags Pull from `repo.anhonesthost.net/cloud-hosting-platform/cnoc:`. 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. ## Quick start with `local-dev.sh` 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: ```bash git clone https://repo.anhonesthost.net/cloud-hosting-platform/cloud-node-container.git cd cloud-node-container ``` 2. Start a local instance: ```bash ./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. ## Flags | Flag | Purpose | Default | |---|---|---| | `-n` | Container name (required) | — | | `-p` | HTTP port | `80` | | `-s` | HTTPS port | `443` | | `-r` | Root path for files | current directory | | `-a` | Node version (`18`, `20`, `22`) | `20` | | `-v` | Verbose mode | off | | `-h` | Show help | — | Example — run a Node 22 instance on port 3000: ```bash ./local-dev.sh -n my-node22-app -a 22 -p 3000 -s 3443 ``` ## Manual Docker usage ```bash 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 ``` ## Get a shell inside the container ```bash docker exec -it local-dev /bin/bash ``` Useful for running `pm2 ls`, `pm2 logs`, or `npm` commands against your bind-mounted app folder. ## Where your code goes Your Node application lives at `user/app/` on your laptop. Inside the container that's `/home//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: ```bash 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. ## Logs | Where | What | |---|---| | `user/logs/nginx/` | Nginx access + error logs | | `user/logs/nodejs/` | PM2's stdout/stderr capture from your Node app | Tail them from your laptop: ```bash tail -F user/logs/nodejs/*.log ``` Or via the helper script: ```bash ./instance_logs ``` ## Stop / start / clean up ```bash ./instance_stop # stop the container ./instance_start # start it again ./instance_logs # view container logs ./instance_shell # exec into the container ``` To wipe everything: ```bash docker rm -f local-dev rm -rf local-development/ ``` ## Source [`cloud-node-container` on Gitea](https://repo.anhonesthost.net/cloud-hosting-platform/cloud-node-container) — Dockerfile, Nginx + PM2 configs, entrypoint, and the `local-dev.sh` script. ## Related - [PHP + Apache locally](/whp/local-dev/php-apache/) - [Create a site](/whp/how-to/create-a-site/) — the hosted side. ## Still stuck?