Hugo 0.169.0
Overview
This guide covers launching and using the Hugo 0.169.0 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. The AMI is one version of the SecureAnyCloud developer and API tools listing on AWS Marketplace. You select 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.
What you get:
- 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. When you change a page, add a post or adjust the stylesheet,hugo-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. The service has 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, so 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. Ubuntu 24.04 LTS is fully patched at build time, with unattended security upgrades switched on.
The image contains 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/sac-hugo/. SecureAnyCloud also masks the fwupd-refresh timer, because EC2 has no firmware that 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 ports 443 and 80 to everyone who should see the site, and port 22 to your own networks only.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Select Hugo 0.169.0 on Ubuntu 24.04 as the software version, choose your Region, and select Launch through EC2.
Choose m5.large, your key pair, a security group as described above and a subnet.
Alternatively, launch 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}]'Connect to your instance
Version SSH user
Hugo 0.169.0 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>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/sac/data/hugo-firstboot.done && echo FIRSTBOOT_DONEactive active active active active FIRSTBOOT_DONEOnly SSH and nginx listen on the network. Hugo itself never listens on a port, because 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 443Open your site
Your site is at https://<public-ip>/. First boot records the address and the certificate details in /var/lib/sac/data/hugo-endpoints.txt. Nothing in that file 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/sac/data/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 recordedRun sudo cat /var/lib/sac/data/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/sac/data/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 sac</title> <h1>Your Hugo site is live</h1> the site is live over HTTPSThe starter site, as your browser shows it, has pages that 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
SecureAnyCloud wrote the templates and the stylesheet for this image. You can change or delete them, and no third-party theme is included.
Hugo's cache of generated resources (the compiled stylesheet and processed images) is kept in /var/cache/hugo-publish, outside the source, so the source folder holds only what you wrote.
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.
In this example, 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/sac/data/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/Add a post
A post is one Markdown file in /var/www/hugo/content/posts/ with a short header (the "front matter") that gives 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/sac/data/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 1My first postThe 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.
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. This 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=sac 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>/ publishedThe WARN line is expected, because 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 3hugo-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.
In this example, a broken template is added and the publish fails. The site keeps serving the last good version, and it 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/sac/data/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 againWhen an automatic publish fails, sudo journalctl -u hugo-publish.service -n 50 shows Hugo's error message.
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. Run this from your own machine, and 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 that your site does not have.
Check the following 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 SecureAnyCloud's [security] block from the end of the starter hugo.toml. The starter keeps a pristine copy in /opt/hugo/starter-site/hugo.toml. Without the block, 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.
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. LibSass 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. It sets the following:
hugo version sed -n '/^\[security\]/,$p' /var/www/hugo/hugo.tomlhugo v0.169.0+extended linux/amd64 BuildDate=unknown VendorInfo=sac [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 widen the policy, widen exactly the list that you need (see Hugo's documentation on security configuration). The outbound fence in Step 12 still applies.
Use your own domain name or certificate
Point a DNS record at the instance, and then set the name. The helper generates a new certificate for the name (and the instance's addresses) and pins nginx to those names, so other host names get no answer. It then 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 readable by 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.
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/sac/data/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 expectedEvery response also carries security headers:
H=$(sudo sed -n 's/^HUGO_HOST=//p' /var/lib/sac/data/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 presentThe content security policy only limits framing, plugins and the <base> tag, so your own scripts, styles and embeds keep working. If your site allows it, add stricter headers in /etc/nginx/conf.d/.
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 :-) sandboxedA 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). A firewall rule for the hugo account rejects the same set outside the service too, and allows 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 sac_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://secureanycloud.com/ } | 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 fencedThe 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.
Run the self-test
The image ships a self-test. It checks the Hugo binary and its security policy, renders your current source as hugo into a scratch folder, and compares what nginx serves with the published files. It also 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_OKHUGO_SELFTEST_OKIf the self-test prints BROKEN-<reason> lines instead, they name what to look at.
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 AuthenticationThe binary is the one that 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/sac-hugo/SHA256SUMS) \
&& sed -n '1p;3p;6,7p' /usr/share/doc/sac-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 sac 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 compilerHugo is licensed under the Apache License 2.0; its licence and the licences of every library compiled into it are in /usr/share/doc/sac-hugo/. By design, the site has no login, admin panel or upload form, so 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.
Keep it up to date
Ubuntu security updates install automatically. To apply everything now:
sudo apt-get update && sudo apt-get upgrade -yNew 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: sales@secureanycloud.com
- Website: https://secureanycloud.com
The other versions on this listing are on the developer and API tools guide.
Deploy on AWS
Launch Hugo 0.169.0 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com