From 69439afe4a5e78c327da68fb2921909eda7de103 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 18 May 2026 12:01:49 -0700 Subject: [PATCH] docs(local-dev): add 'Local development' section + PHP 8.5 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds /whp/local-dev/ with three articles documenting the public cloud container images on repo.anhonesthost.net/cloud-hosting-platform/: - overview: dev/prod parity pitch, prerequisites, table of images, link to the Gitea org, and a note that this is for customers comfortable with Docker (the hosted side needs none of this). - php-apache: cloud-apache-container (cac). PHP 7.4 through 8.5 side by side, default 8.3, AlmaLinux 9 + Apache mod_ssl. Documents image tags, local-dev.sh flags, manual docker command, bind-mount layout, WordPress install, helper scripts (instance_start / instance_stop / instance_logs / instance_db_info), and cleanup. - node: cloud-node-container (cnoc). Node 18/20/22, default 20, AlmaLinux 9 + Nginx (SSL + HTTP→HTTPS redirect) + PM2 + Memcached. Same shape: tags, flags, manual docker, where code goes (user/app/), logs layout, helpers, cleanup. Sidebar gains a 'Local development' group between Site Builder and Reference. Section redirect /whp/local-dev/ -> overview added to the section-landing redirect set. --- astro.config.mjs | 5 + src/content/docs/whp/local-dev/node.mdx | 169 ++++++++++++++++++ src/content/docs/whp/local-dev/overview.mdx | 50 ++++++ src/content/docs/whp/local-dev/php-apache.mdx | 155 ++++++++++++++++ 4 files changed, 379 insertions(+) create mode 100644 src/content/docs/whp/local-dev/node.mdx create mode 100644 src/content/docs/whp/local-dev/overview.mdx create mode 100644 src/content/docs/whp/local-dev/php-apache.mdx diff --git a/astro.config.mjs b/astro.config.mjs index 0c26271..da2605f 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -15,6 +15,7 @@ export default defineConfig({ '/whp/getting-started/': '/whp/getting-started/welcome/', '/whp/how-to/': '/whp/how-to/add-a-domain/', '/whp/site-builder/': '/whp/site-builder/overview/', + '/whp/local-dev/': '/whp/local-dev/overview/', '/whp/reference/': '/whp/reference/service-hostnames/', '/whp/add-ons/': '/whp/add-ons/overview/', '/whp/admin/': '/whp/admin/overview/', @@ -65,6 +66,10 @@ export default defineConfig({ badge: { text: 'Beta', variant: 'tip' }, items: [{ autogenerate: { directory: 'whp/site-builder' } }], }, + { + label: 'Local development', + items: [{ autogenerate: { directory: 'whp/local-dev' } }], + }, { label: 'Reference', items: [{ autogenerate: { directory: 'whp/reference' } }], diff --git a/src/content/docs/whp/local-dev/node.mdx b/src/content/docs/whp/local-dev/node.mdx new file mode 100644 index 0000000..6844492 --- /dev/null +++ b/src/content/docs/whp/local-dev/node.mdx @@ -0,0 +1,169 @@ +--- +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? + + diff --git a/src/content/docs/whp/local-dev/overview.mdx b/src/content/docs/whp/local-dev/overview.mdx new file mode 100644 index 0000000..d10cac3 --- /dev/null +++ b/src/content/docs/whp/local-dev/overview.mdx @@ -0,0 +1,50 @@ +--- +title: Develop locally with our containers +description: Run the same Apache/PHP and Node containers locally that we use to host your site in production. +sidebar: + order: 1 +--- + +import { Aside } from '@astrojs/starlight/components'; +import Support from '~/content/partials/support-link.mdx'; + +The same container images we use to host your site in production are published as open-source images you can pull and run on your laptop. If you're comfortable with Docker, this gives you a development environment that matches production exactly — same OS, same Apache/Nginx config, same PHP or Node version. + +## Why use our containers locally + +- **Dev/prod parity.** Anything that runs in the container on your machine will run the same way in production. No "works on my Mac" surprises. +- **Quick start.** Each container ships a `local-dev.sh` script that handles the Docker incantation, volume layout, and helper commands. +- **No account required.** The images are public — pull and run. + + + +## Available containers + +| Stack | Image | Use case | +|---|---|---| +| **PHP + Apache** | `repo.anhonesthost.net/cloud-hosting-platform/cac` | WordPress, Laravel, traditional PHP apps | +| **Node + Nginx** | `repo.anhonesthost.net/cloud-hosting-platform/cnoc` | Express, custom Node apps, PM2-managed processes | + +Both images live in our public Gitea organisation at [repo.anhonesthost.net/cloud-hosting-platform/](https://repo.anhonesthost.net/cloud-hosting-platform/) — the source Dockerfiles, build configs, and helper scripts are all there too. Issues and PRs welcome. + +## Prerequisites + +- **Docker** (or a compatible runtime like Podman / OrbStack / Rancher Desktop). Docker Desktop on Mac/Windows or `docker.io` on Linux both work. +- A terminal where you can run `git`, `docker`, and basic shell scripts. +- Ports `80` and `443` free on your machine (the local-dev scripts bind these by default; both can be overridden with flags). + +## Pick your stack + +- **[PHP + Apache locally](/whp/local-dev/php-apache/)** — for WordPress and any PHP application. +- **[Node + Nginx locally](/whp/local-dev/node/)** — for Express, Next.js standalone, or any Node app. + +## Related + +- [Create a site](/whp/how-to/create-a-site/) — how the same images run as hosted sites in WHP. +- [What is containerized hosting?](/whp/getting-started/what-is-containerized-hosting/) + +## Still stuck? + + diff --git a/src/content/docs/whp/local-dev/php-apache.mdx b/src/content/docs/whp/local-dev/php-apache.mdx new file mode 100644 index 0000000..3221d07 --- /dev/null +++ b/src/content/docs/whp/local-dev/php-apache.mdx @@ -0,0 +1,155 @@ +--- +title: PHP + Apache locally +description: Run the cloud-apache-container image on your laptop for WordPress and other PHP apps. +sidebar: + order: 2 +--- + +import { Steps, Aside } from '@astrojs/starlight/components'; +import Support from '~/content/partials/support-link.mdx'; + +[`cloud-apache-container`](https://repo.anhonesthost.net/cloud-hosting-platform/cloud-apache-container) (image: **`cac`**) is the same Apache + PHP image we use for hosted PHP sites. It's based on **AlmaLinux 9**, ships with **PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, and 8.5** side-by-side (default 8.3), and uses **Apache with mod_ssl**. + +## Image tags + +Pre-built tags are pushed on every change: + +- `cac:latest` — the default (PHP 8.3). +- `cac:php74`, `cac:php80`, `cac:php81`, `cac:php82`, `cac:php83`, `cac:php84`, `cac:php85` — pin to a specific PHP version. + +Pull from `repo.anhonesthost.net/cloud-hosting-platform/cac:`. + +## Quick start with `local-dev.sh` + +The repo ships a `local-dev.sh` script that handles the Docker incantation, creates the volume + log directories, generates helper scripts, and installs a fresh WordPress in the web root. + + + +1. Clone the repo and `cd` in: + + ```bash + git clone https://repo.anhonesthost.net/cloud-hosting-platform/cloud-apache-container.git + cd cloud-apache-container + ``` + +2. Start a local instance: + + ```bash + ./local-dev.sh -n local-dev + ``` + +3. The script will: + - Create a user directory and log folders (`apache/`, `system/`). + - Create a Docker volume for MySQL. + - Start the container with the right env vars. + - Generate helper scripts in your root path (`instance_start`, `instance_stop`, `instance_logs`, `instance_db_info`). + - Install WordPress in your web root. + - Print the MySQL credentials it generated. + +4. Open `http://localhost/` in a browser — WordPress's setup screen should be there. + + + +## Flags + +| Flag | Purpose | Default | +|---|---|---| +| `-n` | Container name (required) | — | +| `-p` | HTTP port | `80` | +| `-s` | HTTPS port | `443` | +| `-r` | Root path for files and DB | current directory | +| `-a` | PHP version (`74`, `80`, `81`, `82`, `83`, `84`, `85`) | `83` | +| `-v` | Verbose mode | off | +| `-h` | Show help | — | + +Example — run a PHP 8.5 instance on port 8080: + +```bash +./local-dev.sh -n my-php85-site -a 85 -p 8080 -s 8443 +``` + +## Manual Docker usage + +If you'd rather skip the script and run it yourself: + +```bash +mkdir -p local-development/domain.tld +cd local-development/domain.tld +mkdir user +mkdir -p user/logs/{apache,system} + +docker run -d -it \ + -p 80:80 -p 443:443 \ + -e PHPVER=84 -e environment=DEV \ + --mount type=bind,source="$(pwd)"/user,target=/home/myuser \ + -v"$name-mysql":/var/lib/mysql \ + -e uid=30001 -e user=myuser -e domain=localhost \ + --name local-dev \ + repo.anhonesthost.net/cloud-hosting-platform/cac:latest +``` + +## Get a shell inside the container + +```bash +docker exec -it local-dev /bin/bash +``` + +Useful for running `wp-cli`, tailing logs from inside, or checking PHP modules. + +## Where things live + +| Inside the container | On your laptop (via bind mount) | +|---|---| +| `/home/myuser/public_html/` — Apache docroot | `local-development/domain.tld/user/public_html/` | +| `/home/myuser/logs/apache/` — Apache logs | `local-development/domain.tld/user/logs/apache/` | +| `/var/lib/mysql/` — MySQL data | Named Docker volume (`-mysql`) | +| `/home/myuser/mysql_creds` | Same path on the bind mount | + +## WordPress + +`local-dev.sh` installs WordPress automatically. If you started manually: + +```bash +docker exec -it local-dev bash +cat /home/myuser/mysql_creds # see the credentials +cd /home/myuser/public_html +wp core download +wp config create --dbname=... --dbuser=... --dbpass=... --dbhost=localhost +wp core install --url=http://localhost --title="Local Dev" --admin_user=admin --admin_email=you@example.com +``` + +## Stop / start / clean up + +The helper scripts the local-dev script writes are the easy path: + +```bash +./instance_stop # stop the container +./instance_start # start it again +./instance_logs # tail Apache logs +./instance_db_info # show MySQL credentials +``` + +To wipe everything: + +```bash +docker rm -f local-dev +docker volume rm local-dev-mysql +rm -rf local-development/ +``` + + + +## Source + +[`cloud-apache-container` on Gitea](https://repo.anhonesthost.net/cloud-hosting-platform/cloud-apache-container) — Dockerfile, entrypoint, build configs, and the `local-dev.sh` script. + +## Related + +- [Node + Nginx locally](/whp/local-dev/node/) +- [Create a site](/whp/how-to/create-a-site/) — the hosted side. + +## Still stuck? + +