Private
Public Access
1
0
Files
websitebox/CLAUDE.md
constantprojects 0bef817f7b Add license key gate, migrate marketing site to separate repo
- install.sh: prompt for license key as first step, validate against
  makeyourown.website/api/validate before any system changes
- setup.sh: secondary key check (format-only if .license-key exists,
  server validation if missing)
- Remove website/ directory — marketing site, keyserver, and deploy
  scripts migrated to the websites repo (git.constantprojects.xyz/
  tankadmin/websites.git) for independent deployment
- Update CLAUDE.md, guide.md, .gitignore to reflect migration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 12:50:24 -07:00

7.2 KiB

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.
  • Keep guide.md in sync. Any change that alters the user-facing flow — new commands, renamed scripts, changed setup wizard prompts, added/removed steps, new dependencies, modified ports, updated troubleshooting — must also be reflected in guide.md. This is a beginner-facing deployment guide in ProjectPublic markup format. If you're unsure whether a change affects the guide, check. Treat guide.md as a living document that must always match the actual codebase.

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

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

Marketing Site & License Keys (separate repo)

The marketing site (makeyourown.website) and license key validation server live in a separate repository: https://git.constantprojects.xyz/tankadmin/websites.git (local: ~/claude/projects/websites). This is business infrastructure that runs on its own VPS, independent of any WebsiteBox test/product deployments.

License key validation (client-side)

  • install.sh prompts for a license key as the very first step (before any system changes)
  • setup.sh has a secondary check (format-only if .license-key file exists, server validation if missing)
  • Endpoint: POST https://makeyourown.website/api/validate with body key=WBOX-XXXX-XXXX-XXXX-XXXX
  • Key format: WBOX-XXXX-XXXX-XXXX-XXXX (uppercase alphanumeric, no ambiguous chars 0/O/1/I/L)
  • Behavior: Burn-on-use — keys are consumed on first activation
  • Storage: .license-key file in project root (gitignored, chmod 600)

What lives where

Concern Location
Key check in install flow This repo: install.sh, setup.sh
Keyserver, key generation, marketing site websites repo: services/keyserver/, scripts/generate-keys.sh, sites/makeyourown.website/
Key storage (keys.txt) websites VPS: services/keyserver/keys.txt

Business rules

  • WebsiteBox is not free and not "open source" — code is auditable, buyers can read every line before purchasing
  • Do not say "free" or "open source" in marketing content
  • Pricing tiers: Standard $49 one-time, Lifetime Updates $149 one-time, Managed $25/month (all placeholder amounts)

Non-Goals (v1)

Payment processing, multi-site WordPress, automatic VPS provisioning, built-in CDN, email server (SMTP relay config only).