# HostSeba NOC — cPanel shared-hosting deployment guide

Audience: HostSeba operator deploying the NOC + AI Portal to a single cPanel
account (e.g. `hostsebau` user on `cpanel.hostseba.com`).

Target architecture for Phase 1 (≤20 monitored servers):

```
+---------------------------------------------+
|  cPanel shared hosting (PHP 8.3, MariaDB)   |
|  ┌─────────────────────────────────────┐    |
|  │ /home/hostsebau/noc-app             │    |
|  │   ├ app/  ├ config/  ├ ...          │    |
|  │   └ public/   ← document root       │    |
|  │       ├ noc/   (NOC SPA build)      │    |
|  │       ├ ai/    (AI Portal SPA build)│    |
|  │       └ index.php                   │    |
|  └─────────────────────────────────────┘    |
|  Cron: scheduler every 1 min,                |
|        queue:work every 1 min                |
|  External: Pusher SaaS (broadcasting)        |
+---------------------------------------------+
        ↑                          ↑
   browser (operator)         agent on monitored server
   noc.hostseba.com           curl install.sh | bash
```

---

## 0. Prerequisites checklist

On your cPanel account:

- [ ] PHP 8.3+ available (cPanel → "Select PHP Version" — pick 8.3 or higher)
- [ ] PHP extensions enabled: `openssl`, `pdo_mysql`, `mbstring`, `tokenizer`,
      `xml`, `ctype`, `bcmath`, `fileinfo`, `curl`, `gd` (or `imagick`), `zip`,
      `sodium`
- [ ] SSH access enabled (cPanel → "SSH Access" → "Manage SSH Keys")
- [ ] Composer available on SSH (test: `which composer` — most cPanels have it)
- [ ] MariaDB / MySQL: 1 database + 1 user with ALL PRIVILEGES
- [ ] Cron Jobs panel accessible
- [ ] AutoSSL enabled for the chosen domain/subdomain
- [ ] Pusher SaaS account (free tier OK) — gives realtime updates
- [ ] (Optional) Subdomain set up: e.g. `noc.hostseba.com`

If any of these is missing, fix BEFORE proceeding — debugging from a broken
foundation eats time.

---

## 1. Build the deployable bundle locally

On your dev box (where this repo lives):

```bash
cd noc/frontend
npm install
npm run build                 # builds NOC -> public/noc/, AI -> public/ai/

cd ../backend/hostseba-noc-backend
composer install --no-dev --optimize-autoloader --classmap-authoritative

# Clean caches that shouldn't ship
php artisan optimize:clear
rm -rf storage/logs/*.log storage/framework/cache/data/*
```

Then create the upload bundle (excluding dev clutter):

```bash
cd ..   # parent dir
tar --exclude='hostseba-noc-backend/node_modules' \
    --exclude='hostseba-noc-backend/.git' \
    --exclude='hostseba-noc-backend/tests' \
    --exclude='hostseba-noc-backend/.env' \
    --exclude='hostseba-noc-backend/.env.local' \
    --exclude='hostseba-noc-backend/storage/logs/*.log' \
    --exclude='hostseba-noc-backend/storage/framework/sessions/*' \
    --exclude='hostseba-noc-backend/storage/framework/cache/*' \
    --exclude='hostseba-noc-backend/storage/framework/views/*' \
    --exclude='hostseba-noc-backend/database/database.sqlite' \
    -czf noc-deploy.tgz hostseba-noc-backend
```

Should produce a ~40-80 MB tarball.

---

## 2. Database setup (cPanel UI)

1. cPanel → "MySQL Databases"
2. Create database: `hostsebau_noc`
3. Create user: `hostsebau_nocadm` with strong password
4. Add user to database with ALL PRIVILEGES

Note the exact DB name + user — needed in `.env`.

---

## 3. Domain / subdomain setup

If using a subdomain like `noc.hostseba.com`:

