# Ladill Hosting — deploy & cutover runbook Standalone app for **shared web hosting** at `hosting.ladill.com` (single-domain, multi-domain, WordPress). **VPS and dedicated servers** are a separate product — **Ladill Servers** at `servers.ladill.com` (not part of this app). It trusts `auth.ladill.com` for login (OIDC) and bills the one platform UserWallet over the §4-A Billing API. Provisioning runs against Contabo nodes and the shared hosting infrastructure (same stack as the monolith phase). Mirrors the Ladill Domains / Email deployment model (app-slot + own DB + Gitea CI). --- ## 0. Prerequisites | Secret | Where it comes from | |---|---| | `CONTABO_CLIENT_ID` / `CONTABO_CLIENT_SECRET` / `CONTABO_API_USER` / `CONTABO_API_PASSWORD` | Contabo API credentials | | `PDNS_API_URL` / `PDNS_API_KEY` | PowerDNS (zone management) | | `PAYSTACK_SECRET_KEY` / `PAYSTACK_PUBLIC_KEY` | Paystack dashboard | | `LADILL_SSO_CLIENT_ID` / `LADILL_SSO_CLIENT_SECRET` | step 3 | | `BILLING_API_KEY_HOSTING` | step 4 (must match platform env) | | `IDENTITY_API_KEY_HOSTING` | step 4 (must match platform env) | --- ## 1. Gitea repo + CI 1. Create repo `isaacclad/ladill-hosting` in Gitea. 2. Push this repo (`git remote add origin … && git push -u origin main`). 3. Ensure an instance-level Actions runner exists (shared with Bird/Domains/Email). 4. CI secrets (`.gitea/workflows/deploy.yml`): `SSH_HOST`, `SSH_PORT`, `SSH_USER`, `APP_ROOT` = `/var/www/ladill-hosting`, deploy SSH key. ## 2. Server app-slot + database ```bash sudo install -d -o deploy -g www-data /var/www/ladill-hosting sudo mysql -e "CREATE DATABASE ladill_hosting CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" sudo mysql -e "CREATE USER 'ladill_hosting'@'127.0.0.1' IDENTIFIED BY '';" sudo mysql -e "GRANT ALL ON ladill_hosting.* TO 'ladill_hosting'@'127.0.0.1'; FLUSH PRIVILEGES;" ``` Create `/var/www/ladill-hosting/.env` from `.env.example`, fill secrets, then `php artisan key:generate`. ## 3. Register the OIDC client (platform / auth.ladill.com) ```bash # On the monolith php artisan passport:client \ --name="Ladill Hosting" \ --redirect_uri="https://hosting.ladill.com/sso/callback" ``` Set `LADILL_SSO_CLIENT_ID` / `LADILL_SSO_CLIENT_SECRET` in this app's `.env`. ## 4. Platform integration On the **platform** `.env`: ```env BILLING_API_KEY_HOSTING= IDENTITY_API_KEY_HOSTING= RP_HOSTING_FRONTCHANNEL_LOGOUT=https://hosting.ladill.com/sso/logout-frontchannel LADILL_HOSTING_APP_URL=https://hosting.ladill.com ``` Then `php artisan config:cache` on the platform. ## 5. nginx + TLS ```bash sudo deployment/setup-service-subdomain-nginx.sh hosting --app ladill-hosting ``` DNS `hosting.ladill.com` is already in `config/pdns.php` → `dns:sync-subdomains` on deploy. ## 6. First deploy Push to `main` (CI) or run deploy manually, then: ```bash cd /var/www/ladill-hosting/current php artisan migrate --force php artisan db:seed --class=HostingProductSeeder --force php artisan config:cache route:cache view:cache chgrp -R www-data storage bootstrap/cache && chmod -R g+rwX storage bootstrap/cache ``` Ensure a queue worker runs (`queue:work` via supervisor). ## 7. Zero-loss migration ```bash # a) On the platform — export customer hosting rows php artisan hosting:export --out=/tmp/hosting-export.json # b) Copy to the hosting app server, dry-run import php artisan hosting:import /tmp/hosting-export.json # c) Apply php artisan hosting:import /tmp/hosting-export.json --commit ``` Re-running import is idempotent (upserts by original platform id). ## 8. Smoke test - `https://hosting.ladill.com/up` → 200 - Logged-out → SSO redirect to auth.ladill.com - Logged-in → dashboard lists imported accounts - Open an account → panel loads (files, domains, SSL) - Buy a test shared hosting plan end-to-end (wallet) - Log out → SLO clears hosting session ## 9. Decommission platform hosting UI (after burn-in) Account sidebar + `/hosting/*` on account.ladill.com already redirect to `hosting.ladill.com`. After burn-in, remove remaining platform hosting models/jobs once the hosting app is the sole writer.