Vinteum's public website, built with Next.js, React, TypeScript, and Tailwind CSS.
Production repository:
https://github.com/vinteumorg/vinteum-site
Production branch:
main
- Next.js App Router
- React
- TypeScript
- Tailwind CSS
- pnpm
- systemd for the Linux VM service
- GitHub webhook-based autodeploy for pushes to
main
- Node.js compatible with the Next.js version in
package.json - pnpm
Install dependencies:
pnpm installCreate a local environment file if needed:
cp .env.local.example .env.localRun the development server:
pnpm devOpen:
http://localhost:3000
pnpm dev # start local development server
pnpm build # create a production build
pnpm start # start the production server
pnpm lint # run eslintEnvironment variables are read from .env.local in local/server environments. This file is intentionally ignored by git.
Important production-only variable:
GITHUB_WEBHOOK_SECRET=<strong random secret>
This secret is used by the deploy webhook to verify GitHub's X-Hub-Signature-256 header.
Generate a new secret with:
openssl rand -hex 32Do not commit secrets to the repository.
The production app runs on the Linux VM under systemd as:
vinteum-site.service
The app path on the server is:
/home/exedev/vinteum-site
Restart the production service with:
sudo systemctl restart vinteum-site.serviceCheck service status with:
systemctl status vinteum-site.service --no-pager -lThis repo includes a GitHub webhook endpoint:
GET /api/deploy
POST /api/deploy
Health check:
curl https://www.vinteum.org/api/deployExpected response:
{ "ok": true, "route": "deploy" }Configure the webhook in GitHub repository settings:
Payload URL: https://www.vinteum.org/api/deploy
Content type: application/json
Secret: value of GITHUB_WEBHOOK_SECRET from the server .env.local
Events: Just the push event
Active: yes
`application/json` is preferred. The deploy route also accepts GitHub's
`application/x-www-form-urlencoded` payload format for compatibility.
The endpoint also works behind the apex redirect:
https://vinteum.org/api/deploy -> https://www.vinteum.org/api/deploy
Using the www URL directly avoids relying on webhook redirect behavior.
The webhook only deploys when all of these are true:
GitHub event: push
ref: refs/heads/main
deleted: false
valid X-Hub-Signature-256 signature
For valid deploy events, the API route starts the deploy script asynchronously and returns quickly to GitHub.
Deploy script:
scripts/deploy-main.sh
The script:
- uses a
flocklock to prevent overlapping deploys - works in
/home/exedev/vinteum-site - fetches
origin main - resets hard to
origin/main - installs dependencies with a frozen lockfile
- builds the app
- restarts
vinteum-site.service - logs output to
/home/exedev/vinteum-deploy.log
Equivalent commands:
git fetch origin main
git reset --hard origin/main
pnpm install --frozen-lockfile
pnpm build
sudo systemctl restart vinteum-site.serviceWatch deploy logs:
tail -f /home/exedev/vinteum-deploy.logHealth check:
curl http://localhost:8000/api/deployTest a signed GitHub-style ping without triggering a deploy:
node - <<'NODE'
const crypto = require('crypto');
const fs = require('fs');
const env = fs.readFileSync('.env.local', 'utf8');
const secret = env.match(/^GITHUB_WEBHOOK_SECRET=(.+)$/m)[1].trim();
const payload = JSON.stringify({ zen: 'Keep it logically awesome.' });
const signature = 'sha256=' + crypto.createHmac('sha256', secret).update(payload).digest('hex');
fetch('http://localhost:8000/api/deploy', {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-github-event': 'ping',
'x-hub-signature-256': signature,
},
body: payload,
})
.then(async (res) => {
console.log(res.status, await res.text());
})
.catch((error) => {
console.error(error);
process.exit(1);
});
NODEDo not test a signed push event unless you intentionally want to trigger a real deployment.
The current origin remote is:
https://github.com/vinteumorg/vinteum-site.git
The previous remote is kept locally, when available, as:
old-origin
A backup branch was created before rebasing local site changes onto the new upstream:
backup/pre-upstream-rebase-20260630225524
Use small, focused commits. Before pushing changes to main, run:
pnpm buildPushing to main triggers production deployment through the GitHub webhook.