Hugo 0.169.0 on AWS User Guide
Overview
This guide covers launching and using the Hugo 0.169.0 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg developer and API tools listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
Hugo is a static site generator: you write pages in Markdown, Hugo turns them into plain HTML, CSS and images, and a web server hands those files out. There is no database and no application server to keep patched, which makes a Hugo site fast and hard to break into.
The cloudimg image is a complete Hugo web server, not just the hugo command:
- A site that is live on first boot, over HTTPS. First boot generates a certificate for your instance, renders the starter site for your instance's address and starts nginx. Port 80 only redirects to HTTPS.
- Edit a file and the site updates itself. The site's source is in
/var/www/hugo, owned by a dedicatedhugoaccount. Change a page, add a post or adjust the stylesheet andhugo-publishrenders and publishes the new site within seconds. A render that fails leaves the previous site online. - nginx serves only the finished pages. Your source files,
hugo.toml, drafts, templates and any dotfile (/.git,/.env) are never served, however the address is spelled. The site answersGETandHEADonly and takes no request bodies, so there is nothing on it to post to. - The build cannot reach into your AWS account. Hugo renders in a locked-down service under the
hugoaccount: no privileges, a read-only view of the system except the site folder, and no network route to the EC2 instance metadata service, to the instance's own services or to private addresses in your VPC. Hugo's own security policy is tightened too: templates cannot fetch remote URLs or read environment variables unless you turn that on. - Built from source with current dependencies. Hugo 0.169.0 extended (with its built-in Sass compiler) is compiled from the official source with Go 1.27.3 and a patched
golang.org/x/net, and the build fails unlessgovulncheckreports no vulnerabilities. No compiler or Go toolchain is left on the image. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Hugo 0.169.0 extended (/opt/hugo/bin/hugo, on the PATH as hugo), a starter site in /var/www/hugo (a pristine copy is kept in /opt/hugo/starter-site), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The build record and the licence notices are in /usr/share/doc/cloudimg-hugo/. cloudimg also masks the fwupd-refresh timer (EC2 has no firmware it can update).
Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 22 (SSH), TCP 443 (the website) and TCP 80 (redirects to HTTPS). Open 443 and 80 to everyone who should see the site, and 22 to your own networks only.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Hugo 0.169.0 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair, a security group as above and a subnet.
With the AWS CLI (replace the values in angle brackets):
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hugo}]'
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Hugo 0.169.0 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot takes under a minute: it generates the certificate, loads the outbound fence, renders the starter site for your instance's address and starts nginx. Check that everything is running:
systemctl is-active nginx hugo-publish.path hugo-publish.timer hugo-egress-guard hugo-firstboot \
&& sudo test -f /var/lib/cloudimg/hugo-firstboot.done && echo FIRSTBOOT_DONE
active
active
active
active
active
FIRSTBOOT_DONE
Only SSH and nginx listen on the network. Hugo itself never listens on a port: it runs only to render the site and then exits.
sudo ss -lntp | awk 'NR>1 && $4 !~ /^127\.0\.0\.5[34]/ {print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u | tee /dev/stderr \
| awk '{sub(/.*:/, "", $1); print $1}' | sort -un | xargs | grep -qx '22 80 443' && echo "network listeners: 22 80 443"
0.0.0.0:22 users:(("sshd"),("systemd"))
0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
[::]:22 users:(("sshd"),("systemd"))
[::]:443 users:(("nginx"),("nginx"),("nginx"))
[::]:80 users:(("nginx"),("nginx"),("nginx"))
network listeners: 22 80 443
Step 4: Open your site
Your site is at https://<public-ip>/. First boot records the address and the certificate details in /var/lib/cloudimg/hugo-endpoints.txt; nothing in it is secret, and the site has no password because it is a public website:
sudo sed -n 's/^\(HUGO_[A-Z0-9_]*\)=.*/\1/p' /var/lib/cloudimg/hugo-endpoints.txt | tee /dev/stderr | grep -qx HUGO_URL && echo "address recorded"
HUGO_HOST
HUGO_URL
HUGO_TLS_SHA256_FINGERPRINT
HUGO_TLS_CERT
address recorded
Run sudo cat /var/lib/cloudimg/hugo-endpoints.txt to see the values. The certificate is self-signed and generated on your instance, so your browser warns about it the first time: compare its SHA-256 fingerprint with HUGO_TLS_SHA256_FINGERPRINT before you accept it, or put your own domain and a CA-issued certificate on the site (Step 10). You can also check the site from the instance itself:
H=$(sudo sed -n 's/^HUGO_HOST=//p' /var/lib/cloudimg/hugo-endpoints.txt)
curl -s --cacert /etc/ssl/hugo/hugo.crt --resolve "$H:443:127.0.0.1" "https://$H/" | grep -oE '<title>[^<]*</title>|<h1[^>]*>[^<]*</h1>' | tee /dev/stderr \
| grep -q 'Your Hugo site is live' && echo "the site is live over HTTPS"
<title>Hugo on cloudimg</title>
<h1>Your Hugo site is live</h1>
the site is live over HTTPS
This is the starter site as your browser shows it. Its pages explain where everything lives and how publishing works:


