Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk10 min

How to Deploy a Hugo Site to Production with Git Hooks on a VPS

Use a bare Git repository and a post-receive hook to build Hugo on your VPS, publish clean output and serve it safely through Nginx.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A bare Git repository and a post-receive hook can turn a push to your VPS into a production Hugo deployment. The hook checks out the approved branch into a private workspace, runs Hugo with production settings and destination cleanup, and Nginx serves only the generated files. Keep the repository, build workspace, and public document root separate so source history and build machinery are never exposed.

This design is small enough for a single Ubuntu VPS, yet gives you an auditable Git history and a repeatable release path without a hosted CI service.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What the deployment pipeline does

The VPS runs three separate filesystem roles:

Component Example path Purpose
Bare Git repository /srv/git/site.git Receives pushes and stores Git objects; it has no working tree.
Private checkout/build workspace /srv/build/site Contains the production branch while Hugo reads content, layouts, assets and configuration.
Nginx document root /var/www/site/public Contains only Hugo’s generated HTML, assets, feeds and sitemap.

A developer adds the bare repository as a Git remote and pushes the production branch. Git invokes hooks/post-receive with the old revision, new revision and reference name. The hook ignores every ref except the production branch, checks out that revision, builds Hugo into the document root and exits non-zero if any command fails.

Run the hook as a dedicated deployment account, not as root. Nginx needs read access to the generated tree but should never need access to the repository’s objects or the source checkout.

#1 Best Overall
Sale
TOZO A1 Wireless Earbuds Bluetooth 5.3 Light Weight in Ear Headphones | IPX5 Waterproof,2 Mics for AI Calls,Immersive Premium Sound Bass Headset with Charging Case,32 EQ via App Black
  • [Ultra-Lightweight Ear Buds Designed for Small Ears] Each earbud weighs only 3.7g and features a compact, ergonomic in-ear design made especially for small ears. Secure, low-profile, and comfortable for workouts, all-day wear or overnight sleeping.The ultra-slim profile sits flush in your ear with no hard edges poking or rubbing, so you can even sleep on your side without discomfort.
  • [Immersive Stereo Sound with TOZO OrigX Technology] TOZO OrigX tuning delivers clear vocals, balanced mids, and natural stereo sound for music, podcasts, and videos.
  • [Long Battery Life for Daily Use] Get up to 7 hours of playtime on a single charge, with up to 32 hours total using the charging case—ideal for workdays, commuting, and extended listening sessions.
  • [Bluetooth 5.3 & Stable Connection] Bluetooth 5.3 provides fast pairing, stable wireless performance, and reduced dropouts as you move around home or office.
  • [Deep Bass with Clear Vocals] High-performance drivers produce punchy bass while keeping vocals clean and detailed for everyday listening.

Prerequisites and decisions

  • An Ubuntu or comparable Linux VPS with SSH access and a DNS name pointing at it.
  • Git, Nginx and a Hugo binary installed on the server.
  • A production branch name, such as main. The hook below accepts only refs/heads/main.
  • A deployment SSH key used only for this repository. Keep your personal login key separate.
  • A decision about ownership of generated files. The simplest arrangement is to let the deployment account write the destination while Nginx has read and directory-traverse permission.

Choose the smallest Hugo Linux edition that supports your site. The available editions are standard, deploy, extended and extended/deploy. Sass processing requires an extended edition. Hugo’s direct object-storage deployment features require a deploy edition. A VPS hook that only builds files for Nginx normally needs standard unless the site’s modules or asset pipeline require more.

Create the deployment account and directory layout

Create a system account with no administrative role. The exact account-management command varies by distribution; on Ubuntu, an example is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo adduser --system --group --home /srv/deploy deploy
sudo mkdir -p /srv/git /srv/build/site /var/www/site/public
sudo chown -R deploy:deploy /srv/git /srv/build
sudo chown -R deploy:www-data /var/www/site
sudo chmod 0755 /var/www/site /var/www/site/public

Keep /srv/git and /srv/build outside Nginx’s configured web root. If you use a different account or group, substitute those names consistently in the repository, SSH configuration, hook and Nginx permissions.

Initialize the bare repository

Initialize the repository as the deployment account. A bare repository has Git metadata at its top level and deliberately does not contain checked-out files.

sudo -u deploy git init --bare /srv/git/site.git

On your development machine, add the SSH remote and push the branch that should publish:

git remote add production deploy@example-vps:/srv/git/site.git
git push production main

