Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ jobs:
- name: Build
run: npm run build

- name: Fail if dist/ differs from the committed tree
run: |
if ! git diff --exit-code --stat -- dist/; then
echo "::error::dist/ does not match a clean rebuild. Run 'npm run build' and commit the result."
exit 1
fi
echo "dist/ reproduces exactly."

- name: Verify output
run: |
for page in index about services contact shop privacy terms; do
Expand Down
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,58 @@ All compiled output goes to `dist/`. Do not edit files in `dist/` directly.
GitHub Actions runs on every push and pull request to `master`:
1. Prettier format check
2. Full build
3. Verify all 7 HTML pages are present in `dist/`
3. Fail if `dist/` does not match a clean rebuild
4. Verify all 7 HTML pages are present in `dist/`

Step 3 matters because the server serves the committed `dist/` and never runs a
build. Without it, `src/` and `dist/` can drift apart and CI stays green while the
live site is stale. A sibling site ran 20 months behind `master` before anyone
noticed.

## Deployment

The site runs on a Vultr VPS behind Cloudflare. Apache serves the committed
`dist/` from `/var/www/integrumsys.com/dist` — **the server never runs a build**,
so whatever is committed under `dist/` is what visitors get.

Deployment is a manual pull:

```sh
ssh linuxuser@integrumsys.com
cd /var/www/integrumsys.com
sudo git pull --ff-only origin master
```

No restart is needed; Apache reads the files on each request.

A source change is only live once the rebuilt `dist/` is committed too:

```sh
npm ci
npm run build
git add dist/ && git commit
```

### Server notes

- SSH is key-only; password authentication is disabled and `PermitRootLogin` is
`prohibit-password`. `linuxuser` has passwordless sudo, so that key alone is
root. Its password is deliberately left set — it is the only Vultr console
fallback if the key ever fails.
- fail2ban guards SSH with escalating bans. Before it was installed the box was
taking roughly 9,000 failed authentication attempts per day.
- ufw allows 22 and 80 from anywhere, but **443 only from Cloudflare's published
ranges**, so the origin cannot be reached directly. Refresh the ranges from
<https://www.cloudflare.com/ips-v4> and `ips-v6` if the site becomes
intermittently unreachable — Cloudflare adds ranges occasionally, and a missing
one fails for a subset of edges rather than outright.
- **Port 80 must stay open.** Certbot uses the `apache` authenticator (HTTP-01),
so restricting port 80 breaks certificate renewal — and the failure surfaces up
to 90 days later as a browser warning, with no email since Let's Encrypt
stopped expiry notifications. Closing it requires moving to DNS-01 first.
Verify any firewall or vhost change with
`sudo /snap/bin/certbot renew --dry-run` (certbot is a snap; non-interactive
SSH needs the full path).

## License

Expand Down
Loading