The site's source is the folder /var/www/hugo:
| Path | What it is |
|---|---|
/var/www/hugo/content |
your pages, one Markdown file per page (posts/ holds the blog posts) |
/var/www/hugo/layouts |
the HTML templates |
/var/www/hugo/assets/scss |
the stylesheet source, compiled by Hugo's built-in Sass |
/var/www/hugo/static |
files copied into the site as they are (images, downloads, favicon.ico) |
/var/www/hugo/hugo.toml |
the site configuration, including Hugo's security policy |
/var/www/hugo/public |
the generated site nginx serves; it is replaced on every publish, so do not edit it |
The templates and the stylesheet were written by cloudimg for this image and are yours to change or delete; no third-party theme is included. Hugo's cache of generated resources (the compiled stylesheet, processed images) is kept in /var/cache/hugo-publish, outside the source, so the source folder holds only what you wrote.
Step 5: Edit a page
The source belongs to the hugo account, so edit it as that account: sudo -u hugo -e /var/www/hugo/content/about.md opens the About page in your editor and saves it back with the right owner (set EDITOR=nano first if you prefer nano to vi).
Save the file and the site republishes itself within seconds: hugo-publish.path watches the source folders, and hugo-publish.timer catches anything else once a minute. Here the title of the About page is changed with sed instead of an editor, and the new page is fetched over HTTPS until it appears:
sudo -u hugo sed -i 's/^title: "About this appliance"$/title: "About this site"/' /var/www/hugo/content/about.md
H=$(sudo sed -n 's/^HUGO_HOST=//p' /var/lib/cloudimg/hugo-endpoints.txt)
timeout 60 bash -c "until curl -s --cacert /etc/ssl/hugo/hugo.crt --resolve '$H:443:127.0.0.1' 'https://$H/about/' | grep -q '<h1>About this site</h1>'; do sleep 1; done" \
&& echo "the edited page is live at https://$H/about/"
the edited page is live at https://<public-ip>/about/

Step 6: Add a post
A post is one Markdown file in /var/www/hugo/content/posts/ with a short header (the "front matter") giving its title and date. Posts with a date in the future, and posts marked draft: true, are not published until you change that:
sudo -u hugo tee /var/www/hugo/content/posts/my-first-post.md > /dev/null <<'MD'
---
title: "My first post"
date: 2026-11-07
---
Hello from my new Hugo site.
MD
H=$(sudo sed -n 's/^HUGO_HOST=//p' /var/lib/cloudimg/hugo-endpoints.txt)
timeout 60 bash -c "until curl -s --cacert /etc/ssl/hugo/hugo.crt --resolve '$H:443:127.0.0.1' 'https://$H/posts/my-first-post/' | grep -q 'Hello from my new Hugo site.'; do sleep 1; done" \
&& curl -s --cacert /etc/ssl/hugo/hugo.crt --resolve "$H:443:127.0.0.1" "https://$H/posts/" | grep -o 'My first post' | head -n 1
My first post
The new post is at https://<public-ip>/posts/my-first-post/ and at the top of the posts list:

