Files

195 lines
9.9 KiB
Markdown
Raw Permalink Normal View History

# Deploying to cPanel (site administrator guide)
This guide assumes the standard cPanel layout `/home/USER/`. Replace `USER` with the account's
username throughout. Nothing here changes DNS or publishes anything until step 8.
> **Current state (2026-09-22):** `visit.waterschurch.org` already resolves to the same server as
> waterschurch.org (108.160.152.27) and currently 301-redirects to a Church Center form
> (`waterschurch.churchcenter.com/people/forms/21186`). That redirect lives either in the main
> site's `.htaccess` or in a cPanel **Redirects** entry and must be removed when this site goes live.
## Fastest path: `deploy/deploy.sh` (SSH)
If you have SSH access (alias `waterschurch` in `~/.ssh/config`), one command does steps 2, 5, 6 and 7 below:
```bash
deploy/deploy.sh --keep-redirect # deploy, but keep visitors on the Church Center form (pre-launch)
deploy/deploy.sh # build, deploy and go live (removes the redirect)
deploy/deploy.sh --no-build # re-upload the existing ./out
```
It preserves cPanel's own `.htaccess` blocks and `.user.ini`, never overwrites an existing
`~/visit-private/.env`, and prints the health check when done. The manual steps below describe
what it does, for File Manager users or troubleshooting.
**Status 2026-09-22 (evening): LIVE.** Deployed with `deploy/deploy.sh`; the Church Center redirect is
gone. `INTEGRATION_MODE=live` with Mailchimp (audience "Waters Church", datacenter `us2`) and Sinch
(all five campus sub-accounts verified). The 12 merge fields exist in the audience. A real email-only
test lead succeeded end to end; the SMS path is verified against Sinch auth but a live text has not yet
been sent. Journey "New Visit" (id 5842) is still a draft and triggers only on `Visit:Apollo Beach`.
## 0. What you will need
* cPanel login for the waterschurch.org account
* The build package: run `npm run build && npm run package` → `dist/visit-waterschurch-<version>-<date>.zip`
* Filled-in `.env` values (Mailchimp key, Sinch key/secret, etc.) — see `.env.example`
## 1. Check the account's PHP
cPanel → **Software → MultiPHP Manager** (or *Select PHP Version*).
* Set the domain (once created) to **PHP 8.1, 8.2 or 8.3**.
* **MultiPHP INI Editor / Select PHP Version → Extensions**: ensure `curl`, `pdo_sqlite`, `sqlite3`,
`mbstring`, `json`, `openssl` are enabled. (`pdo_mysql` only if you choose MySQL storage.)
Node.js is **not** required. If the account has "Setup Node.js App", ignore it.
## 2. Create the private configuration folder (outside the web root)
cPanel → **Files → File Manager** → navigate to `/home/USER/` (the home directory, *not*
`public_html`).
1. Create folder **`visit-private`**.
2. Inside it create folders **`data`** and **`logs`**.
3. Upload `.env.example` from the package (`dist/env.example.txt`), rename it to **`.env`**, and edit
it in File Manager: fill in real values, set `INTEGRATION_MODE=live` only when ready to go live,
and set a long random `HASH_SALT`.
4. Permissions (right-click → *Change Permissions*): folders `0750`, the `.env` file `0640`.
PHP runs as your cPanel user under suPHP/LSAPI, so it can read and write these while the web
server cannot serve them.
If your host runs PHP as a different user (rare), use `0755`/`0644` and rely on the folder being
outside the document root.
## 3. Create the subdomain
cPanel → **Domains → Domains** (or *Subdomains* on older versions) → **Create a New Domain**:
* Domain: `visit.waterschurch.org`
* Untick "Share document root"; set **Document Root** to `/home/USER/visit.waterschurch.org`
* Submit. cPanel creates the folder and the DNS `A` record automatically because the zone is hosted
here (`ns1/ns2.waterschurch.org`). The record already exists and points at this server, so nothing
external changes.
Then remove the old redirect:
* cPanel → **Domains → Redirects**: delete any entry for `visit.waterschurch.org`, **or**
* File Manager → `public_html/.htaccess`: remove the `RewriteCond %{HTTP_HOST} ^visit\.` block that
redirects to churchcenter.com.
Do this at the moment you are ready to launch (step 8); until then the redirect keeps working.
## 4. Enable SSL
cPanel → **Security → SSL/TLS Status** → tick `visit.waterschurch.org` → **Run AutoSSL**.
Wait for the green padlock (usually under 5 minutes). If AutoSSL fails with a DCV error, make sure
the document root exists and nothing blocks `/.well-known/` (our `.htaccess` explicitly allows it).
Verify: `https://visit.waterschurch.org/BUILD.txt` shows the build id once files are uploaded
(step 5). Force-HTTPS is handled by the site's own `.htaccess`; you do **not** need cPanel's
"Force HTTPS Redirect" toggle, but enabling it is harmless.
## 5. Upload the build
1. File Manager → open `/home/USER/visit.waterschurch.org/`. Delete the placeholder `cgi-bin`
folder if present.
2. **Upload** the zip from `dist/`, then right-click → **Extract** into this folder. Delete the zip.
3. Enable **Settings → Show Hidden Files (dotfiles)** and confirm `.htaccess` is present at the root
and inside `api/lib`, `api/cron`, `api/config`.
4. Tell the API where the private folder is. Either:
* leave the default (`/home/USER/visit-private` — the folder *next to* the document root), **or**
* edit `/home/USER/visit.waterschurch.org/.htaccess` and uncomment
`SetEnv VISIT_PRIVATE_DIR /home/USER/visit-private` with the real path.
5. Permissions: folders `0755`, files `0644` (File Manager's defaults after extraction are fine).
The upload never requires editing generated files. To update the site later, rebuild locally and
repeat steps 5.2–5.3 (or use *File Manager → Upload* with "Overwrite existing files"). An alternative
for frequent updates is cPanel's **Git Version Control** pointed at a repo whose `out/` is committed,
or SFTP with `rsync --delete out/ USER@host:visit.waterschurch.org/`.
## 6. Verify the API
Open `https://visit.waterschurch.org/api/health.php`. You should see `"ok": true` and:
```
"private_dir_found": true, "env_file_found": true, "data_dir_writable": true,
"database": "ok (sqlite)", "campuses_loaded": 6, "https": true
```
`integration_mode` shows `mock` until you change it in `.env`. Fix anything `false` before continuing
(most often: wrong `VISIT_PRIVATE_DIR` path or `data` folder not writable).
Confirm private paths are blocked (each must return **403**):
* `https://visit.waterschurch.org/api/lib/Config.php`
* `https://visit.waterschurch.org/api/config/campuses.json`
* `https://visit.waterschurch.org/api/cron/retry-integrations.php`
## 7. Cron job for retries
cPanel → **Advanced → Cron Jobs** → add, every 5 minutes (`*/5 * * * *`):
```
VISIT_PRIVATE_DIR=/home/USER/visit-private /usr/local/bin/php /home/USER/visit.waterschurch.org/api/cron/retry-integrations.php >> /home/USER/visit-private/logs/cron.log 2>&1
```
Check the PHP binary path with **MultiPHP Manager** (often `/usr/local/bin/php`, `/opt/cpanel/ea-php82/root/usr/bin/php`, or `/usr/local/bin/ea-php82`). The job re-sends any Mailchimp/Sinch
delivery that failed transiently (up to 5 attempts with backoff) and, if `LEAD_RETENTION_DAYS` is set,
deletes fully-processed leads older than that.
Optional weekly export for staff (contains personal data — download and delete promptly):
```
VISIT_PRIVATE_DIR=/home/USER/visit-private /usr/local/bin/php /home/USER/visit.waterschurch.org/api/cron/export-leads.php --since=$(date -d '7 days ago' +%F) > /home/USER/visit-private/data/leads-week.csv
```
## 8. Go live
1. Set `INTEGRATION_MODE=live` in `/home/USER/visit-private/.env`.
2. Remove the Church Center redirect (step 3).
3. Submit one real test lead with your own email and mobile: confirm the Mailchimp contact + tags
and the confirmation text arrive. Reply STOP to test opt-out routing, then re-subscribe.
4. Run through [LAUNCH-CHECKLIST.md](LAUNCH-CHECKLIST.md).
## 9. Updating content later
| Change | Where | Then |
| --- | --- | --- |
| Service times, address, phone, SMS number, campus status | `config/campuses.json` | `npm run build` → re-upload |
| Logo | `assets/source/logos/` (same file names) | `npm run build` → re-upload |
| Photos | `assets/source/photos/` (same file names) | `npm run build` → re-upload |
| FAQs, kids info, headlines, consent text | `src/content/*.ts` (bump `consent.version` if consent text changes) | `npm run build` → re-upload |
| Central contact number, privacy URL | `.env` (`NEXT_PUBLIC_*`) | `npm run build` → re-upload |
| API keys, mode, providers | `/home/USER/visit-private/.env` | takes effect immediately, no rebuild |
| SMS template | `SINCH_CONFIRMATION_TEMPLATE` in server `.env` | immediate |
## 10. Files, permissions and logs
```
/home/USER/
├── visit.waterschurch.org/ document root (0755) — everything in out/
│ ├── .htaccess HTTPS + canonical redirects, caching, security headers, 404
│ ├── index.html, 404.html, _next/, images/
│ └── api/ PHP endpoints (public) + lib/ cron/ config/ (403)
└── visit-private/ NOT web accessible (0750)
├── .env secrets (0640)
├── data/leads.sqlite lead store (created automatically)
├── data/retry.lock
└── logs/app.log, cron.log JSON lines; personal data and secrets are redacted
```
Rotate `app.log` occasionally (cPanel cron: `find /home/USER/visit-private/logs -name '*.log' -size +20M -delete`)
or simply download and clear it.
## 11. Optional: MySQL instead of SQLite
cPanel → **Databases → MySQL Database Wizard**: create `USER_visit` + a user with ALL PRIVILEGES.
In `.env`: `DATABASE_DSN=mysql:host=localhost;dbname=USER_visit;charset=utf8mb4`,
`DATABASE_USER`, `DATABASE_PASSWORD`. Tables are created automatically on first request.
## 12. Content Security Policy
`.htaccess` ships a **report-only** CSP covering GTM, GA4, Meta, TikTok and Turnstile. After
confirming the tags you actually use, change `Content-Security-Policy-Report-Only` to
`Content-Security-Policy` and remove hosts you do not need.