Replace the host, account and branch with your values. The first push creates the branch that the hook will later check out.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Smart Watch for Men Women Compatible with iPhone Samsung Android Phone 1.69 inch Full Touch Screen IP68 Waterproof Bluetooh Fitness Tracker Heart Rate/Sleep Monitor (Black)
  • 【IP68 Waterproof Multifunctinal Smart Watch】Torjalph fitness activity tracker smart watch is IP68 waterproof technology ,you can wear it when swimming,handwashing,it's rain-proof which means that you perform multiple exercise modes outside without worrying about sweat or rain corroding your fitness smart watch,and this watch equipped with a 230 mAh large capacity battery magnetic charging ,and this sports activity tracker watch can be used 5-7 days If fully charged.
  • 【Larger 1.83'' Full Screen Watch & Multi-dial Selection】1.83 inch full HD color touch screen smart watch for men / women provides excellent 240*284 resolution image quality ,This Bluetooth smart watch offers a better touch experience and remarkable immersion and ,more than 200 watch faces for you to choose from App"Da Fit ", you can change the dial style according to your mood to wear keeping the world on your wrist
  • 【Accurate Activity Tracker Smart Watch 】sports watch activity tracker uses sweat and dust resistant breathable silicone strap, our Fitness Tracker Smart Watch for Android iOS Phones supports 12 sports modes,walking,running,bicycle,swimming,badminton,basketball,football,rope skipping. This bluetooth calls smart watch for men women is lightweight and stylish, bringing more convenient and relaxing sports experience while also providing more protection.
  • 【Your 24 Hour Personal Daily Health Monitor】Fitness watch for women men full touch screen IP67 waterproof bluetooth smartwatch for Android iOS Phones with heart rate blood pressure monitor multifunction Andriod smart watch with steps counter sleep monitor sports fitness watch, monitoring blood oxygen saturation allows you to understand your physical condition in real time to track fitness progress ,to know your health status in time.
  • 【More Functions Bluetooth Call Smart Watch】This fitness activity smart watch full screen for iPhone and Android phones includes a bunch of new features including:The bluetooth smart watch can hang up the phone, receive and display WhatsAPP /Text /Facebook /Twitter /Messenger reminder.Support sedentary reminder, alarm clock, stopwatch, timer,weather information,music control, remote camera control compatible with Android 5.0 and above or iOS 9.0 and above smartphones.

Restrict the deployment SSH key

Place a dedicated public key in /srv/deploy/.ssh/authorized_keys. Restrict it to the single Git receive command and disable interactive features. A forced-command entry can be written as follows; adjust the repository path exactly:

command="case $SSH_ORIGINAL_COMMAND in git-receive-pack\ /srv/git/site.git) exec git-receive-pack /srv/git/site.git;; *) exit 1;; esac",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAA... deployment-key

The escape sequences shown as $ and \ preserve the shell variables and spaces when the key line is parsed. Generate a real key pair, replace the placeholder public key, and test that a normal shell session is rejected. If your Git or OpenSSH packaging provides a repository-specific git-shell restriction, use it in addition to the forced command.

Do not give this account sudo merely to make the hook convenient. If changing ownership with chown is not permitted, preconfigure the destination group and permissions so the deployment account can replace generated files without privilege escalation.

Install and verify Hugo

Install the edition and version appropriate for the site’s modules. Confirm the binary location and version as the deployment account or with the same absolute path the hook will use:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
/usr/local/bin/hugo version

Using an absolute path avoids a different non-interactive SSH PATH from selecting another binary. Build the site once manually from the checkout to expose missing modules, themes or permissions before automating it.

Write the post-receive hook

Create /srv/git/site.git/hooks/post-receive, make it executable, and run it as deploy. This implementation follows the bare-repository, private-checkout and separate-destination layout:

Rank #3
New Bee Guitar Cable 10ft Electric Instrument Bass AMP Cord
  • [Low Noise High Fidelity] New bee guitar cord with 22AWG oxygen-free-copper center conductors provides enhanced signal transfer, the PVC insulation material and the high-density stranded copper double shield provide noise rejection for quiet operation
  • [Ideal for Choice] New bee 1/4 straight and right angle metal connectors, ensures a secure connection in any instrument, pedal, or amp jack. L shape great fro on stage guitar stands
  • [Wide Compatible] Suitable for mixer, power amplifier, microphone, effector, decoder, equalizer, electoronic organ, electric guitar, electric bass and other electronic equipments. Widely used in the installation of smart home, karaoke speaker, professional stage audio, etc
  • [Easy Disassemble] Making incidental repairs quick and easy! Very nice, flexible cable
  • [Dont Hesite to Order] 24 hours customer services and professional technology team are standing by
#!/bin/sh
set -eu
REPO=/srv/git/site.git
WORK=/srv/build/site
DEST=/var/www/site/public
BRANCH=refs/heads/main

while read oldrev newrev refname; do
  [ "$refname" = "$BRANCH" ] || continue
  git --work-tree="$WORK" --git-dir="$REPO" checkout -f main
  /usr/local/bin/hugo --source "$WORK" --destination "$DEST" --cleanDestinationDir --environment production
  chown -R www-data:www-data "$DEST"
