Use a GitHub repository webhook to notify an HTTPS Node.js endpoint whenever the selected repository event occurs. The endpoint should verify the raw request with X-Hub-Signature-256, identify the repository, ref, action, and X-GitHub-Delivery ID, then place an authorized synchronization job on a durable queue. A worker performs the controlled Git fetch, fast-forward, build, or deployment while the HTTP handler returns a 2XX response within GitHub’s 10-second limit.
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
The important design choice is the synchronization contract: a push can update a bare mirror, fast-forward a checked-out branch, build a specific commit, or merely trigger another system. Decide that policy before writing the webhook, because accepting arbitrary branch names or shell commands from a request can turn a deployment endpoint into a remote-code-execution service.
| # | Preview | Product | Price | |
|---|---|---|---|---|
| 1 |
|
Pro Git | Buy on Amazon | |
| 2 |
|
Pro Git (Expert's Voice in Software Development) | $37.07 | Buy on Amazon |
| 3 |
|
Professional Git | $24.79 | Buy on Amazon |
| 4 |
|
Pro Git 1st (first) edition Text Only | $83.26 | Buy on Amazon |
| 5 |
|
Git: Github Programming, In 8 Hours, For Beginners, Learn Coding Fast: Git Github Language, Crash... | $2.99 | Buy on Amazon |
As an Amazon Associate I earn from qualifying purchases.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesWhat a webhook-based sync actually does
GitHub describes webhooks as HTTP notifications delivered to an external web server when selected events occur. In a synchronization system, GitHub is the event source, Node.js is the authenticated intake service, and a separate worker owns the privileged Git or deployment operation.
A push event does not itself copy files to your server. It carries metadata such as the repository, ref, commit information, and delivery ID. Your application decides whether that repository and ref are permitted, records the delivery, and schedules work. The worker then fetches from the expected remote and applies a deterministic update policy.
#1 Best Overall
Choose the contract before choosing the code
| Contract | What the worker does | When it fits | Main risk |
|---|---|---|---|
| Bare mirror | Fetches the approved remote into a bare repository, usually with pruning. | Backup, archival, or serving another internal clone. | A mirror update can remove refs; do not point it at a working tree. |
| Fast-forward deployment branch | Fetches the approved branch and runs a fast-forward-only update. | A host that should never deploy rewritten history. | The job must fail visibly when the remote is not a descendant of the deployed commit. |
| Clean checkout | Checks out the approved commit or branch into an isolated directory. | Immutable builds and reproducible releases. | Reset or checkout operations must be confined to a dedicated service directory. |
| Build or deployment trigger | Builds a specific commit and hands an artifact to the deployment system. | Systems where the webhook host should not serve live files. | The build system needs its own authorization, retention, and rollback policy. |
| Notification only | Stores the event and alerts another system without changing Git state. | Approval workflows, dashboards, or audit pipelines. | It does not provide synchronization by itself. |
Keep the contract narrow. A repository allow-list, an explicit branch mapping, and a fixed operation are safer than allowing a payload to choose a local path, executable, or arbitrary Git ref.
Reference architecture
A robust flow has five boundaries:
- GitHub delivery: GitHub sends an HTTPS POST containing event headers and a JSON payload.
- Node.js intake: the service reads the exact request bytes, authenticates the signature, validates the event, and reserves the delivery ID.
- Durable queue: the accepted job records the repository, ref, commit SHA, event, and delivery ID.
- Git worker: a least-privilege account fetches from the configured remote and performs the selected update.
- Audit and recovery: status, output, and errors are retained so an operator can inspect or retry a failed delivery.
Do not perform a network fetch, checkout, build, or deployment inside the request handler. Those operations have unpredictable duration and can prevent GitHub from receiving its acknowledgement.
Prerequisites and deployment boundary
- A repository where you can manage webhooks and a server reachable at a stable HTTPS URL.
- Node.js with access to the built-in
http,crypto, and buffer APIs, or an equivalent web framework that exposes the untouched request body. - A high-entropy webhook secret stored in a secret manager or protected environment variable.
- A dedicated service account and filesystem directory for the Git worker.
- A durable store for delivery IDs and job status. An in-memory set is not sufficient because it disappears on restart.
- A queue or worker process that can retry or expose failed jobs without making the webhook request wait.
Terminate TLS at the Node.js service or at a reverse proxy with certificate verification enabled. If a proxy parses and re-serializes JSON before your application receives it, signature verification can fail because the HMAC is calculated over the original bytes, not an equivalent JSON object.
Build the Node.js intake endpoint
The following example uses Node’s native HTTP server so the raw-body requirement is visible. Replace the illustrative deliveryStore and jobQueue objects with durable implementations.
const http = require('node:http');
const crypto = require('node:crypto');
const secret = Buffer.from(process.env.GITHUB_WEBHOOK_SECRET || '', 'utf8');
const allowedRepositories = new Set(['acme/game-project']);
const allowedRefs = new Set(['refs/heads/main']);
function validSignature(rawBody, header) {
if (!header || !header.startsWith('sha256=')) return false;
const supplied = Buffer.from(header.slice(7), 'hex');
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
return supplied.length === expected.length && crypto.timingSafeEqual(supplied, expected);
}
function readBody(req) {
return new Promise((resolve, reject) => {
const chunks = [];
req.on('data', chunk => chunks.push(chunk));
req.on('end', () => resolve(Buffer.concat(chunks)));
req.on('error', reject);
});
}
const server = http.createServer(async (req, res) => {
if (req.method !== 'POST' || req.url !== '/github/webhook') {
res.writeHead(404).end();
return;
}
let rawBody;
try {
rawBody = await readBody(req);
} catch {
res.writeHead(400).end('cannot read request');
return;
}
if (!validSignature(rawBody, req.headers['x-hub-signature-256'])) {
res.writeHead(401).end('invalid signature');
return;
}
const deliveryId = req.headers['x-github-delivery'];
const eventName = req.headers['x-github-event'];
if (typeof deliveryId !== 'string' || typeof eventName !== 'string') {
res.writeHead(400).end('missing GitHub headers');
return;
}
let payload;
try {
payload = JSON.parse(rawBody.toString('utf8'));
} catch {
res.writeHead(400).end('invalid JSON');
return;
}
const repository = payload.repository && payload.repository.full_name;
const ref = payload.ref;
const action = payload.action || null;
if (eventName !== 'push' || !allowedRepositories.has(repository) || !allowedRefs.has(ref)) {
res.writeHead(202).end('ignored');
return;
}
const reservation = await deliveryStore.reserve(deliveryId, {
eventName, repository, ref, action
});
if (reservation === 'completed' || reservation === 'in-flight') {
res.writeHead(200).end('already recorded');
return;
}
try {
jobQueue.enqueue({
deliveryId,
eventName,
action,
repository,
ref,
commit: payload.after
});
res.writeHead(202).end('accepted');
} catch (error) {
await deliveryStore.markFailedToQueue(deliveryId, String(error));
res.writeHead(503).end('queue unavailable');
}
});
server.listen(process.env.PORT || 8080);
The example validates before it uses JSON fields to select work. It also treats the GitHub delivery ID as a durable idempotency key. A real store should make the reservation unique, keep a status such as received, running, completed, or failed, and retain the repository, ref, commit, and timestamps.
Rank #2
Preserve the exact raw body
GitHub’s SHA-256 signature is an HMAC over the exact bytes sent in the request. Parse the body only after verification. JSON middleware that consumes the stream first, changes whitespace, or converts character encoding can leave you with a different byte sequence and an invalid comparison.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteRead the X-Hub-Signature-256 header, remove its sha256= prefix, decode the hexadecimal digest, and calculate your own HMAC with the shared secret. Compare equal-length digests with a constant-time function. Reject a missing, malformed, or mismatched signature before examining payload-controlled instructions.
Classify the delivery
Use X-GitHub-Event to select the event family. Then inspect the payload’s action when that event defines actions. Push payloads commonly identify the target with ref and the resulting commit with after; other event types have different fields and should not be forced through the push path.
Allow-list the complete combination you intend to process: organization or repository, event name, branch or ref, and any required action. Return a harmless 2XX response for valid but irrelevant events so they are not retried as failures. Never infer authorization merely from a branch string supplied by the request.
Make duplicate handling explicit
X-GitHub-Delivery identifies a delivery. Reserve it before queueing work, using a uniqueness constraint in the delivery store. If the same ID arrives while the first job is running, acknowledge it without adding a second Git mutation. Mark the record completed only after the worker finishes successfully. Keep failed records available for an operator retry rather than silently treating an error as success.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
Configure the GitHub repository webhook
- Open the repository’s Settings, choose Webhooks, and select Add webhook.
- Enter the HTTPS URL for the Node.js route, such as
https://sync.example.net/github/webhook. - Set the content type to
application/jsonand enter the same high-entropy secret loaded by the service. - Keep SSL verification enabled. Disable it only while diagnosing a controlled staging certificate problem, then re-enable it before production use.
- Select only the events required by the contract. Choose push events for branch synchronization; add another event only when a documented workflow needs it.
- Save the webhook, then inspect the repository’s delivery history. Confirm that the endpoint records the event and returns a 2XX response without exposing the secret or payload credentials in logs.
- Make a test commit on an allowed branch and correlate the resulting delivery ID with the queued job and worker log.
Subscribing to every event increases validation and logging paths without improving a push-only deployment. GitHub recommends selecting the minimum event set and checking both event type and action.
Design the queue and worker
The queue message should contain immutable facts from the authenticated delivery: delivery ID, event name, action, repository full name, ref, commit SHA, reception time, and a configuration key identifying the target workspace. It should not contain an executable command assembled from payload text.
The worker loads the repository and branch mapping from trusted configuration, verifies that the message still refers to an allowed project, and uses an account with only the Git and host permissions required for that target. Log the delivery ID on every worker message so an operator can trace one event across intake, queue, fetch, build, and deployment.
Fast-forward-only update
For a checked-out deployment branch, fetch from the configured remote and update with a fast-forward-only policy. A conceptual command sequence is:
Free tools Windows power users keep installed
One-click scans. No signup required.
git -C /srv/game-project fetch --prune origin refs/heads/main
git -C /srv/game-project merge --ff-only origin/main
Use a process-spawn API with an argument array rather than passing a concatenated string to a shell. Validate the configured ref before constructing the argument list. If the merge is not a fast-forward, stop and alert; do not automatically reset a production worktree to whatever commit appeared in the request.
Clean checkout or build from a commit
For reproducible builds, fetch the approved remote and check out the exact commit SHA recorded in the event, preferably in an isolated worktree or disposable build directory. Build artifacts from that directory, publish them through the deployment system, and retain the commit SHA with the artifact. This avoids a race in which a moving branch changes between the webhook and the build.
Bare mirror
A bare mirror can use a dedicated repository and a configured refspec that is deliberately allowed to prune. Treat mirror updates as destructive to local refs and keep the mirror separate from any directory serving live files. If the mirror is also a backup, add independent storage and retention; a webhook is not a substitute for backup verification.
Acknowledge quickly, process asynchronously
GitHub’s webhook guidance requires the server to respond with a 2XX status within 10 seconds. The handler should perform only bounded work: read the body, verify the signature, validate the event, reserve the delivery ID, and enqueue a job. Fetches, dependency installation, tests, packaging, and deployment belong to the worker.
A queue outage is different from an irrelevant event. For an allowed delivery that cannot be durably queued, return a failure status and record the reason so the delivery is visible for redelivery. For a valid event outside your allow-list, acknowledge it as ignored and retain enough metadata to explain that decision.
Failure recovery and redelivery
GitHub does not automatically redeliver failed webhook deliveries. Persist the delivery status and worker output, and provide an operator procedure for retrying a failed synchronization. After an outage, open the repository webhook’s recent delivery history, select the missed delivery, and use its redelivery control. The intake service will receive a new attempt; the original delivery ID remains the key for deciding whether work already completed.
Best Value
Separate transport failure from Git failure. A transport failure means the endpoint could not authenticate or enqueue the message. A Git failure may mean the remote is unreachable, credentials expired, the ref was deleted, the update is not a fast-forward, or the build failed. Record these categories separately so an operator knows whether to redeliver, fix the worker, or change the repository policy.
Retried jobs must be idempotent at the operation level as well as at the webhook level. Before deploying, verify the target commit and current state. If a previous worker completed the deployment but crashed before writing its final status, a second run should detect the commit or artifact already applied rather than blindly repeating a destructive reset.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Security checklist
- Transport: expose the endpoint over HTTPS and keep certificate verification enabled.
- Secret handling: generate a high-entropy secret, store it in a secret manager or protected environment variable, and never commit or print it.
- Authentication: verify
X-Hub-Signature-256over the raw bytes before parsing or acting on JSON. - Comparison: use a constant-time digest comparison and reject malformed lengths safely.
- Scope: allow-list repositories, organizations, refs, event names, and actions.
- Git credentials: use a token or deploy credential with the least repository permissions needed for fetching.
- Host permissions: run the worker as a dedicated account restricted to its repository, build directory, and deployment interface.
- Command safety: use fixed command paths and argument arrays; never execute a payload field as shell text.
- Isolation: keep the fast HTTP handler separate from privileged background work.
- Audit: log delivery ID, repository, ref, commit SHA, decision, result, and error without logging secrets.
Testing before production
Signature tests
Send a known body with a locally calculated HMAC and confirm that the endpoint accepts the matching digest. Change one byte, remove the prefix, use a different secret, and send a digest of the wrong length; each case should be rejected before queueing.
Event and authorization tests
Test an allowed push, a push to a disallowed branch, a delivery from an unapproved repository, and an event name your service does not process. The latter cases should not invoke Git. Verify that payloads with missing repository or ref fields cannot bypass the allow-list.
Idempotency tests
Submit the same delivery ID twice, including while the first worker is running. Confirm that only one job performs the Git mutation. Then simulate a worker failure, confirm the record is marked failed, and exercise the operator retry path.
Worker tests
Run against a staging repository and a disposable worktree. Cover an ordinary fast-forward, a non-fast-forward update, a deleted branch, a network timeout, an invalid remote, and a failed build. Check that each failure leaves the previous deployed state intact and produces a searchable delivery-linked log.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Troubleshooting common failures
| Symptom | Likely cause | Correction |
|---|---|---|
| Every request returns 401 | The service parsed or transformed the body, the secret differs, or the signature header is being truncated. | Capture raw bytes, compare the configured secrets, preserve the complete sha256= value, and test with a known fixture. |
| GitHub marks deliveries as failed after several seconds | The handler is waiting for fetch, build, or deployment work. | Reserve the delivery and enqueue a job before returning a 2XX response. |
| The same commit deploys twice | The delivery store is in memory, or the ID is recorded after queueing. | Use a durable unique reservation before work begins and make the worker idempotent. |
| Valid pushes are ignored | The repository full name, ref format, or event name does not match configuration. | Log the allow-list decision and compare it with the exact payload values, such as refs/heads/main. |
| Fast-forward update fails | The checked-out branch has diverged or local changes exist. | Stop, preserve the worktree, inspect the divergence, and choose an explicit recovery policy instead of an automatic reset. |
| Redelivery appears to do nothing | The original delivery is already marked completed or remains in-flight. | Inspect the delivery record and worker log; retry only a failed or intentionally reset job. |
| Worker can fetch but cannot deploy | The host service account lacks the required filesystem, process, or deployment permission. | Grant the smallest missing permission to the worker account and keep the intake process unprivileged. |
When to use an official Node.js helper
Octokit’s webhooks.js toolkit provides helpers for webhook event handling, including webhooks.verify(eventPayload, signature). It can reduce signature-verification boilerplate, but it does not decide which repositories or refs you trust, reserve delivery IDs, enqueue jobs, or perform your Git policy. Keep those authorization, queueing, and worker responsibilities in your service.
Whether you use the helper or native crypto, the invariants remain the same: verify the untouched body, check the event and action, enforce an allow-list, deduplicate with X-GitHub-Delivery, acknowledge promptly, and run Git operations outside the request process.
Quick Recap
Operational checklist
- Write down the synchronization contract and rollback behavior.
- Map each approved repository and branch to a fixed target directory or build configuration.
- Configure an HTTPS webhook with the smallest event set and SSL verification enabled.
- Store the secret outside source control and rotate it through a controlled procedure.
- Verify signatures before JSON-driven decisions and compare digests in constant time.
- Persist delivery IDs before queueing and retain status through completion or failure.
- Return a 2XX response within 10 seconds after durable acceptance.
- Run fetch, checkout, build, and deployment in a least-privilege worker.
- Log delivery ID, repository, ref, commit, result, and error without secrets.
- Test duplicate deliveries, rejected signatures, divergent branches, outages, and manual redelivery before enabling production updates.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




