Marketing website for Integrum Systems Inc. Built with Bootstrap 5, Pug, and Sass via a Node.js build pipeline.
| Page | Source | Description |
|---|---|---|
| Home | src/pug/index.pug |
Hero, differentiators, CTA |
| About | src/pug/about.pug |
Founding context, founder, operating principles |
| Services | src/pug/services.pug |
Service cards, approach block |
| Contact | src/pug/contact.pug |
Contact form, direct info |
| Shop | src/pug/shop.pug |
Coming Soon product card |
| Privacy | src/pug/privacy.pug |
Privacy policy stub |
| Terms | src/pug/terms.pug |
Terms of service stub |
- Bootstrap 5.2.3
- Pug 3.0.2 — HTML templating
- Sass 1.60.0 — CSS compilation
- Prettier 3.x +
@prettier/plugin-pug— formatting - Browser Sync — live reload dev server
| Command | Description |
|---|---|
npm run build |
Clean + compile all sources to dist/ |
npm run build:pug |
Compile Pug to HTML |
npm run build:scss |
Compile Sass to CSS |
npm run build:scripts |
Copy JS to dist |
npm run build:assets |
Copy assets to dist |
npm run clean |
Delete dist/ |
npm start |
Build + launch live preview with watch |
npm run format |
Format all source files with Prettier |
npm install
npm start # builds and opens browser with live reloadAll compiled output goes to dist/. Do not edit files in dist/ directly.
GitHub Actions runs on every push and pull request to master:
- Prettier format check
- Full build
- Fail if
dist/does not match a clean rebuild - 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.
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:
ssh linuxuser@integrumsys.com
cd /var/www/integrumsys.com
sudo git pull --ff-only origin masterNo restart is needed; Apache reads the files on each request.
A source change is only live once the rebuilt dist/ is committed too:
npm ci
npm run build
git add dist/ && git commit- SSH is key-only; password authentication is disabled and
PermitRootLoginisprohibit-password.linuxuserhas 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-v6if 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
apacheauthenticator (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 withsudo /snap/bin/certbot renew --dry-run(certbot is a snap; non-interactive SSH needs the full path).
MIT — see LICENSE.