1. cPanel → "Domains" → "Create A New Domain"
2. Domain: `noc.hostseba.com`
3. Document Root: `/home/hostsebau/noc-app/public`
   (NOT `public_html/...` — Laravel-style structure)

If you can't change document root (some restrictive cPanels), see the
"public_html fallback" section at the bottom.

---

## 4. Upload + extract

Via SFTP or cPanel File Manager:

1. Upload `noc-deploy.tgz` to `/home/hostsebau/`
2. SSH in:
   ```bash
   ssh hostsebau@cpanel.hostseba.com
   cd ~
   tar -xzf noc-deploy.tgz
   mv hostseba-noc-backend noc-app
   cd noc-app
   ```

---

## 5. Configure `.env`

```bash
cp .env.production.example .env
nano .env                                  # fill in every "FILL IN" marker
php artisan key:generate                   # writes APP_KEY=
```

Required minimums to fill: `APP_URL`, `DB_*`, `MAIL_PASSWORD`, `PUSHER_*`,
`ANTHROPIC_API_KEY`, `WHMCS_*` (if using), `NOC_WEBHOOK_SECRET`.

---

## 6. Migrate + seed + cache

```bash
php artisan migrate --force                # apply all migrations
php artisan storage:link                   # symlinks public/storage -> ../storage/app/public
php artisan config:cache                   # prod: compile all config into bootstrap/cache/
php artisan route:cache                    # ditto for routes
php artisan view:cache                     # ditto for views
chmod -R 755 storage bootstrap/cache
```

If any of these fails with "permission denied", check ownership:
```bash
chown -R hostsebau:hostsebau ~/noc-app
```

---

## 7. Cron jobs (cPanel → Cron Jobs)

The Laravel scheduler is ONE entry that fans out to every periodic task
defined in `routes/console.php`. The queue worker is a separate entry.

```
# Laravel scheduler — every minute
* * * * * /usr/local/bin/ea-php83 /home/hostsebau/noc-app/artisan schedule:run >> /dev/null 2>&1

# Queue worker — process queued jobs in 55s bursts so cPanel doesn't kill us
* * * * * /usr/local/bin/ea-php83 /home/hostsebau/noc-app/artisan queue:work --stop-when-empty --max-time=55 >> /dev/null 2>&1
```

Find your PHP binary path with `which php` on SSH — `/usr/local/bin/ea-php83`
is the cPanel/EasyApache convention; some shared hosts use
`/opt/cpanel/ea-php83/root/usr/bin/php` or `/usr/bin/php`.

---

## 8. Verify

From your laptop:

```bash
curl -fsSL https://noc.hostseba.com/health
# expected: {"app":"HostSeba NOC","version":"1.0.0","status":"ok"}

curl -fsSL https://noc.hostseba.com/install.sh | head -3
# expected: #!/usr/bin/env bash — and the BACKEND_URL inside should be the noc.hostseba.com URL
```

In browser:

- https://noc.hostseba.com/  → redirects to /noc/ → dashboard loads, login screen
- https://noc.hostseba.com/ai/ → AI Portal SPA
- Login with a seeded admin account

---

## 9. First agent install (from a real shared-hosting box you monitor)

On the target server:

```bash
# Generate a registration token from the dashboard (Servers → "Add Server")
TOKEN="paste-here"

curl -fsSL https://noc.hostseba.com/install.sh | sudo bash -s -- --token "$TOKEN"
```

The installer downloads `agent.sh`, `agent-hosting.sh`, `agent-security.sh`,
writes config to `/etc/hostseba-noc/agent.conf`, registers a systemd unit, and
starts pushing metrics. Within 30s the dashboard should show the new server
as online.

---

## 10. Common cPanel pitfalls

### `php artisan config:cache` fails with "could not find driver"
You're missing a PHP extension. cPanel → "Select PHP Version" → "Extensions"
→ ensure `pdo_mysql` + `mysqli` + `openssl` checked.

