|
| 1 | +# Project Wharf |
| 2 | + |
| 3 | +**The Sovereign Web Hypervisor** - Immutable CMS infrastructure for WordPress and beyond. |
| 4 | + |
| 5 | +## What is Wharf? |
| 6 | + |
| 7 | +Wharf separates CMS **administration** (offline, secure) from **runtime** (online, hardened). Think of it like a ship: |
| 8 | + |
| 9 | +- **Wharf** = The dock where you build and maintain your ship (your local machine) |
| 10 | +- **Yacht** = The ship at sea serving visitors (your production server) |
| 11 | +- **Mooring** = The secure channel connecting them (rsync over SSH + Nebula mesh) |
| 12 | + |
| 13 | +### Why? |
| 14 | + |
| 15 | +Traditional WordPress hosting is vulnerable because: |
| 16 | +- `/wp-admin` is exposed to the internet |
| 17 | +- Plugins can be installed/modified live |
| 18 | +- Database can be corrupted by attackers |
| 19 | +- No separation between admin and runtime |
| 20 | + |
| 21 | +Wharf fixes this by making the runtime **read-only** and moving all administration offline. |
| 22 | + |
| 23 | +## Architecture |
| 24 | + |
| 25 | +``` |
| 26 | +┌─────────────────────────────────────────────────────────────┐ |
| 27 | +│ YOUR MACHINE (Wharf) │ |
| 28 | +│ │ |
| 29 | +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ |
| 30 | +│ │ WordPress │ │ wharf-cli │ │ Fleet Config │ │ |
| 31 | +│ │ (editable) │ │ │ │ (TOML/JSON) │ │ |
| 32 | +│ └──────────────┘ └──────────────┘ └──────────────────┘ │ |
| 33 | +│ │ │ |
| 34 | +│ `wharf moor` │ |
| 35 | +│ (SSH + rsync) │ |
| 36 | +└────────────────────────────┼────────────────────────────────┘ |
| 37 | + │ |
| 38 | + ┌───────▼───────┐ |
| 39 | + │ Nebula Mesh │ |
| 40 | + │ (Zero Trust) │ |
| 41 | + └───────┬───────┘ |
| 42 | + │ |
| 43 | +┌────────────────────────────┼────────────────────────────────┐ |
| 44 | +│ PRODUCTION SERVER (Yacht) │ |
| 45 | +│ │ |
| 46 | +│ ┌──────────────────────────────────────────────────────┐ │ |
| 47 | +│ │ Yacht Pod │ │ |
| 48 | +│ │ ┌─────────────────┐ ┌─────────────────────┐ │ │ |
| 49 | +│ │ │ OpenLiteSpeed │ │ Yacht Agent │ │ │ |
| 50 | +│ │ │ + PHP 8.3 │ │ (Distroless Rust) │ │ │ |
| 51 | +│ │ │ │ │ │ │ │ |
| 52 | +│ │ │ - /wp-admin │────▶│ - DB Proxy (AST) │ │ │ |
| 53 | +│ │ │ BLOCKED │ │ - Integrity Check │ │ │ |
| 54 | +│ │ │ - Read-only FS │ │ - nftables/eBPF │ │ │ |
| 55 | +│ │ └─────────────────┘ └─────────────────────┘ │ │ |
| 56 | +│ └──────────────────────────────────────────────────────┘ │ |
| 57 | +│ │ |
| 58 | +│ ┌──────────────────────────────────────────────────────┐ │ |
| 59 | +│ │ MariaDB (Shadow Port 33060) │ │ |
| 60 | +│ └──────────────────────────────────────────────────────┘ │ |
| 61 | +└─────────────────────────────────────────────────────────────┘ |
| 62 | +``` |
| 63 | + |
| 64 | +## Quick Start |
| 65 | + |
| 66 | +### Prerequisites |
| 67 | + |
| 68 | +- Rust 1.75+ (`curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`) |
| 69 | +- Podman (`apt install podman` or equivalent) |
| 70 | +- rsync and SSH client |
| 71 | + |
| 72 | +### 1. Build Wharf CLI |
| 73 | + |
| 74 | +```bash |
| 75 | +git clone https://gitlab.com/hyperpolymath/wharf.git |
| 76 | +cd wharf |
| 77 | +cargo build --release --bin wharf |
| 78 | +``` |
| 79 | + |
| 80 | +### 2. Initialize Your Fleet |
| 81 | + |
| 82 | +```bash |
| 83 | +# Create a new fleet configuration |
| 84 | +./target/release/wharf init --path ./my-fleet |
| 85 | + |
| 86 | +# Edit the configuration |
| 87 | +nano ./my-fleet/fleet.toml |
| 88 | +``` |
| 89 | + |
| 90 | +### 3. Add a Yacht |
| 91 | + |
| 92 | +Edit `fleet.toml`: |
| 93 | + |
| 94 | +```toml |
| 95 | +[yachts.production] |
| 96 | +name = "production" |
| 97 | +ip = "your-server-ip" |
| 98 | +domain = "example.com" |
| 99 | +ssh_user = "deploy" |
| 100 | +adapter = "wordpress" |
| 101 | +``` |
| 102 | + |
| 103 | +### 4. Prepare Your WordPress Site |
| 104 | + |
| 105 | +Place your WordPress files in `./my-fleet/site/`: |
| 106 | + |
| 107 | +```bash |
| 108 | +# Copy existing WordPress |
| 109 | +cp -r /path/to/wordpress/* ./my-fleet/site/ |
| 110 | + |
| 111 | +# Or download fresh |
| 112 | +wget https://wordpress.org/latest.tar.gz |
| 113 | +tar -xzf latest.tar.gz |
| 114 | +mv wordpress/* ./my-fleet/site/ |
| 115 | +``` |
| 116 | + |
| 117 | +### 5. Deploy (Moor) to Production |
| 118 | + |
| 119 | +```bash |
| 120 | +./target/release/wharf moor production |
| 121 | +``` |
| 122 | + |
| 123 | +This will: |
| 124 | +1. Generate a BLAKE3 integrity manifest |
| 125 | +2. Sync files via rsync over SSH |
| 126 | +3. Verify the deployment |
| 127 | + |
| 128 | +### 6. Build and Deploy Containers (on the Yacht) |
| 129 | + |
| 130 | +On your production server: |
| 131 | + |
| 132 | +```bash |
| 133 | +# Build containers |
| 134 | +podman build -t yacht-web:latest -f infra/containers/openlitespeed.Dockerfile . |
| 135 | +podman build -t yacht-agent:latest -f infra/containers/agent.Dockerfile . |
| 136 | + |
| 137 | +# Deploy the pod |
| 138 | +podman kube play infra/podman/yacht.yaml |
| 139 | +``` |
| 140 | + |
| 141 | +## Configuration |
| 142 | + |
| 143 | +### Fleet Configuration (TOML) |
| 144 | + |
| 145 | +```toml |
| 146 | +# configs/fleet.toml |
| 147 | + |
| 148 | +version = 1 |
| 149 | +name = "my-fleet" |
| 150 | + |
| 151 | +sync_excludes = [ |
| 152 | + ".git", |
| 153 | + "node_modules", |
| 154 | + ".env", |
| 155 | + "*.log", |
| 156 | +] |
| 157 | + |
| 158 | +[yachts.production] |
| 159 | +name = "production" |
| 160 | +ip = "10.0.1.10" |
| 161 | +domain = "example.com" |
| 162 | +ssh_port = 22 |
| 163 | +ssh_user = "deploy" |
| 164 | +adapter = "wordpress" |
| 165 | +enabled = true |
| 166 | + |
| 167 | +[yachts.production.database] |
| 168 | +variant = "mariadb" |
| 169 | +shadow_port = 33060 |
| 170 | +public_port = 3306 |
| 171 | +``` |
| 172 | + |
| 173 | +### Database Policy (Nickel) |
| 174 | + |
| 175 | +The database proxy uses AST-based SQL parsing to enforce security policies: |
| 176 | + |
| 177 | +```nickel |
| 178 | +# configs/policies/database.ncl |
| 179 | +{ |
| 180 | + default_policy = "audit", |
| 181 | +
|
| 182 | + # Content tables - can be written by the website |
| 183 | + allow_write = [ |
| 184 | + "wp_comments", |
| 185 | + "wp_commentmeta", |
| 186 | + ], |
| 187 | +
|
| 188 | + # Config tables - can ONLY be changed via Wharf |
| 189 | + lock_down = [ |
| 190 | + "wp_users", |
| 191 | + "wp_options", |
| 192 | + ], |
| 193 | +
|
| 194 | + # Structural operations are always blocked |
| 195 | + blocked_operations = ["DROP", "ALTER", "TRUNCATE", "CREATE"], |
| 196 | +} |
| 197 | +``` |
| 198 | + |
| 199 | +## Security Model |
| 200 | + |
| 201 | +### The "Dark Matter" Concept |
| 202 | + |
| 203 | +`/wp-admin` exists on disk but is **blocked at the web server level**. It's there (so WordPress works), but attackers can't reach it. Administration happens offline on your Wharf machine. |
| 204 | + |
| 205 | +### Database Virtual Sharding |
| 206 | + |
| 207 | +The Yacht Agent proxies all database connections and: |
| 208 | + |
| 209 | +1. **Parses SQL using AST** (not regex - can't be bypassed) |
| 210 | +2. **Classifies queries** as Allow, Audit, or Block |
| 211 | +3. **Blocks dangerous operations** (DROP, ALTER, etc.) |
| 212 | +4. **Logs everything** for forensics |
| 213 | + |
| 214 | +### Integrity Verification |
| 215 | + |
| 216 | +Every deployment generates a BLAKE3 manifest of all files. The agent continuously verifies the filesystem hasn't been tampered with. |
| 217 | + |
| 218 | +### Firewall Options |
| 219 | + |
| 220 | +| Mode | Description | Requirements | |
| 221 | +|------|-------------|--------------| |
| 222 | +| `nftables` | Standard Linux firewall (default) | Linux kernel 3.13+ | |
| 223 | +| `ebpf` | XDP packet filtering at NIC level | Linux kernel 5.2+, CAP_BPF | |
| 224 | +| `none` | No firewall (not recommended) | - | |
| 225 | + |
| 226 | +## CLI Reference |
| 227 | + |
| 228 | +```bash |
| 229 | +wharf init # Initialize fleet configuration |
| 230 | +wharf build # Compile zone files and artifacts |
| 231 | +wharf moor <yacht> # Deploy to a yacht |
| 232 | +wharf moor <yacht> --dry-run # Preview what would be synced |
| 233 | + |
| 234 | +wharf fleet list # List all yachts |
| 235 | +wharf fleet add <name> # Add a yacht |
| 236 | +wharf fleet status # Show fleet status |
| 237 | + |
| 238 | +wharf sec verify <yacht> # Verify file integrity |
| 239 | +wharf sec audit # Security audit |
| 240 | + |
| 241 | +wharf state freeze # Create a snapshot |
| 242 | +wharf state thaw <id> # Restore a snapshot |
| 243 | +wharf state diff <yacht> # Compare local vs remote |
| 244 | +``` |
| 245 | + |
| 246 | +## SSL/TLS Certificates |
| 247 | + |
| 248 | +```bash |
| 249 | +# Set your email for Let's Encrypt |
| 250 | +export WHARF_ACME_EMAIL=admin@example.com |
| 251 | + |
| 252 | +# Initialize certificate |
| 253 | +./scripts/ssl-setup.sh init example.com |
| 254 | + |
| 255 | +# Check status |
| 256 | +./scripts/ssl-setup.sh status |
| 257 | + |
| 258 | +# Auto-renewal |
| 259 | +./scripts/ssl-setup.sh auto-renew |
| 260 | +``` |
| 261 | + |
| 262 | +## Monitoring |
| 263 | + |
| 264 | +The Yacht Agent exposes Prometheus metrics at `/metrics`: |
| 265 | + |
| 266 | +``` |
| 267 | +yacht_queries_total{status="allowed"} 1234 |
| 268 | +yacht_queries_total{status="blocked"} 5 |
| 269 | +yacht_integrity_status 1 |
| 270 | +yacht_db_proxy_connections 3 |
| 271 | +``` |
| 272 | + |
| 273 | +## Supported CMS |
| 274 | + |
| 275 | +| CMS | Adapter | Status | |
| 276 | +|-----|---------|--------| |
| 277 | +| WordPress | `wordpress` | Primary support | |
| 278 | +| Drupal | `drupal` | Adapter exists | |
| 279 | +| Moodle | `moodle` | Adapter exists | |
| 280 | +| Joomla | `joomla` | Adapter exists | |
| 281 | +| Custom | `custom` | Manual config | |
| 282 | + |
| 283 | +## Container Images |
| 284 | + |
| 285 | +| Image | Base | Purpose | |
| 286 | +|-------|------|---------| |
| 287 | +| `yacht-web` | OpenLiteSpeed | Web server + PHP 8.3 | |
| 288 | +| `yacht-agent` | Chainguard static (distroless) | Security enforcer | |
| 289 | +| `mariadb` | Chainguard MariaDB | Database | |
| 290 | + |
| 291 | +## Development |
| 292 | + |
| 293 | +```bash |
| 294 | +# Run tests |
| 295 | +cargo test |
| 296 | + |
| 297 | +# Build all binaries |
| 298 | +cargo build --release |
| 299 | + |
| 300 | +# Build containers |
| 301 | +podman build -t yacht-web:latest -f infra/containers/openlitespeed.Dockerfile . |
| 302 | +podman build -t yacht-agent:latest -f infra/containers/agent.Dockerfile . |
| 303 | + |
| 304 | +# Run smoke test |
| 305 | +./scripts/smoke_test.sh |
| 306 | +``` |
| 307 | + |
| 308 | +## License |
| 309 | + |
| 310 | +MIT License - See [LICENSE](LICENSE) for details. |
| 311 | + |
| 312 | +## Contributing |
| 313 | + |
| 314 | +Contributions welcome! Please read the architecture docs before submitting PRs. |
| 315 | + |
| 316 | +## Support |
| 317 | + |
| 318 | +- Issues: https://gitlab.com/hyperpolymath/wharf/-/issues |
| 319 | +- Discussions: https://gitlab.com/hyperpolymath/wharf/-/discussions |
| 320 | + |
| 321 | +--- |
| 322 | + |
| 323 | +**Wharf** - Because your CMS deserves sovereign security. |
0 commit comments