Applications AWS

Wiki-Go 1.9.2 on AWS User Guide

| Product: Wiki-Go 1.9.2 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Wiki-Go 1.9.2 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg BookStack, CMS, Blogs and Wikis listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

Wiki-Go is an open source wiki written in Go that keeps every page as a plain Markdown file on disk instead of rows in a database. There is no database engine to run, tune or back up: your wiki is a folder tree you can copy, search or keep in version control. It is still a full wiki, with hierarchical pages and breadcrumbs, version history with restore, full text search, comments, file attachments, Mermaid diagrams, LaTeX maths, kanban boards, users with administrator, editor and viewer roles, and per path access rules.

The cloudimg image adds:

  • No default login and no setup page. Out of the box Wiki-Go creates an administrator admin with the password admin the first time it runs. This image never lets that happen: it ships with no wiki configuration at all, and your instance's first boot writes one administrator, admin, with a password generated on the instance. Only its bcrypt hash is stored in the wiki; the password itself is in /root/wiki-go-credentials.txt (readable by root only). Nothing from the image build ships in the image.
  • HTTPS from the first boot. nginx serves the wiki on port 443 with a certificate generated on your instance's first boot, and port 80 redirects to HTTPS. The wiki's session cookie is marked Secure, so it is never sent over plain HTTP.
  • The wiki is never exposed directly. Wiki-Go listens on 127.0.0.1:8080 only; nginx is the only public listener. Requests for a host name the instance does not serve are dropped.
  • A sign-in that sees the real client. Wiki-Go bans an address after five failed sign-ins in three minutes. nginx always replaces any X-Forwarded-For or X-Real-IP header a client sends with the connection's own address, and Wiki-Go trusts those headers from nginx only, so the ban and the wiki's log record the real client and a client cannot dodge the ban (or get someone else banned) with a forged header. In front of that, nginx limits how fast one address can call the sign-in and password endpoints and answers 429 Too Many Requests to a flood.
  • Uploads cannot run in the site. Wiki-Go accepts only a fixed list of attachment types (images, text, PDF, Office documents, zip, mp4), checks their content and sends nosniff; nginx adds a sandboxing content security policy to every attachment it serves.
  • Fail closed and confined. Wiki-Go and nginx refuse to start until first boot has finished. Wiki-Go runs as its own unprivileged user with no Linux capabilities, can write only its data folder (/var/lib/wiki-go), and both services are blocked from the instance metadata service; the AMI requires IMDSv2.
  • Current security fixes. Wiki-Go 1.9.2 carries every upstream 1.9 security fix (path traversal, access rule bypass, attachment and comment handling, link preview SSRF). The binary is rebuilt by cloudimg from the exact upstream 1.9.2 source with Go 1.27.3, so it carries no known reachable Go vulnerability (upstream's own 1.9.2 binary was built with an older Go).
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Wiki-Go 1.9.2 (one self contained binary, /opt/wiki-go/wiki-go), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The wiki starts with Wiki-Go's own welcome page.

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 with a route to the internet (or a private route you use for management).
  • A security group that allows TCP 22 (SSH), TCP 443 (the wiki) and TCP 80 (redirects to HTTPS) from the networks that should reach them. Keep 22 to your own networks.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Wiki-Go 1.9.2 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (Wiki-Go is light; a smaller instance is fine for a small team), your key pair and a security group as above.

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=wiki-go}]'

Step 2: Connect to your instance

Version SSH user
Wiki-Go 1.9.2 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

Step 3: Check the services

First boot takes a few seconds. Then nginx, Wiki-Go and the first boot unit are active:

systemctl is-active nginx wiki-go wiki-go-firstboot
active
active
active

nginx serves ports 80 and 443; Wiki-Go listens on the loopback address only, and there is no database, so the only open ports are 22, 80 and 443:

sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|wiki-go/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
State Local Peer
LISTEN 0.0.0.0:22 users:(("sshd"),("systemd"))
LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN 127.0.0.1:8080 users:(("wiki-go"))
LISTEN [::]:22 users:(("sshd"),("systemd"))
LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))

The release record names the binary and the source it was built from:

cat /usr/share/doc/wiki-go/RELEASE
sha256sum /opt/wiki-go/wiki-go
Wiki-Go 1.9.2
binary sha256 c640b78d65d9904762141eb727f19d4cf362a551a6fd33259014cb68268ebeef
source sha256 c521c3cc537ede4e0a1fa9d2705c1f339258db00fb50b2fb669e4e9640a66eed
patch sha256 53580dec1466769f514e955ae684cfb85634fd70b94d4b14a4176de541f7b897
license GPL-3.0 sha256 8b1ba204bb69a0ade2bfcf65ef294a920f6bb361b317dba43c7ef29d96332b9b
c640b78d65d9904762141eb727f19d4cf362a551a6fd33259014cb68268ebeef  /opt/wiki-go/wiki-go

Step 4: Get your sign-in details

The credentials file holds the address the wiki is served as (your instance's public DNS name by default), the user name and the password generated on this instance. Show it with:

sudo cat /root/wiki-go-credentials.txt
WIKIGO_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
WIKIGO_ADMIN_USER=admin
WIKIGO_ADMIN_PASSWORD=<24 letters and digits>

Step 5: Sign in

Open WIKIGO_URL in your browser. The certificate is self signed (generated on your instance), so accept the browser warning once, or install your own certificate (Step 10). The wiki is readable without signing in; choose Login (or open /login) and sign in as admin with WIKIGO_ADMIN_PASSWORD. (The sign-in page always carries Wiki-Go's notice that the wiki is private; a fresh wiki is in fact readable by anyone who can reach it until you make it private in Step 7.)

The Wiki-Go sign-in page with the username and password fields

Signed in, the toolbar shows the authoring tools and Settings. The sidebar holds the page tree and the search box. The home page is Wiki-Go's own welcome page; edit it like any other page. Its note about setting allow_insecure_cookies: true is for wikis served over plain HTTP and does not apply here: this image serves HTTPS, so leave that setting false.

The Wiki-Go home page after signing in as admin, with the page tree and search box in the sidebar and the New, Edit and Settings tools in the toolbar

Step 6: Write and organise pages

Choose New to create a page and Edit to change the page you are on. The editor shows the Markdown with a formatting toolbar and a preview toggle; Save writes it to disk as a .md file. While editing, History lists earlier versions and restores any of them, Attachments uploads images and documents to the page, and Move/Rename and Delete reorganise the tree.

The Wiki-Go Markdown editor open on a runbook page, with the formatting toolbar above the Markdown source

Tables, syntax highlighted code, task lists, Mermaid diagrams and LaTeX maths render from the Markdown:

A rendered Wiki-Go page with a table, a task list and a syntax highlighted code block, and the page in the sidebar tree

The search box searches the full text of every page; use quotes for an exact phrase and -word to leave a word out. To order pages in the sidebar, start their slugs with a number (1-overview, 2-install).

Step 7: Users, roles and a private wiki

Under Settings, Users, add an account for each person with the admin, editor or viewer role (viewers can read and comment, editors can also write). Change your own password under Settings, Profile.

The Wiki-Go settings dialog on the Users tab, listing the admin account with its role

A fresh wiki is readable by anyone who can reach port 443, and only signed-in users can edit. To require a sign-in to read anything, turn on Private wiki under Settings, Content. Settings, Access marks individual paths public, private or restricted to a group, so you can keep most of the wiki open and lock down a section.

Step 8: Where your content lives

Everything the wiki stores is under /var/lib/wiki-go/data: the settings and users (config.yaml), pages (documents/, and the home page in pages/home/), uploaded attachments next to their page, version history, comments, and the session and sign-in ban state (temp/). Each page is a folder with a document.md:

sudo ls /var/lib/wiki-go/data
sudo du -sh /var/lib/wiki-go/data
config.yaml
documents
pages
static
temp
572K    /var/lib/wiki-go/data

Wiki-Go has a built-in backup under Settings, Backup. Because the content is just files, a file copy is also a full backup (stop the wiki first so nothing changes during the copy):

sudo systemctl stop wiki-go
sudo tar czf /home/ubuntu/wiki-go-backup-$(date +%F).tar.gz -C /var/lib/wiki-go data
sudo systemctl start wiki-go

To keep the wiki on its own EBS volume, attach the volume, stop Wiki-Go, copy /var/lib/wiki-go onto the volume, mount the volume on /var/lib/wiki-go (by UUID in /etc/fstab), make sure it is owned by wikigo:wikigo with mode 750, and start Wiki-Go again. EBS snapshots of that volume are then your backups.

Step 9: Security checks

Port 80 sends browsers to HTTPS, the health endpoint answers for load balancer checks, the upstream default password is not in use, and requests for a host name the instance does not serve are dropped:

H=$(sed -n 's/^set \$wg_host "\(.*\)";$/\1/p' /etc/nginx/wiki-go-host.conf)
curl -s -o /dev/null -w 'port 80: %{http_code} -> %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/healthz"
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/api/check-default-password"; echo
curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: example.com' http://127.0.0.1/ || true
port 80: 301 -> https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
ok
{"defaultPasswordInUse":false}

unknown host name: 000

(000 means nginx closed the connection without an answer.) The upstream default admin / admin is refused, and the password generated on this instance signs in. This block hands the password to curl from the credentials file without printing it:

H=$(sed -n 's/^set \$wg_host "\(.*\)";$/\1/p' /etc/nginx/wiki-go-host.conf)
curl -sk -w ' %{http_code}\n' --resolve "$H:443:127.0.0.1" -H 'Content-Type: application/json' \
  -d '{"username":"admin","password":"admin"}' "https://$H/api/login"
sudo sed -n 's/^WIKIGO_ADMIN_PASSWORD=\(.*\)/{"username":"admin","password":"\1"}/p' /root/wiki-go-credentials.txt \
  | curl -sk -o /dev/null -w 'generated password: %{http_code}\n' --resolve "$H:443:127.0.0.1" \
      -H 'Content-Type: application/json' --data-binary @- "https://$H/api/login"
{"message":"Invalid credentials","success":false}
 401
generated password: 200

The credentials file is readable by root only, the wiki's data folder by Wiki-Go's own user only, and the binary belongs to root. Wiki-Go listens on loopback, keeps its session cookie Secure, trusts forwarded addresses from nginx only, and stores the administrator's password as a bcrypt hash:

sudo stat -c '%a %U:%G %n' /root/wiki-go-credentials.txt /var/lib/wiki-go/data /var/lib/wiki-go/data/config.yaml /opt/wiki-go/wiki-go
sudo grep -E '^    (host|port|allow_insecure_cookies|trusted_proxies):' /var/lib/wiki-go/data/config.yaml
sudo grep -A1 '^    - username: admin' /var/lib/wiki-go/data/config.yaml | cut -c1-23
600 root:root /root/wiki-go-credentials.txt
750 wikigo:wikigo /var/lib/wiki-go/data
640 wikigo:wikigo /var/lib/wiki-go/data/config.yaml
755 root:root /opt/wiki-go/wiki-go
    host: "127.0.0.1"
    port: 8080
    allow_insecure_cookies: false
    trusted_proxies: [127.0.0.1]
    - username: admin
      password: $2y$14$

nginx replaces the client address headers with the connection's own address and passes the configured host name, never the one a client sends:

grep -E 'X-Forwarded-For|X-Real-IP|Host ' /etc/nginx/snippets/cloudimg-wiki-go-proxy.conf | grep -v '^#'
proxy_set_header Host $wg_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host "";

Wiki-Go runs as wikigo with no capabilities, a read-only system and only its data folder writable, and neither service can reach the instance metadata service:

systemctl show wiki-go -p User -p ProtectSystem -p ReadWritePaths -p NoNewPrivileges -p IPAddressDeny
systemctl show nginx -p IPAddressDeny
IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32
User=wikigo
ReadWritePaths=/var/lib/wiki-go
ProtectSystem=strict
NoNewPrivileges=yes
IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32

The certificate was generated on this instance and names its own addresses:

H=$(sed -n 's/^set \$wg_host "\(.*\)";$/\1/p' /etc/nginx/wiki-go-host.conf)
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
subject=CN = ec2-<public-ip-dashed>.<region>.compute.amazonaws.com, O = cloudimg
X509v3 Subject Alternative Name:
    DNS:ec2-<public-ip-dashed>.<region>.compute.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost

Step 10: Your own DNS name and certificate

Point a DNS record at the instance, then set the name the wiki is served as. This mints a new self signed certificate for the name, updates nginx and the URL in /root/wiki-go-credentials.txt, and keeps the name across reboots:

sudo wiki-go-set-hostname <your-domain>

To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx (running wiki-go-set-hostname again replaces it with a self signed one):

sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/wiki-go.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/wiki-go.key
sudo nginx -t && sudo systemctl reload nginx

Once browsers trust the certificate you can also add an HSTS header (add_header Strict-Transport-Security "max-age=31536000" always;) to the port 443 server in /etc/nginx/sites-available/cloudimg-wiki-go. The image does not send one: browsers ignore HSTS from a site whose certificate they do not trust. Keep Wiki-Go's own ssl setting off and allow_insecure_cookies false: nginx handles TLS.

Step 11: Passwords, sign-in bans and upgrades

Change the administrator password in the web interface (Settings, Profile), or reset it from SSH if it is lost. wiki-go-set-password writes a new bcrypt hash into the wiki, records the password in /root/wiki-go-credentials.txt, signs every session out and restarts Wiki-Go. Run it without arguments for a random password, or pass your own (24 to 64 letters and digits) on stdin:

sudo wiki-go-set-password
printf '%s\n' '<your-new-password>' | sudo wiki-go-set-password --stdin

Wiki-Go bans an address for 60 seconds after five failed sign-ins in three minutes, and each further ban of that address doubles, up to 24 hours. Tune it under Settings, Security. A ban clears itself; to clear every ban at once, run sudo systemctl stop wiki-go && sudo rm -f /var/lib/wiki-go/data/temp/login_ban.json && sudo systemctl start wiki-go.

Settings changed in the web interface are saved to /var/lib/wiki-go/data/config.yaml. If you edit that file by hand, restart Wiki-Go afterwards (sudo systemctl restart wiki-go). Keep host: "127.0.0.1", port: 8080 and trusted_proxies: [127.0.0.1] as they are: nginx depends on them.

To upgrade to a later Wiki-Go release, snapshot the instance, download the wiki-go-linux-amd64 binary of the new release from the Wiki-Go releases page on GitHub and check its checksum, then replace /opt/wiki-go/wiki-go with it (owned by root, mode 755) and restart Wiki-Go. Your content is untouched because it lives in /var/lib/wiki-go/data. cloudimg also publishes new versions of this image as Wiki-Go releases appear.

Step 12: Server components

Component Path
Wiki-Go binary (root owned) /opt/wiki-go/wiki-go
Wiki data, settings and users /var/lib/wiki-go/data (config.yaml, documents/)
Wiki-Go service /etc/systemd/system/wiki-go.service
nginx site and proxy settings /etc/nginx/sites-available/cloudimg-wiki-go, /etc/nginx/snippets/cloudimg-wiki-go-proxy.conf
Certificate and key /etc/nginx/ssl/
First boot script and settings template /usr/local/sbin/wiki-go-firstboot.sh, /usr/share/cloudimg/wiki-go/config.template.yaml
Helpers /usr/local/sbin/wiki-go-set-hostname, /usr/local/sbin/wiki-go-set-password
Licence, source and release record /usr/share/doc/wiki-go/
Credentials /root/wiki-go-credentials.txt (mode 0600)

Step 13: Security recommendations

  • Allow port 22 in the security group from your own networks only, and port 443 from the networks that should reach the wiki.
  • Give each person their own account with the smallest role they need, and make the wiki private (Step 7) if its content is not for everyone.
  • Use your own DNS name and a certificate your browsers trust (Step 10).
  • Every page loads /var/lib/wiki-go/data/static/custom.css and custom.js (only comments by default) for your own styling and scripts; anything you put there runs for every visitor, so keep those files to content you trust.
  • Keep the operating system patched; unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else.
  • Back up /var/lib/wiki-go/data (Step 8).

Support and licensing

Wiki-Go is open source under the GNU General Public License v3.0; there is no per user or per CPU licence fee. The image's binary is built by cloudimg from the unmodified upstream 1.9.2 source with two Go library updates (golang.org/x/crypto and golang.org/x/text) and Go 1.27.3; the licence, the exact source archive, the library update and the build steps are in /usr/share/doc/wiki-go/. The AMI price covers cloudimg's hardening, first boot setup and support.

  • Email: support@cloudimg.co.uk
  • Website: https://www.cloudimg.co.uk
  • Support: 24/7, with a 24 hour response SLA