Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesiTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Antihost offers Linux VPS plans with full root access, unlimited traffic on a 1 Gbps port and a 14-day free trial.
Use a GitHub repository webhook to notify an HTTPS Node.js endpoint when a selected event—usually a push—occurs. Verify the X-Hub-Signature-256 HMAC against the untouched request bytes, identify the event and delivery ID, record that ID for idempotency, return a 2XX response within 10 seconds, and let a queued worker perform the Git fetch, checkout, build, or deployment. This separates an untrusted network request from privileged repository changes and gives you a recoverable synchronization process instead of a shell command exposed to the internet.
Start with the synchronization contract
A webhook only announces that something happened. It does not define what your server should do with the repository. Write the synchronization contract before writing the handler, because each policy has different safety and recovery requirements.
| # | 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 |
| Contract | What the worker does | When it fits | Main risk |
|---|---|---|---|
| Bare mirror | Fetches the approved remote refs into a bare repository. | You need a server-side copy for backup, replication, or another read-only consumer. | A mirror can contain many refs; do not mistake it for a deployed working tree. |
| Fast-forward deployment | Fetches a named branch and advances a checked-out tree only with a fast-forward. | The deployment branch is linear and force-pushes are not part of the release process. | A rewritten or diverged branch must fail safely rather than silently overwrite files. |
| Clean checkout of a commit | Fetches, checks out the exact approved commit, builds, and activates the result. | Reproducible deployments where each delivery should identify one immutable revision. | Build artifacts, environment variables, and rollback storage must be managed separately. |
| CI or deployment trigger | Places repository, ref, and commit information on a queue for another pipeline. | The webhook host should not hold compiler, deployment, or production credentials. | The downstream system still needs authentication, idempotency, and failure reporting. |
| Notification only | Stores or forwards event metadata without changing Git state. | You are integrating issue tracking, audit logging, or chat notifications. | It does not keep a checkout synchronized by itself. |
Never let a payload choose an arbitrary shell command, directory, remote URL, or branch. Allow-list the repository, organization, event, action, and deployment ref in configuration. Treat the webhook as a request to run one of those pre-declared operations, not as a remote-control interface.
Use a two-stage architecture
Stage 1: a small, defensive receiver
The public endpoint should do only the work required to authenticate and classify a delivery. It reads the raw body, validates the signature, parses enough JSON to determine the event and action, checks the repository and ref against policy, records the delivery ID, and writes a job to durable storage. It then responds with a 2XX status.
#1 Best Overall
Stage 2: a privileged worker
A private worker consumes the job and performs git fetch, checkout or merge, build, and deployment. The worker can retry with backoff, serialize jobs for the same repository, and keep credentials away from the internet-facing process. GitHub’s guidance requires a server to answer within 10 seconds; a slow fetch or build must never run in the request path.
Keep these records for every job: delivery ID, repository full name, event name, action, ref, commit SHA, received time, start and finish times, result, and a redacted error message. Those fields let an operator distinguish a duplicate delivery from a failed Git operation and retry a specific revision.
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 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPrepare the Node.js endpoint
Prerequisites
- A publicly reachable HTTPS URL with a valid certificate. Enable certificate verification in the GitHub webhook configuration.
- A Node.js service account and a process manager or container runtime that can restart the receiver.
- A secret manager or protected environment variable for the webhook secret.
- A durable queue or database for delivery records and jobs. An in-memory array is suitable only for a local demonstration.
- A separate, least-privilege account for the Git worker and, where possible, a separate account for deployment activation.
Install the receiver dependencies
npm install express
The example below uses Express’s raw-body middleware. Do not place a JSON parser before this route: parsing and re-serializing JSON can change whitespace or character encoding and invalidate an otherwise correct signature.
Verify the signature before parsing actions
const express = require('express');
const crypto = require('crypto');
const app = express();
const secret = process.env.GITHUB_WEBHOOK_SECRET;
if (!secret) {
throw new Error('GITHUB_WEBHOOK_SECRET is required');
}
function signaturesMatch(rawBody, supplied) {
if (typeof supplied !== 'string' || !supplied.startsWith('sha256=')) {
return false;
}
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const a = Buffer.from(supplied, 'utf8');
const b = Buffer.from(expected, 'utf8');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post(
'/github/webhook',
express.raw({ type: 'application/json', limit: '2mb' }),
async (req, res) => {
const signature = req.get('x-hub-signature-256');
const delivery = req.get('x-github-delivery');
const event = req.get('x-github-event');
if (!delivery || !event || !signaturesMatch(req.body, signature)) {
return res.sendStatus(401);
}
let payload;
try {
payload = JSON.parse(req.body.toString('utf8'));
} catch {
return res.sendStatus(400);
}
const repository = payload.repository?.full_name;
const ref = payload.ref;
const action = payload.action || null;
const commit = payload.after || null;
if (event !== 'push' || repository !== process.env.ALLOWED_REPOSITORY ||
ref !== 'refs/heads/main') {
return res.sendStatus(204);
}
// Replace these calls with a durable, transactional store and queue.
if (await deliveries.completedOrRecorded(delivery)) {
return res.sendStatus(204);
}
await deliveries.record({ delivery, event, action, repository, ref, commit });
await jobs.enqueue({ delivery, repository, ref, commit });
return res.sendStatus(202);
}
);
app.listen(process.env.PORT || 3000);
deliveries and jobs are intentionally interfaces in this example. In production, record the delivery and enqueue the job in a way that survives a process crash. If the two operations cannot be made atomic, use an outbox table: commit the delivery and job in one database transaction, then have a dispatcher publish pending outbox rows.
Rank #2
Why each header matters
X-Hub-Signature-256is the SHA-256 HMAC that proves possession of the configured secret and detects body tampering. Reject missing or mismatched values.X-GitHub-Eventidentifies the event family, such aspush. Do not infer the event from a payload field.X-GitHub-Deliveryis the unique delivery identifier to use as the idempotency key. Persist it before starting a Git mutation.- The payload’s
action, when present, further classifies events. A handler that accepts several event families must allow-list valid event/action combinations.
Use a constant-time comparison for signatures. A normal string comparison can leak timing information. Keep the secret out of source control, logs, error pages, and process arguments visible to other users.
Configure the repository webhook
- In the repository, open Settings, then Webhooks, and choose Add webhook.
- Enter the complete HTTPS receiver URL, including the path such as
/github/webhook. - Set the payload content type to JSON and enter a high-entropy secret generated for this integration. Do not reuse a password or a repository access token.
- Enable SSL verification. Disabling it allows an intermediary to impersonate the endpoint.
- Select only the events your contract needs. For a branch synchronization trigger, choose the push event rather than subscribing to every event.
- Save the webhook, then inspect the delivery details for the test request. Confirm that your server returned a 2XX status, recorded the delivery ID, and did not start a deployment for an unapproved ref.
If your policy needs tags, pull requests, releases, or several branches, add each event deliberately and implement a separate allow-list rule. A broad subscription increases traffic and the number of payload shapes your code must reject safely.
Free tools Windows power users keep installed
One-click scans. No signup required.
Choose a safe Git update policy
Fast-forward-only branch update
For a long-lived checkout, fetch from a configured remote and advance only when the target branch can be fast-forwarded. A worker can run git fetch --prune origin, verify that the remote URL is the expected repository, and then use git merge --ff-only origin/main. If the command reports divergence, mark the job failed and require an operator decision. Do not automatically reset a shared working tree to resolve it.
Exact-commit deployment
For reproducible releases, use the commit SHA from the verified push payload as the requested revision. Fetch the expected remote, verify that the SHA is present in the fetched ref, and check out a detached worktree or a new release directory. Build there, run tests, and switch an application symlink only after the build succeeds. Retain the previous release directory so rollback does not require another webhook.
Rank #3
Bare mirror
A mirror worker should operate in a bare repository and fetch approved refs. It should not execute application build scripts. Consumers can clone from that mirror or read it through another controlled service. Keep mirror synchronization separate from deployment so a mirror update cannot accidentally restart production.
Reset, merge, and force-push decisions
git reset --hard is destructive and belongs only in an isolated deployment worktree whose contents can be recreated. A merge policy creates a new commit and may introduce conflict handling that is inappropriate for an automated receiver. If force-pushes are allowed, define exactly which refs may be rewritten and require an explicit policy; never infer permission from the payload alone.
Recommended Free Tools
Invoke Git with fixed argument arrays, not a shell string containing values from the request. In Node.js, prefer child_process.spawnFile or an equivalent API, set a fixed working directory, impose timeouts, and capture exit status. Validate repository names, refs, and SHAs before passing them to the worker.
Make duplicate deliveries harmless
GitHub can retry a delivery when the endpoint is unavailable or responds too slowly, and operators can redeliver it manually. The delivery ID must therefore be unique in durable storage. Use a unique constraint and a state such as received, running, succeeded, or failed.
- When a new ID arrives, insert it before enqueueing work.
- If the ID already has a completed result, return a 2XX response without repeating the Git mutation.
- If the ID is still running, acknowledge the duplicate and let the existing worker continue.
- If the ID is failed, allow an operator to retry the recorded job under the same delivery identity or create a clearly linked retry record.
Delivery-level idempotency does not solve every race. Two different pushes can target the same branch while workers are running. Serialize jobs per repository and branch, or make the worker re-check the expected commit immediately before activation. A stale job should be marked superseded rather than deploying an older commit after a newer one has completed.
Security hardening checklist
- Terminate TLS at a maintained reverse proxy or managed HTTPS endpoint and keep certificate verification enabled in the webhook settings.
- Generate a high-entropy secret, rotate it deliberately, and support a brief overlap period if zero-downtime rotation is required.
- Verify the raw-body HMAC before trusting any JSON field. Never use the parsed object to reconstruct the signed message.
- Use constant-time signature comparison and reject malformed, missing, or oversized requests.
- Allow-list the exact repository, organization if relevant, branch or tag, event, and action. Ignore validly signed deliveries outside that policy.
- Give the GitHub token only the repository permissions needed to fetch. Give the host service account only access to its checkout, queue, and required deployment actions.
- Keep privileged workers off the public network where possible. The receiver should enqueue data, not expose a command execution endpoint.
- Redact secrets and tokens from logs. Log identifiers and outcomes, not complete payloads by default.
- Rate-limit malformed requests and cap body size. A valid signature does not make an unexpectedly large payload safe to process.
Handle failures and missed deliveries
Receiver failures
A non-2XX response or a timeout tells GitHub that delivery failed. Alert on repeated failures and inspect the delivery details in the repository’s webhook settings. GitHub does not automatically redeliver every failed delivery, so an outage requires an operator or an integration-specific replay process.
Queue and worker failures
Keep the original payload metadata and delivery ID with the job. Retry transient network, DNS, and remote-service errors with bounded exponential backoff. Do not blindly retry authentication failures, signature failures, invalid repositories, or a branch policy violation; those require correction or an operator decision.
Git and build failures
Capture the command’s exit code, stderr, target revision, and working directory identifier. Leave the previous successful deployment active when a new build fails. Mark the job failed, expose a manual retry action, and require a fresh policy check when an operator changes the target ref.
Best Value
Recovery after a prolonged outage
After restoring the receiver, inspect the webhook’s delivery history and replay only the events needed to reach the desired state. For a deployment that always uses the newest approved commit, it can be safer to enqueue the current branch tip once than to deploy every historical push. For an audit-sensitive workflow, preserve and process each delivery in order. The contract must state which behavior applies.
Test the complete path before production
- Send a signed test delivery to a non-production repository and verify that an invalid signature receives a rejection and creates no job.
- Send a valid push for an unapproved branch. Confirm that it is acknowledged but ignored and that no Git command runs.
- Send the same valid delivery twice. The second request must not create a second mutation.
- Delay the worker intentionally while keeping the receiver fast. Confirm the endpoint still answers within the 10-second limit.
- Kill the worker after the delivery record is committed. Restart it and verify that the pending job is recovered.
- Create a non-fast-forward condition and ensure the worker fails without deleting or overwriting the existing checkout.
- Rotate the webhook secret in a staging repository and verify that old and new behavior matches the documented rotation window.
- Test a redelivery after an outage and confirm that logs connect the retry to the original delivery ID.
Use a staging checkout and credentials that cannot affect production. Test repository names, refs, commit SHAs, payload size limits, malformed JSON, and missing headers as well as the normal push path.
When to use Octokit
Octokit’s Node.js webhooks.js toolkit can dispatch event handlers and provides helpers such as webhooks.verify(eventPayload, signature). It can reduce header and event-routing boilerplate, but it does not decide your synchronization contract. Keep repository allow-lists, durable idempotency, queueing, Git commands, deployment permissions, and recovery procedures in your service. Whether you use the helper or the direct HMAC code above, verify the exact raw payload before acting.
Decision guide for a practical design
| If you need… | Prefer… | Design emphasis |
|---|---|---|
| Only one production branch updated automatically | Push-only subscription plus a fast-forward or exact-commit worker. | Strict branch allow-list, per-branch serialization, rollback. |
| Several repositories or environments | One authenticated receiver feeding a queue and workers with repository-specific policies. | Tenant/repository authorization, job isolation, separate credentials. |
| Large builds or deployments | Webhook receiver that triggers an existing CI/deployment system. | Short acknowledgement path and a durable downstream status link. |
| Audit and replay requirements | Durable delivery ledger plus an outbox and explicit operator replay. | Immutable metadata, ordered processing where required, retention rules. |
| Occasional synchronization only | Notification or queue trigger rather than a host that performs every Git operation. | Clear manual recovery and a documented source of truth. |
The reliable pattern is therefore: authenticate the raw request, restrict what it is allowed to mean, record the delivery once, acknowledge quickly, and let a least-privilege worker perform a deterministic Git operation. That design keeps remote projects synchronized without turning a public webhook into an unaudited deployment shell.
Quick Recap
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.