To remove a post, delete its file (sudo -u hugo rm /var/www/hugo/content/posts/<name>.md) and it disappears from the site on the next publish.
Step 7: Publish by hand and read the publish log
sudo hugo-publish renders and publishes the site at once, even when nothing has changed, and prints Hugo's own report. It is the quickest way to see an error in a page or a template:
sudo hugo-publish | tee /dev/stderr | grep -q '^hugo-publish: published [0-9]* page(s) for https://' && echo "published"
Start building sites …
hugo v0.169.0+extended linux/amd64 BuildDate=unknown VendorInfo=cloudimg
WARN deprecated: css.Sass: libsass was deprecated in Hugo v0.153.0 and will be removed in a future release. Use dartsass instead. See https://gohugo.io/functions/css/sass/#dart-sass
│ EN
──────────────────┼────
Pages │ 12
Paginator pages │ 0
Non-page files │ 0
Static files │ 0
Processed images │ 0
Aliases │ 0
Cleaned │ 0
Total in 35 ms
hugo-publish: published 8 page(s) for https://<public-ip>/
published
The WARN line is expected: the starter stylesheet is compiled with LibSass, which is what Hugo extended has built in (see Step 9). Every automatic publish is logged too:
sudo journalctl -u hugo-publish.service --since -10min --no-pager -o cat | grep '^hugo-publish:' | tail -n 3
hugo-publish: published 7 page(s) for https://<public-ip>/
hugo-publish: published 8 page(s) for https://<public-ip>/
hugo-publish: published 8 page(s) for https://<public-ip>/
Hugo renders into a staging folder and the result replaces the live site only when the render succeeds, so a mistake never takes the site down. Here a broken template is added, the publish fails, the site keeps serving the last good version, and the site publishes again once the template is removed:
echo '{{ .Title ' | sudo -u hugo tee /var/www/hugo/layouts/broken.html > /dev/null
H=$(sudo sed -n 's/^HUGO_HOST=//p' /var/lib/cloudimg/hugo-endpoints.txt)
{ if sudo hugo-publish > /dev/null 2>&1; then echo "published"; else echo "render failed: nothing published"; fi
curl -s --cacert /etc/ssl/hugo/hugo.crt --resolve "$H:443:127.0.0.1" "https://$H/posts/my-first-post/" | grep -q 'Hello from my new Hugo site.' && echo "the previous site is still online"
} | tee /dev/stderr | tr '\n' ' ' | grep -qx 'render failed: nothing published the previous site is still online ' \
&& sudo -u hugo rm /var/www/hugo/layouts/broken.html && sudo hugo-publish > /dev/null && echo "fixed and published again"
render failed: nothing published
the previous site is still online
fixed and published again
When an automatic publish fails, sudo journalctl -u hugo-publish.service -n 50 shows Hugo's error message.
Step 8: Upload a site you already have
If you already keep a Hugo site in Git or on your computer, copy its source to the instance and let the hugo account move it into place. From your own machine (leave out the generated public/ and resources/ folders):
rsync -a --exclude public/ --exclude resources/ --exclude .git/ ./my-site/ ubuntu@<public-ip>:/tmp/my-site/
Then on the instance, copy it over the starter as hugo with sudo -u hugo rsync -a --delete --exclude '/public/' --exclude '/resources/' --exclude '/.publish-*' /tmp/my-site/ /var/www/hugo/ and publish it with sudo hugo-publish. Copying as hugo keeps every file owned by the publishing account, and --delete removes the starter pages your site does not have.
Things to check in your site's own hugo.toml:
- Leave out
baseURL(or leave it as it is):hugo-publishalways renders for the instance's address, or for your domain once you set one (Step 10). - Keep cloudimg's
[security]block from the end of the starterhugo.toml(the starter keeps a pristine copy in/opt/hugo/starter-site/hugo.toml). Without it, Hugo falls back to its own looser defaults. - Theme: put the theme's files in
themes/<name>/(a plain copy or a Git checkout made on your machine) and settheme = "<name>".
Symbolic links that point outside /var/www/hugo are refused: a publish stops with an error rather than copy a file from elsewhere on the instance into your public site.
Step 9: Themes, Sass and Hugo Modules
This is Hugo extended, so themes that compile SCSS with css.Sass (or the older resources.ToCSS) work: Hugo's built-in LibSass 3.6.6 compiles them. Hugo deprecated LibSass in v0.153.0 in favour of Dart Sass, which is why hugo-publish prints a WARN line; it still compiles normally in 0.169.0. Dart Sass is not installed. If a theme needs it, install the sass binary from the Dart Sass releases into /usr/local/bin and set transpiler = "dartsass" in the theme's css.Sass options; the security policy already allows Hugo to run it.
The security policy at the end of hugo.toml is tighter than Hugo's defaults:
hugo version
sed -n '/^\[security\]/,$p' /var/www/hugo/hugo.toml
hugo v0.169.0+extended linux/amd64 BuildDate=unknown VendorInfo=cloudimg
[security]
enableInlineShortcodes = false
[security.exec]
allow = ['^(dart-)?sass$']
osEnv = ['(?i)^(PATH|TE?MP|HOME|LANG)$']
[security.funcs]
getenv = ['none']
[security.http]
urls = ['none']
http.urls = none: templates cannot fetch anything from the network withresources.GetRemote(Hugo's default allows any URL).funcs.getenv = none: templates cannot read environment variables (Hugo's default allowsHUGO_*andCI).exec.allow: Hugo may run only the Dart Sass binary. Hugo's default also allows Go, Git, Node and PostCSS, none of which is installed here.
Hugo Modules (hugo mod get, themes imported with [module] imports) need Go and Git, which are not on the image, and network access that the policy turns off. Use themes as a folder in themes/ instead, or vendor the modules on your machine with hugo mod vendor and copy the _vendor/ folder up with your site. If you do widen the policy, widen exactly the list you need (see Hugo's documentation on security configuration); the outbound fence in Step 12 still applies.
Step 10: Use your own domain name or certificate
Point a DNS record at the instance, then set the name. The helper generates a new certificate for the name (and the instance's addresses), pins nginx to those names (other host names get no answer) and republishes the site so every link uses the new name:
sudo hugo-set-hostname <your-domain>
To use a CA-issued certificate instead of the self-signed one, replace /etc/ssl/hugo/hugo.crt and /etc/ssl/hugo/hugo.key with your own (keep the key root only, mode 0600) and run sudo systemctl reload nginx. If the instance's public IP address changes after a stop and start, run sudo hugo-set-hostname with the new address, or use an Elastic IP address.
Step 11: What the web server refuses
nginx serves only the generated site, only for GET and HEAD, and never your source. Every other method gets 405, the source files, hugo.toml and dotfiles get 404 however the address is spelled, folders have no file listing, plain HTTP only redirects, and unknown host names get no answer:
H=$(sudo sed -n 's/^HUGO_HOST=//p' /var/lib/cloudimg/hugo-endpoints.txt)
C=(curl -s -o /dev/null --cacert /etc/ssl/hugo/hugo.crt --resolve "$H:443:127.0.0.1")
{
"${C[@]}" -w 'GET /: %{http_code}\n' "https://$H/"
"${C[@]}" -w 'POST /: %{http_code}\n' -X POST -d 'x=1' "https://$H/"
"${C[@]}" -w 'PUT /posts/: %{http_code}\n' -X PUT -d 'x=1' "https://$H/posts/"
"${C[@]}" -w '/hugo.toml: %{http_code}\n' "https://$H/hugo.toml"
"${C[@]}" -w '/content/about.md: %{http_code}\n' "https://$H/content/about.md"
"${C[@]}" -w '/.git/config: %{http_code}\n' "https://$H/.git/config"
"${C[@]}" -w '/%2Eenv: %{http_code}\n' "https://$H/%2Eenv"
"${C[@]}" -w 'folder without an index (/css/): %{http_code}\n' "https://$H/css/"
curl -s -o /dev/null -w 'plain http: %{http_code}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -o /dev/null -w 'unknown host name: %{http_code}\n' --resolve "other.example:443:127.0.0.1" https://other.example/ || true
} | tee /dev/stderr | tr '\n' ' ' | grep -qx 'GET /: 200 POST /: 405 PUT /posts/: 405 /hugo.toml: 404 /content/about.md: 404 /.git/config: 404 /%2Eenv: 404 folder without an index (/css/): 404 plain http: 301 unknown host name: 000 ' && echo "all refused as expected"
GET /: 200
POST /: 405
PUT /posts/: 405
/hugo.toml: 404
/content/about.md: 404
/.git/config: 404
/%2Eenv: 404
folder without an index (/css/): 404
plain http: 301
unknown host name: 000
all refused as expected
Every response also carries security headers:
H=$(sudo sed -n 's/^HUGO_HOST=//p' /var/lib/cloudimg/hugo-endpoints.txt)
curl -sI --cacert /etc/ssl/hugo/hugo.crt --resolve "$H:443:127.0.0.1" "https://$H/" | tr -d '\r' \
| grep -iE '^(strict-transport-security|x-content-type-options|x-frame-options|referrer-policy|content-security-policy|permissions-policy):' | sort | tee /dev/stderr \
| grep -qi '^x-content-type-options: nosniff$' && echo "security headers present"
content-security-policy: frame-ancestors 'self'; object-src 'none'; base-uri 'self'
permissions-policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
referrer-policy: strict-origin-when-cross-origin
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
security headers present
The content security policy only limits framing, plugins and the <base> tag, so your own scripts, styles and embeds keep working. Add stricter headers in /etc/nginx/conf.d/ if your site allows it.
Step 12: The build sandbox and the outbound fence
Hugo renders in hugo-publish.service, which runs as the unprivileged hugo account with no capabilities, a read-only view of the system and write access to /var/www/hugo only:
systemctl show hugo-publish.service -p User -p NoNewPrivileges -p ProtectSystem -p ProtectHome -p ReadWritePaths -p PrivateDevices -p CapabilityBoundingSet
systemd-analyze security hugo-publish.service 2>/dev/null | tail -n 1 | tee /dev/stderr | grep -q 'Overall exposure level for hugo-publish.service: 1\.[0-9] OK' && echo "sandboxed"
CapabilityBoundingSet=
User=hugo
ReadWritePaths=/var/www/hugo
PrivateDevices=yes
ProtectHome=yes
ProtectSystem=strict
NoNewPrivileges=yes
→ Overall exposure level for hugo-publish.service: 1.4 OK :-)
sandboxed
A site generator can be told to fetch URLs while it renders, so the image fences what the hugo account can connect to, even if you widen Hugo's own policy. The service refuses the EC2 instance metadata service, link-local and private addresses, loopback and multicast (IPAddressDeny), and a firewall rule for the hugo account rejects the same set outside the service too, allowing only DNS to the local resolver. You can see both fences, and watch hugo fail to reach the metadata service, this instance's own address and loopback while the public internet still works:
systemctl show -p IPAddressDeny --value hugo-publish.service | tr ' ' '\n' | sort -V
sudo nft list table inet cloudimg_hugo_egress | grep -oE 'oifname "lo" .*(accept|reject)|ip6? daddr \{[^}]*\} counter packets [0-9]+ bytes [0-9]+ reject' | sed -E 's/counter packets [0-9]+ bytes [0-9]+ //'
P=$(ip -4 -o addr show scope global | awk '{sub(/\/.*/, "", $4); print $4; exit}')
{ sudo -u hugo curl -s -m 5 -o /dev/null -w 'hugo -> metadata service: %{http_code}\n' http://169.254.169.254/latest/meta-data/
sudo -u hugo curl -s -m 5 -o /dev/null -w "hugo -> this instance's private address: %{http_code}\n" "https://$P/"
sudo -u hugo curl -s -m 5 -o /dev/null -w 'hugo -> loopback: %{http_code}\n' http://127.0.0.1/
sudo -u hugo curl -s -m 10 -o /dev/null -w 'hugo -> the public internet: %{http_code}\n' https://www.cloudimg.co.uk/
} | tee /dev/stderr | tr '\n' ' ' | grep -qx "hugo -> metadata service: 000 hugo -> this instance's private address: 000 hugo -> loopback: 000 hugo -> the public internet: 200 " && echo "fenced"
0.0.0.0/8
10.0.0.0/8
100.64.0.0/10
127.0.0.0/8
168.63.129.16/32
169.254.0.0/16
172.16.0.0/12
192.168.0.0/16
224.0.0.0/4
fc00::/7
fe80::/10
ff00::/8
::1/128
oifname "lo" ip daddr 127.0.0.53 udp dport 53 accept
oifname "lo" ip daddr 127.0.0.53 tcp dport 53 accept
oifname "lo" ct state new reject
ip daddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 168.63.129.16, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16, 224.0.0.0/4 } reject
ip6 daddr { fc00::/7, fe80::/10, ff00::/8 } reject
hugo -> metadata service: 000
hugo -> this instance's private address: 000
hugo -> loopback: 000
hugo -> the public internet: 200
fenced
The metadata service address 169.254.169.254 is inside 169.254.0.0/16, and its IPv6 address fd00:ec2::254 is inside fc00::/7. nginx is also kept away from the metadata service. The fence applies only to the hugo account and nginx: your own SSH session, the AWS Systems Manager agent and package updates are not affected.
Step 13: Run the self-test
The image ships a self-test that checks the Hugo binary and its security policy, renders your current source as hugo into a scratch folder, compares what nginx serves with the published files, and checks the request policy, the listening ports, the certificate and the publishing units:
sudo hugo-selftest | tail -n 1 | tee /dev/stderr | grep -qx HUGO_SELFTEST_OK
HUGO_SELFTEST_OK
If it prints BROKEN-<reason> lines instead, they name what to look at.
Step 14: Security notes and the build record
The certificate generated at first boot is a server certificate only: it cannot sign other certificates.
openssl x509 -in /etc/ssl/hugo/hugo.crt -noout -ext basicConstraints,keyUsage,extendedKeyUsage | tee /dev/stderr | grep -q 'CA:FALSE'
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
The binary is the one the build record describes: Hugo 0.169.0 extended, built from the official module with Go 1.27.3 and golang.org/x/net v0.62.0 (Hugo 0.169.0 itself pins v0.61.0, which is affected by GO-2026-6860 and GO-2026-6866). The build failed unless govulncheck reported no vulnerabilities, and no Go toolchain or C compiler is left on the image. BUILD-INFO.txt also records the module, dependency and toolchain checksums:
(cd / && sha256sum -c /usr/share/doc/cloudimg-hugo/SHA256SUMS) \
&& sed -n '1p;3p;6,7p' /usr/share/doc/cloudimg-hugo/BUILD-INFO.txt \
&& { command -v go gcc cc || echo "no Go toolchain or C compiler"; } | grep -qx 'no Go toolchain or C compiler' && echo "no Go toolchain or C compiler"
opt/hugo/bin/hugo: OK
Hugo 0.169.0 (extended) built from source by cloudimg
dependency change vs upstream: golang.org/x/net v0.61.0 -> v0.62.0 h1:18ELalfM5+XNRwzM2nYqXsZQ9ByS1uhj2O/U7+5jqRY= (GO-2026-6860, GO-2026-6866)
Sass: LibSass 3.6.6 via github.com/bep/golibsass v1.2.0 (embedded; Dart Sass is NOT installed)
CVE gate: govulncheck v1.9.0 -mode=binary on the unstripped build: no vulnerabilities
no Go toolchain or C compiler
Hugo is licensed under the Apache License 2.0; its licence and the licences of every library compiled into it are in /usr/share/doc/cloudimg-hugo/. The site has no login, admin panel or upload form, by design: content is changed only by someone with SSH access to the instance. nginx's access log is the standard one in /var/log/nginx/; Hugo itself keeps no logs beyond the publish messages in the journal.
Step 15: Keep it up to date
Ubuntu security updates install automatically. To apply everything now:
sudo apt-get update && sudo apt-get upgrade -y
New Hugo releases arrive as new versions of the AWS Marketplace listing: launch the new version and copy /var/www/hugo across (keep the hugo owner, for example with sudo rsync -a --chown=hugo:hugo).
Support
- Email: support@cloudimg.co.uk
- Website: https://www.cloudimg.co.uk
The other versions on this listing are on the developer and API tools guide.