done
sudo chown deploy:deploy /srv/git/site.git/hooks/post-receive
sudo chmod 0755 /srv/git/site.git/hooks/post-receive

Why each line matters

  • set -eu stops on an error and treats an unset variable as an error, so a failed Hugo build cannot be reported as a successful push.
  • The ref comparison is a fail-closed branch gate. Tags, feature branches and unrelated references do not publish.
  • checkout -f updates the private workspace to the received branch. Do not put user-uploaded or hand-edited files in that workspace; Git will overwrite tracked files on the next deployment.
  • --source identifies the checkout, while --destination identifies the tree Nginx serves.
  • --cleanDestinationDir removes generated files that no longer correspond to the current build.
  • --environment production lets configuration select production URLs, analytics or other environment-specific values.
  • The ownership change is optional when the destination is already writable by the deployment account and readable by Nginx. If you retain it, ensure the account is allowed to perform it; otherwise the hook will fail after a successful build.

You can set cleanDestinationDir in Hugo configuration instead of passing the flag, but using the flag in the production hook makes the cleanup policy visible in the deployment code.

Why destination cleanup is mandatory

Hugo does not automatically remove every old output path unless destination cleaning is enabled. A page can disappear because it was deleted, renamed, changed to a draft, expired or given a future publication date. Without cleanup, its previous HTML can remain publicly reachable even though the source no longer publishes it. Run a clean build on every production deployment, not only after major reorganizations.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure Nginx to serve only generated output

Create a server block whose root is the Hugo destination, not the repository or source checkout:

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/site/public;

    location / {
        try_files $uri $uri/ =404;
    }
}

Configure TLS for the hostname using your distribution’s supported certificate process. Validate the complete Nginx configuration before reloading:

sudo nginx -t
sudo systemctl reload nginx

Reload only after the test succeeds. Never place /srv/git or /srv/build under the server’s root, and do not add an alias that exposes them.

Perform the first deployment safely

Use a harmless content or layout change for the first automated push. Verify each stage rather than assuming a successful SSH exit means the site is correct.

Rank #4
BSIMB 15.6" Digital Family Calendar & Chore Chart, No Subscription Fees
  • Digital Family Calendar: BSIMB digital calendar wall touch screen puts an end to your chaotic life. Designed for busy families, the digital calendar keeps you organised and in step with your family. Assign different colours and tasks to each family member to make family scheduling easier and more intuitive.
  • Easy Setup and Auto-Sync: Plug in, connect to WLAN and auto-syn your electric calendar in minutes. Digital wall calendar compatible with Google calendar, iCloud calendar, Outlook calendar, Cozi calendar and Yahoo calendar. Add events directly on the device or through the ecalendar app. Electronic calendar stays current whether you're at work or traveling—no manual updates needed.
  • All-In-One Home Assistant: Smart calendar builds habits and encourage independence with personalised chores. Display daily meal plan to reduce the daily ‘What's for dinner?’ stress. To-do lists keep track of everything you want. Turning chores into valuable achievements with stars and rewards, making life easier and more enjoyable.
  • Manage Anytime Anywhere: BSIMB electronic calendar for family stay connected with the powerful ecalendar app. Access and manage your digital wall calendar anytime, anywhere with free features like stars & rewards, photo screensaver, chore charts, meals plans, to-do lists etc. Electronic planner paid features like Magic Import tailor advanced tools for users with special needs.
  • Stay in Touch with Loved Ones: Share photos or videos from your phone to electronic wall calendar with app, instantly update your life moment, and keep in touch with your family, especially those who are far away; you can also surprise your smart calendar digital wall by sending him a wish card; it's also great for keeping tech-illiterate elders in touch with the youngsters.
  1. Push the production branch to the restricted remote.
  2. Confirm the remote output shows the receive operation and that the hook exits successfully.
  3. Inspect the hook’s captured output or service logs. Hugo warnings and errors must be visible somewhere an operator can review.
  4. Check that the deployment account, not root, owns the hook process and workspace.
  5. Inspect /var/www/site/public for index.html, expected assets, feeds and the sitemap.
  6. Open the site through its public hostname and confirm Nginx serves the new revision.
  7. Delete or rename a test page, push again and verify the old URL is gone after the clean build.
  8. Introduce a controlled build error in a disposable change. Confirm the hook reports failure and that the previously good output remains available; restore the valid revision immediately afterward.

These checks establish the behavior you need before relying on the pipeline for real releases.

Make failed releases and rollbacks predictable

