Wiki: Cloudflare WAF discovery, CI/CD docs, architecture, getting started

2026-07-03 09:00:59 +02:00
parent c5f4dd8752
commit 6f0a5e194e
5 changed files with 484 additions and 0 deletions
+154
@@ -0,0 +1,154 @@
# Architecture Overview
## System Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ Developer Workflow │
│ git push → Gitea (git.falahos.my) → Actions Runner │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Gitea Actions (Docker Swarm) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ CI │ │ Deploy │ │ Sync │ │ Health │ │
│ │ lint + │ │ git push │ │ cPanel + │ │ every │ │
│ │ security │ │ + WP API │ │ Nextcloud│ │ 30min │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────┴──────────────┐
▼ ▼
┌──────────────────────┐ ┌──────────────────────────┐
│ cPanel (Hosting) │ │ Contabo (Docker Host) │
│ │ │ │
│ WordPress Site │ │ Gitea (git.falahos.my) │
│ ummah.falahos.my │ │ Nextcloud │
│ │ │ team.falahos.my │
│ Hermes Plugin: │ │ │
│ ┌───────────────┐ │ │ Gitea Actions Runner │
│ │ REST API │ │ │ (Docker Swarm service) │
│ │ hermes/v1/* │ │ │ │
│ ├───────────────┤ │ │ OpenClaw AI API │
│ │ WP-Cron │ │ │ (via Mac Mini) │
│ │ Agent Sched. │ │ │ │
│ ├───────────────┤ │ └──────────────────────────┘
│ │ AI Provider │ │
│ │ (OpenClaw) │ │
│ ├───────────────┤ │
│ │ Nextcloud │ │
│ │ Bridge │ │
│ └───────────────┘ │
│ │
│ cPanel Git: │
│ auto-pull from │
│ Gitea on push │
└──────────────────────┘
```
## Data Flow: Content Generation (Ody Clone)
```
User/REST Client
POST https://ummah.falahos.my/wp-json/hermes/v1/content/generate
WordPress: rest_ensure_response() → HermesAiBridge\RestController
├──→ Validate Application Password (HTTP Basic Auth)
├──→ Parse request: prompt, tone, length
HermesAiBridge\AiProvider
├──→ Call OpenClaw API (on Mac Mini or LLM provider)
├──→ Handle response / error
Return generated content as JSON
WP-Cron (async) → HermesAiBridge\Scheduler
├──→ Post to WordPress as draft
├──→ Sync to Nextcloud
└──→ Log to database
```
## Data Flow: Auto-Reply (PI Clone — Planned)
```
bbPress Forum Topic / Comment
WordPress hook → HermesAiBridge\PiController
├──→ Analyze topic content
├──→ Generate reply via AI Provider
Post reply as specified user
Notify thread participants (email/WhatsApp)
```
## Authentication Flow
```
HTTP Request
Cloudflare → ummah.falahos.my
│ (No WAF block — passes through)
WordPress → Check Authorization header
├── Has "Basic base64(user:app_password)"?
│ └── Yes → WordPress validates Application Password
│ └── Valid → Process request
│ └── Invalid → HTTP 401
└── No HTTP Basic Auth?
└── REST API returns HTTP 401
```
**Key insight:** Application Passwords authenticate at the WordPress application layer, not at the network layer. This means:
- Cloudflare WAF is transparent to them
- No special IP whitelisting needed
- Works from any IP, any network
## Plugin Components
### REST Controller (`rest-controller.php`)
- Registers `hermes/v1` namespace
- Routes: `content/generate`, `nextcloud/sync`, `settings`
- Authentication via `is_user_logged_in()` or Application Password
### AI Provider (`ai-provider.php`)
- Connects to OpenClaw API
- Handles prompt formatting, response parsing
- Fallback: Curl-based HTTP client (no cURL extension needed)
### Scheduler (`scheduler.php`)
- WP-Cron hooks for periodic tasks
- Content generation schedules
- Health check tasks
### Nextcloud Bridge (`nextcloud-bridge.php`)
- WebDAV sync to `team.falahos.my`
- Uploads published content
- Syncs agent artifacts
## Environment
| Component | URL | Hosting | Purpose |
|-----------|-----|---------|---------|
| WordPress | ummah.falahos.my | cPanel (RoketServer) | Agent runtime |
| Gitea | git.falahos.my | Contabo Docker | Source + CI/CD |
| Nextcloud | team.falahos.my | Contabo Docker | Team hub |
| Gitea Runner | — | Contabo Docker | CI/CD execution |
| OpenClaw | 100.72.2.115:4747 | Mac Mini | AI inference |
+90
@@ -0,0 +1,90 @@
# Cloudflare WAF Bypass Discovery 🎯
## The Breakthrough Finding
We discovered that **Cloudflare WAF was NOT blocking the Contabo IP from the WordPress REST API**. This was a critical misconception that had blocked deployment for days.
### What Actually Happened
We assumed Cloudflare's WAF was blocking `172.17.0.1` (our Contabo Docker host) from reaching `ummah.falahos.my/wp-json/`. This assumption was wrong.
**Evidence:**
```
$ curl -s -w "HTTP %{http_code}" "https://ummah.falahos.my/wp-json/wp/v2/users"
HTTP 200
$ curl -s -w "HTTP %{http_code}" "https://ummah.falahos.my/wp-json/wp/v2/plugins"
HTTP 401
```
The WP REST API was fully reachable — it just returned:
- **HTTP 200** for public endpoints (users, index, etc.)
- **HTTP 401** for protected endpoints (plugins, etc.) — **not a WAF block!**
### Why We Thought It Was Blocked
Earlier testing used `/wp-json/hermes/v1/content/generate` which returned HTTP 404 (plugin not installed yet, not blocked). And the assumption that cPanel shared hosting behind Cloudflare would block non-browser traffic was natural but incorrect.
### The Real Blocker
The actual blocker was **authentication**, not Cloudflare:
```
WP REST API needs → Application Password (HTTP Basic Auth)
→ OR Cookie + Nonce (browser-based auth)
```
Cloudflare WAF was never the issue — we just needed a WordPress Application Password.
## Solution: Application Passwords
WordPress Application Passwords provide **app-layer authentication** via HTTP Basic Auth:
```bash
curl -u "username:application_password" \
"https://ummah.falahos.my/wp-json/wp/v2/plugins"
```
This bypasses any WAF because the auth happens at the application layer inside WordPress, not at the network level.
### How to Create
**Via REST API (if already logged in):**
```bash
# 1. Log in with cookie auth
curl -c cookies.txt \
-d "log=wmj&pwd=PASSWORD&wp-submit=Log+In" \
"https://ummah.falahos.my/wp-login.php"
# 2. Extract nonce from admin page
NONCE=$(curl -b cookies.txt \
"https://ummah.falahos.my/wp-admin/profile.php" \
| grep -oP '"nonce":"[^"]*"' | head -1 | cut -d'"' -f4)
# 3. Create Application Password
curl -b cookies.txt \
-H "X-WP-Nonce: $NONCE" \
-H "Content-Type: application/json" \
-d '{"name":"my-agent"}' \
"https://ummah.falahos.my/wp-json/wp/v2/users/me/application-passwords"
```
**Via Admin UI:**
1. Log in to `https://ummah.falahos.my/wp-admin`
2. Go to Users → Profile
3. Scroll to "Application Passwords" section
4. Enter a name and click "Add New"
5. Copy the generated password
## Key Takeaway
**Always verify assumptions about network-level blocking** before engineering complex workarounds. Test with `curl -w "HTTP %{http_code}"` first to distinguish between:
- HTTP 403/503 → WAF or server block
- HTTP 401 → Authentication needed (WordPress is responding!)
- HTTP 404 → Endpoint not found (plugin not installed)
## Related
- WordPress Application Passwords plugin is already installed on ummah.falahos.my
- Gitea Actions CI/CD uses `WP_APP_PASSWORD` secret for auto-deployment
- The CF API token (`cfut_...`) has DNS:Edit + Zone:Read scopes but NOT WAF management
+78
@@ -0,0 +1,78 @@
# Getting Started
This guide covers everything you need to develop and deploy the Hermes cPanel Agent.
## Prerequisites
- Gitea account with push access to `wmj/hermes-cpanel-agent`
- WordPress admin access to `ummah.falahos.my`
- (For CI/CD) cPanel Git SSH key
## Development Setup
```bash
# Clone the repo
git clone https://git.falahos.my/wmj/hermes-cpanel-agent.git
cd hermes-cpanel-agent
# All PHP files — no build step needed
# Install WordPress locally for testing, or use the staging site
```
## Plugin Structure
```
hermes-cpanel-agent/
├── hermes-ai-bridge.php # Main plugin (WordPress header)
├── includes/
│ ├── class-autoloader.php # PSR-4 autoloader
│ ├── core.php # Bootstrap + hooks
│ ├── installer.php # Activation/deactivation
│ ├── rest-controller.php # REST API: hermes/v1/*
│ ├── ai-provider.php # OpenClaw AI integration
│ ├── scheduler.php # WP-Cron tasks
│ └── nextcloud-bridge.php # Nextcloud sync
├── assets/
│ └── admin.css
└── .gitea/
├── workflows/ # CI/CD pipelines
└── scripts/ # Helper scripts
```
## Security Rules
NEVER use these in plugin code (cPanel blocks them anyway):
```php
exec(), shell_exec(), system(), passthru(),
popen(), proc_open(), eval(), assert()
```
## Making Changes
1. Branch from `main`
2. Make changes
3. Push and open PR
4. CI runs: PHP lint, security scan, schema validation
5. Merge → auto-deploys via Gitea Actions
## API Key Setup
The plugin needs an OpenClaw API key configured via WP Admin:
1. Go to Settings → Hermes AI Bridge
2. Enter OpenClaw API key
3. Save
Or via REST API:
```bash
curl -X PATCH -u "wmj:APP_PASSWORD" \
-H "Content-Type: application/json" \
-d '{"openclaw_api_key":"..."}' \
"https://ummah.falahos.my/wp-json/hermes/v1/settings"
```
## Troubleshooting
- **HTTP 401**: Need valid Application Password
- **HTTP 403 Nonce**: Cookie session expired — re-login
- **HTTP 404**: Endpoint not deployed — check plugin is active
- **Plugin not found**: Check `/wp-admin/plugins.php` — manually activate
+140
@@ -0,0 +1,140 @@
# Gitea Actions CI/CD
Full CI/CD pipeline documentation for the Hermes cPanel Agent.
## Runner
A Gitea Actions runner is deployed as a Docker Swarm service on Contabo:
| Detail | Value |
|--------|-------|
| Name | `contabo-swarm-runner` |
| Host | Docker Swarm leader (`vmi3361598`) |
| Image | `gitea/act_runner:v0.6.1` |
| Network | `gitea_gitea-net` |
| Labels | `ubuntu-latest`, `self-hosted` |
### Runner Setup
```bash
# Get registration token from Gitea CLI
docker exec -u git gitea_gitea.1.xxx gitea actions generate-runner-token
# Deploy as Swarm service
docker service create \
--name gitea-runner \
--network gitea_gitea-net \
--restart-condition any \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--env GITEA_INSTANCE_URL=https://git.falahos.my \
--env GITEA_RUNNER_REGISTRATION_TOKEN=TOKEN \
--env GITEA_RUNNER_NAME=contabo-swarm-runner \
gitea/act_runner:latest
```
## Workflows
### 1. CI (`ci.yml`)
**Trigger:** Push to main/develop, PRs
```
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ PHP Syntax │ → │ Security │ → │ Schema │
│ Check │ │ Scan │ │ Validation │
└─────────────┘ └──────────────┘ └─────────────┘
```
- `php -l` on all PHP files
- Greps for banned functions (`exec`, `shell_exec`, `system`, `eval`)
- Validates WordPress plugin headers
- Verifies REST namespace declaration
### 2. Deploy (`deploy.yml`)
**Trigger:** Push to main
```
┌──────────┐ ┌─────────────────┐ ┌──────────────┐
│ CI Check │ → │ Git Push to │ → │ WP REST API │
│ (pass) │ │ cPanel Remote │ │ Fallback │
└──────────┘ └─────────────────┘ └──────────────┘
┌──────────────┐
│ Verify │
│ Deployment │
└──────────────┘
```
**Primary path:** SSH into cPanel Git remote, force-push main branch.
**Fallback:** Build plugin zip and upload via WP REST API `/wp/v2/plugins`.
**Verification:** Check plugin is active + `hermes/v1` namespace is registered.
### 3. Sync (`sync.yml`)
**Trigger:** Push to main + every 6 hours
- Syncs code to cPanel git
- Uploads plugin zip to Nextcloud artifacts folder
### 4. Health (`health.yml`)
**Trigger:** Every 30 minutes
- Checks plugin is active on WordPress
- Verifies REST API responds
- Alerts on failure via Gitea notifications
## Secrets
Set these in **Settings → Actions → Secrets**:
| Secret | Purpose | Required |
|--------|---------|----------|
| `WP_URL` | WordPress site URL | ✅ Set |
| `WP_APP_USER` | WordPress username | ✅ Set |
| `WP_APP_PASSWORD` | Application Password | ❌ Pending |
| `CPANEL_SSH_KEY` | cPanel deploy SSH key | ❌ Pending |
| `CPANEL_GIT_REMOTE` | cPanel git remote URL | ❌ Pending |
| `CPANEL_HOST` | cPanel SSH hostname | ❌ Pending |
| `CPANEL_DEPLOY_HOOK_URL` | Optional deploy webhook | Optional |
| `NEXTCLOUD_HERMES_PASS` | Nextcloud sync password | ❌ Pending |
### Setting Secrets via API
```bash
curl -X PUT -u "wmj:Abedib%4099" \
-H "Content-Type: application/json" \
-d '{"data":"BASE64_ENCODED_VALUE"}' \
"https://git.falahos.my/api/v1/repos/wmj/hermes-cpanel-agent/actions/secrets/SECRET_NAME"
```
## Architecture
```
Developer Push
Gitea (git.falahos.my)
Gitea Actions Runner (Docker Swarm on Contabo)
├── CI: lint, security, schema
├── Deploy: git push → cPanel OR WP REST API
├── Sync: cPanel sync + Nextcloud
└── Health: every 30min
cPanel Hosting (ummah.falahos.my)
├── cPanel Git Version Control (auto-pull)
├── WordPress + Hermes Plugin
└── WP-Cron agent scheduler
Agents Running:
├── Ody Clone: Content Generator (REST API)
└── PI Clone: Auto-Reply (planned)
```
## Adding a New Workflow
1. Create `.gitea/workflows/your-workflow.yml`
2. Use `runs-on: ubuntu-latest` (handled by our self-hosted runner)
3. Any helper scripts go in `.gitea/scripts/`
4. Push to main — runner picks it up automatically
## Monitoring
- Check runner status: `docker service logs gitea-runner --tail 20`
- View runs: https://git.falahos.my/wmj/hermes-cpanel-agent/actions
- Health checks: every 30 min, reports in Gitea Actions tab
+22
@@ -0,0 +1,22 @@
# Hermes cPanel Agent Wiki
Welcome to the Hermes cPanel Agent wiki — documentation for running AI agent clones (Ody, PI) on cPanel via a WordPress plugin with Gitea Actions CI/CD.
## Pages
- **[Cloudflare WAF Bypass Discovery](Cloudflare-WAF-Bypass-Discovery)** — How we discovered Cloudflare wasn't actually blocking the WP REST API
- **[Getting Started](Getting-Started)** — Setup guide for new developers
- **[Gitea Actions CI/CD](Gitea-Actions-CICD)** — Full CI/CD pipeline documentation
- **[Architecture Overview](Architecture-Overview)** — System architecture and data flow
## Quick Start
1. Get a WordPress Application Password for `wmj` user
2. Set Gitea Actions secrets: `WP_APP_PASSWORD`, `CPANEL_SSH_KEY`, etc.
3. Push to `main` → Gitea Actions auto-deploys to cPanel
4. Verify: `curl -u "wmj:APP_PASS" https://ummah.falahos.my/wp-json/hermes/v1/content/generate`
## Repo
- Code: https://git.falahos.my/wmj/hermes-cpanel-agent
- Issues: https://git.falahos.my/wmj/hermes-cpanel-agent/issues