---
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:<tag>`.

## 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.

<Steps>

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.

</Steps>

## 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 (`<name>-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/
```

<Aside type="tip">
  Want to test the exact PHP version of your hosted WHP site locally? Match the `-a` flag to your site's PHP version on the [Sites page](/whp/how-to/create-a-site/).
</Aside>

## 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?

<Support />