The sample hook writes directly into the live destination. For a higher-assurance site, build into a staging directory first, verify the command succeeds, then replace the live directory in one controlled operation. Keep the staging directory under /srv/build, never under the public root. This prevents a syntax or template error from replacing a working site with incomplete output. Test the replacement and permissions on a non-production revision before adopting it.

For a simple rollback, identify the last known-good commit and republish that revision through the same hook. If your remote accepts non-fast-forward updates, a deliberate force push is:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
git push --force production GOOD_COMMIT:main

Use this only when your team understands the history change. An alternative is to check out the known-good commit in the deployment workspace and run Hugo manually, then restore the branch to its intended head. Keep release commit IDs in your change log so the rollback target is unambiguous.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Operational hardening

  • Use file and directory permissions that give Nginx read and traverse access but no write access to source or Git metadata.
  • Keep the deployment key on the build workstation or operator machine that needs to publish; do not copy its private half to the VPS.
  • Log both Git hook output and Hugo output. A silent hook turns a broken publication into a guessing exercise.
  • Prevent overlapping deployments. Two simultaneous pushes can race while checking out the workspace or writing the destination; serialize hooks with a deployment lock or an equivalent service-level mechanism.
  • Monitor disk space in the Git repository, build workspace and destination. A full filesystem can look like a template or permission failure.
  • Review the production configuration for absolute URLs, environment variables and any secrets. Static output is public once Nginx serves it, so never put credentials in content or generated files.
  • Keep the Hugo binary and themes/modules on a controlled update schedule. Upgrade in a test branch first and record the version used for each release.

Common failures and fixes

The push succeeds but nothing changes

Check that the pushed ref is exactly refs/heads/main. A push of another branch is intentionally ignored. Then verify the hook is executable, owned by the deployment account and installed in the bare repository’s hooks directory rather than in the checkout.

The hook says Hugo is not found

Non-interactive SSH sessions often have a minimal PATH. Use the absolute Hugo path in the script and verify it with the deployment account.

Nginx returns 403 or 404

Confirm the server block’s root matches the destination, the generated files exist, and every parent directory grants Nginx execute permission. Run nginx -t after changes and inspect the Nginx error log for the exact path it attempted.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Old URLs remain online

Confirm that the hook includes --cleanDestinationDir or that configuration enables cleanDestinationDir. Also check whether another process is copying files into the destination after Hugo finishes.

The build fails on Sass or a module

Install an extended Hugo edition when Sass is required, and ensure the module dependencies and theme are available in the checkout. Select an extended/deploy edition only when the site needs both extended processing and Hugo’s direct deployment features.

The hook fails at the ownership step

Either preconfigure the destination so the deployment account can write it and Nginx can read it, or arrange a narrowly scoped privileged mechanism for that one operation. Do not grant broad shell privileges to the deployment account.

Choosing this design versus other Hugo deployment methods

Hugo’s documentation describes two broad methods: push source code to a Git repository and let a hosting platform build and deploy it, or build locally and transfer the generated files to the host. A VPS hook is the self-hosted version of the first pattern.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Approach Build environment Strengths Trade-offs
VPS bare repo and hook Your VPS Direct push-to-publish flow, full filesystem control, no separate CI service required, and Git history on your infrastructure. You maintain the server, Hugo installation, SSH restrictions, logs, backups and concurrency controls.
Managed Git CI/CD Hosted runner Less server maintenance, disposable build environments and easier preview workflows when the provider supports them. Secrets and build permissions live in a third-party service; runner configuration and artifact transfer add moving parts.
Local build plus transfer Your workstation Very simple server requirements and an explicit generated artifact. Releases depend on the operator’s local Hugo version and machine; auditability and repeatability are weaker unless you standardize them.
hugo deploy to object storage Where you run Hugo Supports targets such as Amazon S3, Azure Blob Storage and Google Cloud Storage, with dry-run, confirmation, deletion-limit, worker and CDN-invalidation controls. Requires object-storage configuration and an appropriate deploy edition; it is a different hosting model from Nginx on a VPS.

Choose the hook when the VPS is already your operational boundary and a small, transparent release mechanism matters more than hosted previews. Choose managed CI when you want the provider to maintain runners and you accept its secret-handling model. Use object storage when the site’s delivery architecture is already built around a bucket and CDN rather than a long-running web server.

Production checklist

  • Dedicated deployment account with no interactive shell or broad administrative privileges.
  • Bare repository, private checkout and Nginx document root at separate paths.
  • SSH key restricted to the one git-receive-pack command and repository.
  • Hook executable, branch-gated and using an absolute Hugo path.
  • Clean destination enabled for every production build.
  • Nginx root points only to generated output; configuration passes nginx -t.
  • Logs make Git and Hugo failures visible.
  • First push verifies generated assets, deleted-page cleanup, permissions and recovery behavior.
  • A documented known-good commit and rollback procedure exist.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.