253 lines
8.0 KiB
Markdown
253 lines
8.0 KiB
Markdown
# Deployment
|
|
|
|
## Server layout confirmed
|
|
|
|
The production server currently runs multiple separate Docker Compose projects:
|
|
|
|
- Main public site WordPress stack:
|
|
- project: `goodwalkconz`
|
|
- path: `/docker/wordpress/goodwalk.co.nz`
|
|
- Onboarding WordPress stack:
|
|
- project: `onboardinggoodwalkconz`
|
|
- path: `/docker/wordpress/onboarding.goodwalk.co.nz`
|
|
- Shared nginx:
|
|
- project: `nginx`
|
|
- path: `/docker/nginx`
|
|
- Shared mysql:
|
|
- project: `mysql`
|
|
- path: `/docker/mysql`
|
|
|
|
The deployment scripts in this repo are set up to deploy the new Svelte site as a
|
|
separate stack at:
|
|
|
|
- remote path: `/docker/goodwalk-svelte`
|
|
- compose file: `docker-compose.prod.yml`
|
|
- docker project: `goodwalk-svelte`
|
|
|
|
This leaves the onboarding site, shared nginx, shared mysql, and other unrelated
|
|
containers untouched.
|
|
|
|
## Files involved
|
|
|
|
- [deploy.ps1](deploy.ps1)
|
|
- Windows entrypoint for packaging the repo, uploading it, and running the
|
|
remote deployment helper over SSH.
|
|
- [scripts/deploy.ps1](scripts/deploy.ps1)
|
|
- Deprecated compatibility wrapper that forwards to the repo-root
|
|
`deploy.ps1`. Keep using the root script directly.
|
|
- [scripts/deploy-remote.sh](scripts/deploy-remote.sh)
|
|
- Server-side helper that updates only the `goodwalk-svelte` compose project.
|
|
- [scripts/deploy-from-git.sh](scripts/deploy-from-git.sh)
|
|
- Standalone server-side entrypoint that pulls from Git, then runs the same
|
|
compose/nginx deployment steps on the server.
|
|
- [docker-compose.prod.yml](docker-compose.prod.yml)
|
|
- Production compose file for the new Svelte app, mail API, and Postgres.
|
|
- `scripts/export-homepage-content.mjs`
|
|
- Local helper that exports the current `src/lib/content/homepage.ts` into a
|
|
deployable JSON payload before each deployment.
|
|
- `scripts/sync-homepage-content.mjs`
|
|
- Runtime helper that upserts the exported homepage content into PostgreSQL
|
|
after deploys that affect the app/database.
|
|
- [ssh-config](ssh-config)
|
|
- Repo-local SSH config used by the deployment script.
|
|
- [nginx/goodwalk.co.nz.svelte.conf.example](nginx/goodwalk.co.nz.svelte.conf.example)
|
|
- Example shared-nginx config for routing the main public site to the new
|
|
Svelte app and mail API.
|
|
|
|
## First-time server preparation
|
|
|
|
1. Fill in [ssh-config](ssh-config) with the real host details.
|
|
|
|
2. Create the deployment directory on the server:
|
|
|
|
```bash
|
|
mkdir -p /docker/goodwalk-svelte
|
|
```
|
|
|
|
3. The first deployment will auto-create the production env file on the server at:
|
|
|
|
```bash
|
|
/docker/goodwalk-svelte/.env
|
|
```
|
|
|
|
It is created from [deploy.env.template](deploy.env.template). Current template contents:
|
|
|
|
```env
|
|
APP_VERSION=4.0.2
|
|
ENABLE_GENERAL_ENQUIRIES=false
|
|
TZ=Pacific/Auckland
|
|
|
|
POSTGRES_DB=goodwalk
|
|
POSTGRES_USER=goodwalk
|
|
POSTGRES_PASSWORD=gw_Pg_7Jm9!Qx4#Ld2@Vr8
|
|
POSTGRES_PASSWORD_URLENCODED=gw_Pg_7Jm9%21Qx4%23Ld2%40Vr8
|
|
|
|
RESEND_API_KEY=replace-me
|
|
OWNER_EMAIL=replace-me
|
|
FROM_EMAIL=GoodWalk <bookings@goodwalk.co.nz>
|
|
REPLY_TO=aless@goodwalk.co.nz
|
|
|
|
FORM_MIN_SECONDS=4
|
|
FORM_MAX_SECONDS=7200
|
|
RATE_LIMIT_WINDOW_SECONDS=900
|
|
RATE_LIMIT_MAX_PER_IP=5
|
|
RATE_LIMIT_MAX_PER_EMAIL=3
|
|
RATE_LIMIT_MIN_INTERVAL_SECONDS=20
|
|
```
|
|
|
|
After the first deploy, edit `/docker/goodwalk-svelte/.env` on the server and replace:
|
|
|
|
- `RESEND_API_KEY=replace-me`
|
|
- `OWNER_EMAIL=replace-me`
|
|
|
|
4. Confirm the shared Docker network already exists:
|
|
|
|
```bash
|
|
docker network ls | grep webnet
|
|
```
|
|
|
|
Your server already uses `webnet`, so this should already be present.
|
|
|
|
## First deploy
|
|
|
|
From Windows PowerShell in the repo root:
|
|
|
|
```powershell
|
|
powershell -ExecutionPolicy Bypass -File .\deploy.ps1
|
|
```
|
|
|
|
This is the single supported deployment entrypoint. If you see
|
|
`scripts/deploy.ps1`, that file now just forwards to the root script so the
|
|
deployment logic only lives in one place.
|
|
|
|
Or skip the confirmation prompt:
|
|
|
|
```powershell
|
|
powershell -ExecutionPolicy Bypass -File .\deploy.ps1 -Force
|
|
```
|
|
|
|
To rebuild and restart only one service, for example the mail API:
|
|
|
|
```powershell
|
|
powershell -ExecutionPolicy Bypass -File .\deploy.ps1 -Force -Service mail-api
|
|
```
|
|
|
|
## Remote Git deploy
|
|
|
|
If you want the production server to pull straight from Gitea instead of
|
|
receiving an uploaded tarball from Windows, use
|
|
[scripts/deploy-from-git.sh](scripts/deploy-from-git.sh) on the server.
|
|
|
|
Recommended credential setup for a private HTTPS repo:
|
|
|
|
```bash
|
|
umask 077
|
|
cat > ~/.netrc <<'EOF'
|
|
machine g.sublogue.com
|
|
login YOUR_GITEA_USERNAME
|
|
password YOUR_READ_ONLY_TOKEN
|
|
EOF
|
|
chmod 600 ~/.netrc
|
|
```
|
|
|
|
Install the script on the server and make it executable:
|
|
|
|
```bash
|
|
install -m 0755 scripts/deploy-from-git.sh /usr/local/bin/goodwalk-deploy
|
|
```
|
|
|
|
The remote host must have `git` and `docker`. A host-level `node` install is
|
|
optional; if it is missing, the script will export homepage content using a
|
|
temporary `node:22-alpine` container instead.
|
|
|
|
Run a full deploy from the repo:
|
|
|
|
```bash
|
|
/usr/local/bin/goodwalk-deploy \
|
|
--repo-url https://g.sublogue.com/admin/gw-svelte.git \
|
|
--branch main \
|
|
--deploy-path /docker/goodwalk-svelte \
|
|
--compose-file docker-compose.prod.yml \
|
|
--project-name goodwalk-svelte \
|
|
--nginx-source nginx/goodwalk.co.nz.svelte.conf.example \
|
|
--nginx-target /docker/nginx/conf.d/goodwalk.co.nz.conf \
|
|
--nginx-compose-file /docker/nginx/docker-compose.yml \
|
|
--nginx-project-name nginx \
|
|
--maintenance-host-dir /docker/nginx/maintenance \
|
|
--maintenance-flag /docker/nginx/conf.d/maintenance.flag
|
|
```
|
|
|
|
Deploy a specific commit or tag:
|
|
|
|
```bash
|
|
/usr/local/bin/goodwalk-deploy \
|
|
--repo-url https://g.sublogue.com/admin/gw-svelte.git \
|
|
--branch main \
|
|
--ref <commit-or-tag> \
|
|
--deploy-path /docker/goodwalk-svelte \
|
|
--compose-file docker-compose.prod.yml \
|
|
--project-name goodwalk-svelte \
|
|
--nginx-source nginx/goodwalk.co.nz.svelte.conf.example \
|
|
--nginx-target /docker/nginx/conf.d/goodwalk.co.nz.conf \
|
|
--nginx-compose-file /docker/nginx/docker-compose.yml \
|
|
--nginx-project-name nginx \
|
|
--maintenance-host-dir /docker/nginx/maintenance \
|
|
--maintenance-flag /docker/nginx/conf.d/maintenance.flag
|
|
```
|
|
|
|
## Homepage content sync
|
|
|
|
Local development can feel fresher than production because production reads the
|
|
homepage/shared content from PostgreSQL whenever `DATABASE_URL` is set.
|
|
|
|
The deployment flow now handles that automatically:
|
|
|
|
1. `deploy.ps1` exports the current `src/lib/content/homepage.ts` into
|
|
`deploy-data/homepage-content.json`.
|
|
2. The deploy archive uploads that JSON payload with the app source.
|
|
3. After the Goodwalk stack is updated, the remote helper runs a content sync
|
|
inside the app container.
|
|
4. That sync upserts the `homepage` row in `site_content`.
|
|
|
|
This means future deploys will carry your latest file-based homepage/navigation/
|
|
shared content changes into production PostgreSQL automatically.
|
|
|
|
## Cutover nginx
|
|
|
|
After the new Svelte stack is up and healthy, update the shared nginx config on
|
|
the server for the main site.
|
|
|
|
Current live file:
|
|
|
|
```bash
|
|
/docker/nginx/conf.d/goodwalk.co.nz.conf
|
|
```
|
|
|
|
Use the repo example as the new target config:
|
|
|
|
```bash
|
|
nginx/goodwalk.co.nz.svelte.conf.example
|
|
```
|
|
|
|
Important:
|
|
- `deploy.ps1` now copies the repo nginx config to `/docker/nginx/conf.d/goodwalk.co.nz.conf` and reloads the shared nginx container as part of deployment.
|
|
- The repo nginx config uses Docker's internal resolver so future app/mail container rebuilds will not leave nginx pinned to stale upstream IPs.
|
|
|
|
Manual nginx commands, if you ever need them:
|
|
|
|
```bash
|
|
docker compose -p nginx -f /docker/nginx/docker-compose.yml exec nginx nginx -t
|
|
docker compose -p nginx -f /docker/nginx/docker-compose.yml exec nginx nginx -s reload
|
|
```
|
|
|
|
## Important notes
|
|
|
|
- Do not deploy the top-level `docker-compose.yml` to this server for production.
|
|
It includes its own nginx service and does not match the shared nginx setup on
|
|
the host.
|
|
- The deployment scripts do not stop or remove the onboarding WordPress stack.
|
|
- The deployment scripts do not touch the shared mysql compose project.
|
|
- The deployment scripts preserve the remote `.env` file.
|
|
- The site check in `deploy.ps1` targets `https://www.goodwalk.co.nz/api/health`.
|
|
Before nginx cutover, use `-SkipSiteCheck` or expect that check to fail.
|