### Sessions don't persist across page loads
`SESSION_DOMAIN` mismatch. The cookie is set for `noc.hostseba.com` but your
browser is at `www.noc.hostseba.com`. Either use the canonical hostname in
`APP_URL` OR set `SESSION_DOMAIN=.hostseba.com` (leading dot covers subdomains).

### Long-poll endpoint returns empty `[]` after exactly 30 seconds
LiteSpeed/Apache reverse-proxy timeout. Edit `.env`:
```
AGENT_LONG_POLL_SECONDS=20
```
and `php artisan config:cache`. Default is already 20 in the production
template.

### Agent posts return HTTP 419 (CSRF mismatch)
You're posting to a stateful route. Confirm the agent endpoint is under
`/api/agent/*` (which is excluded from CSRF in `bootstrap/app.php`).

### "public_html fallback" — can't change document root
If your cPanel won't let you point a subdomain at `noc-app/public`:

1. Move contents of `noc-app/public/*` into `~/public_html/` directly
2. Edit `~/public_html/index.php` to point at the right paths:
   ```php
   require __DIR__.'/../noc-app/vendor/autoload.php';
   $app = require_once __DIR__.'/../noc-app/bootstrap/app.php';
   ```
3. Update `noc-app/.env`:
   ```
   APP_URL=https://hostseba.com
   ```
4. Re-run `php artisan storage:link --relative` (relative symlinks survive
   accidental rsync better than absolute)

This works but couples the app structure to the cPanel's file layout — every
upgrade you need to redo the file moves. Recommended only if document-root
change isn't possible.

### Telegram / Slack webhooks not firing
cPanel firewalls sometimes block outbound on non-standard ports. Telegram
uses 443 (fine), but if you bind a Slack webhook to a weird port, test with
`curl` from SSH first.

### Pusher (WebSocket) — frontend gets "Connection lost, retrying..."
Wrong cluster. BD ↔ `ap2` (Mumbai) is the right one. If you accidentally
created the Pusher app in `us2`, latency is fine but our default config
expects ap2 — either match the env var or recreate the Pusher app.

### Composer dies with memory exhaustion
cPanel PHP CLI defaults to 128M; Composer needs ≥512M for `--optimize-autoloader`.
```bash
php -d memory_limit=-1 /usr/local/bin/composer install --no-dev --optimize-autoloader
```

---

## 11. After the first deploy — operational hygiene

- **Storage growth:** `storage/framework/sessions/`, `storage/logs/`, and the
  `audit_logs` MySQL table grow forever. Add to your cron:
  ```
  0 3 * * * find ~/noc-app/storage/logs -name "*.log" -mtime +14 -delete
  ```
- **Database backups:** cPanel "Backup" → schedule weekly full account backup.
  Or `mysqldump` to a private S3 bucket via cron.
- **Migration deploys:** every redeploy:
  ```bash
  php artisan migrate --force
  php artisan config:cache && php artisan route:cache && php artisan view:cache
  ```
- **Zero-downtime upgrades:** clone the running app to `noc-app-next`,
  apply changes, then swap the symlink that the document root points at.
  Not built into this guide — overkill for Phase 1 traffic.

---

## 12. When to outgrow shared hosting

Move to a $5–10/mo VPS the moment any ONE of these happens:

1. Monitored server count > 30 (request rate starts hitting cPanel's req/sec caps)
2. You want to self-host the WebSocket (Soketi / Laravel WebSockets) instead
   of paying Pusher
3. You need Redis for cache/queue speed
4. cPanel "Resource Usage" panel shows your account hitting CPU/IO limits
5. Pusher free-tier connection limit (100) bites — typical for >50 dashboard users

The codebase deploys identically to a VPS — just replace this guide with a
standard `nginx + php-fpm + supervisord` setup. Migration is a few hours of
work, not a rewrite.
