Private
Public Access
1
0

Initial commit: complete WebsiteBox project

Docker-based self-hosted WordPress deployment system with:
- Four-container stack (nginx, wordpress/php-fpm, mariadb, certbot)
- Automatic SSL via Let's Encrypt with self-signed fallback
- First-boot WordPress setup via WP-CLI (GeneratePress + child theme, plugins)
- Interactive setup wizard and one-line install script
- Backup, update, healthcheck, and SSL renewal scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
constantprojects
2026-02-20 15:24:23 -07:00
commit a440026701
32 changed files with 3397 additions and 0 deletions

99
CLAUDE.md Normal file
View File

@@ -0,0 +1,99 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Critical Rules
- **NEVER build, test, or run anything locally.** Always use Docker for all build/test/run operations.
- **`websitebox-brief (2).md` is the source of truth** for all project decisions and specifications. Always defer to it.
- **Do not load `websitebox-diagram (1).jsx`** unless the user explicitly asks for it — it is reference material only.
## Project Overview
WebsiteBox is a Docker-based, self-hosted WordPress deployment system. Users provision a VPS, run an install script, and get a working SSL-secured WordPress portfolio site with `docker compose up -d`. The project prioritizes zero-trust transparency, minimal CLI interaction, and VPS-agnostic deployment.
## Architecture
Four-container Docker Compose stack on a single Docker network (`websitebox_internal`):
- **nginx** (custom `nginx:alpine`) — Reverse proxy, SSL termination via Let's Encrypt. Only container exposing ports (80, 443). Entrypoint auto-acquires SSL certs on first boot.
- **wordpress** (custom `wordpress:php8.2-fpm-alpine`) — PHP-FPM with WP-CLI bundled. First-boot entrypoint installs WordPress core, GeneratePress theme, child theme, and plugins (Age Gate, Wordfence, UpdraftPlus) via WP-CLI.
- **db** (`mariadb:11`) — Internal only, never exposed to host.
- **certbot** (`certbot/certbot`) — Renewal loop every 12h, signals nginx via shared volume file trigger (no Docker socket mount).
All persistent data uses **bind mounts** under `./websitebox-data/` (not named Docker volumes):
- `wordpress/`, `database/`, `certs/`, `certbot-webroot/`, `certbot-signal/`, `backups/`
## Key Design Decisions
- **Restart policy**: `restart: unless-stopped` on all containers (not `always`).
- **SSL bootstrap**: Handled entirely in nginx entrypoint — no separate ssl-init.sh script. Nginx detects missing certs, serves HTTP for ACME challenge, acquires certs, reloads with SSL.
- **Certbot-to-nginx reload**: Certbot writes trigger file to shared `certbot-signal/` volume; nginx background loop detects and reloads. No Docker socket mounting.
- **WordPress setup**: All via WP-CLI in container entrypoint, not the mu-plugin. Uses marker files (`.websitebox-setup-complete` / `.websitebox-setup-partial`) for idempotency.
- **Backup path**: UpdraftPlus writes to `/var/backups/websitebox` (mapped to `./websitebox-data/backups/`), deliberately outside `/var/www/html` to avoid nested bind mount conflicts.
- **XML-RPC disable**: In mu-plugin via `add_filter('xmlrpc_enabled', '__return_false')`, NOT in wp-config.php (plugin API not loaded at wp-config time).
- **WP-CLI**: Bundled in WordPress Docker image. Run commands as `www-data`, never use `--allow-root`.
- **Table prefix**: `wbox_` (not default `wp_`).
- **wp-config**: Sets `DISALLOW_FILE_EDIT` (blocks theme/plugin editor) but NOT `DISALLOW_FILE_MODS` (would prevent plugin/theme updates via admin GUI).
## User Flow
1. `curl -fsSL <url>/install.sh | bash` — installs Docker, clones repo, runs setup wizard
2. `setup.sh` — interactive wizard, generates `.env`, creates `websitebox-data/` structure
3. User configures DNS A record
4. `docker compose up -d` — everything self-configures
## File Structure Conventions
- `nginx/entrypoint.sh` — SSL auto-bootstrap logic
- `wordpress/entrypoint.sh` — First-boot WP-CLI setup (theme/plugin install, site config)
- `wordpress/wp-content/mu-plugins/websitebox-setup.php` — Lightweight status checker + XML-RPC disable (not the installer)
- `wordpress/wp-content/themes/websitebox/` — Child theme (parent: GeneratePress)
- `scripts/``backup.sh`, `update.sh`, `ssl-renew.sh`, `healthcheck.sh`
- `.env` / `.env.example` — Configuration (gitignored / template)
## Commands
```bash
# Start the stack
docker compose up -d
# Rebuild after Dockerfile changes
docker compose up -d --build
# View logs
docker compose logs -f [service]
# Restart a specific service
docker compose restart wordpress
# Re-run first-boot setup (force clean)
docker compose exec wordpress rm /var/www/html/.websitebox-setup-complete /var/www/html/.websitebox-setup-partial
docker compose restart wordpress
# Update WebsiteBox
./scripts/update.sh
# Manual backup
./scripts/backup.sh
```
## Healthchecks
| Service | Check | Retries |
|---------|-------|---------|
| nginx | `curl -f http://localhost/nginx-health` | 3 |
| wordpress | `php-fpm-healthcheck` | 3 |
| db | `healthcheck --su-mysql --connect --innodb_initialized` | 5 |
WordPress depends on db with `condition: service_healthy`.
## Error Handling Patterns
- WordPress entrypoint: MariaDB retry loop (30 attempts, 2s apart). On partial failure, creates `.websitebox-setup-partial` marker and starts PHP-FPM anyway. All WP-CLI commands are idempotent — safe to re-run entire sequence.
- nginx entrypoint: On SSL failure, serves HTTP placeholder explaining DNS isn't ready. User retries with `docker compose restart nginx`.
- install.sh: Uses `sg docker` for immediate Docker group activation without logout/login.
## Non-Goals (v1)
Payment processing, multi-site WordPress, automatic VPS provisioning, built-in CDN, email server (SMTP relay config only).