Developer Tools AWS

Opengist 1.15.3 on AWS User Guide

| Product: Opengist 1.15.3 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Opengist 1.15.3 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.

Opengist is an open source, self hosted pastebin powered by Git, an alternative to hosted gist services that keeps your snippets inside your own AWS account. Every snippet (a "gist") is a real Git repository: you write it in the web editor with syntax highlighting for hundreds of languages, and you can clone it, edit it locally and push changes back over HTTPS. It keeps every revision, renders Markdown, CSV, Jupyter notebooks and Mermaid diagrams, searches the code of every gist, and has topics, likes, forks, expiring gists and a REST API.

The cloudimg image locks Opengist down:

  • HTTPS from the first boot. nginx serves Opengist on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS.
  • An administrator made for your instance, nobody else. A stock Opengist install makes the first person who registers the administrator, so whoever reaches a new server first owns it. On this image the first boot creates the administrator admin with a password generated on your instance, before Opengist or nginx accept a single connection, and writes it to /var/lib/cloudimg/opengist-credentials.txt (root only). Opengist stores only an argon2id hash of it. No account and no password is baked into the image.
  • Closed to strangers by default. Open sign-up is off (you add users yourself or send invitations), login is required to see anything, individual gists are not readable anonymously and Gravatar is off, so pages never make your visitors' browsers call gravatar.com. Each is one switch in the admin panel (Step 9).
  • Git over HTTPS only. Opengist's built in SSH git server (port 2222 upstream) is disabled, so the instance listens on ports 22, 80 and 443 only. Clone and push over HTTPS with your password or an access token.
  • Your data on its own volume. The database, every gist repository, the search index and sessions live on a separate 20 GiB EBS volume mounted at /opt/opengist, which you can grow at any time (Step 11).
  • Cross-site requests refused. nginx refuses a form post or WebSocket from another web site, and refuses another site's attempt to trigger the few Opengist links that change something (sign out, start two-factor set up, unlink an OAuth account, or create a gist through the git push address). Opengist's own CSRF tokens stay on as well.
  • Nothing leaves the instance. GitHub, GitLab, Gitea and OpenID Connect sign-in, LDAP and Meilisearch are not configured, and the sign-in routes are closed until you enable a provider (Step 10). Opengist, every git process it runs and nginx are blocked from the EC2 instance metadata service at the kernel level.
  • The host name comes from configuration, never from the request. Opengist's external URL is set on first boot from the instance's public DNS name, nginx refuses requests for host names the instance does not serve, and Opengist always sees the real client address, whatever forwarding headers a request carries.
  • The official release, scanned. Opengist 1.15.3 is the official upstream release binary, checked against its published checksum and built with the current Go release. govulncheck finds no vulnerable code in it.
  • Hardened defaults. Opengist runs as its own unprivileged user with no capabilities and a read only view of the system except its data volume; nginx and Opengist refuse to start until first boot has finished; the AMI requires IMDSv2.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: Opengist 1.15.3 (/usr/local/bin/opengist, with its web UI built in), Git 2.43, nginx, SQLite, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

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 (Opengist) and TCP 80 (redirects to HTTPS) from your own networks only.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Opengist 1.15.3 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (a smaller instance works for a small team), your key pair, a security group as above and a subnet. The image comes with a second 20 GiB volume for Opengist's data; you can make it bigger at 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=opengist}]'

Step 2: Connect to your instance

Version SSH user
Opengist 1.15.3 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

Step 3: Check the services

First boot generates the certificate, the secret key and the administrator, then Opengist and nginx start:

systemctl is-active opengist nginx opengist-firstboot
sudo test -f /var/lib/cloudimg/opengist-firstboot.done && echo FIRSTBOOT_DONE

All three units are active and the first boot marker is present:

active
active
active
FIRSTBOOT_DONE

Only SSH and nginx listen on the network. Opengist itself listens on 127.0.0.1 only, and there is no SSH git server:

sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort
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"))
127.0.0.1:6157 users:(("opengist"))
[::]:22 users:(("sshd"),("systemd"))
[::]:443 users:(("nginx"),("nginx"),("nginx"))
[::]:80 users:(("nginx"),("nginx"),("nginx"))

Step 4: Get your URL and password

sudo cat /var/lib/cloudimg/opengist-credentials.txt

The file is readable by root only and holds the URL, the administrator's user name and this instance's password:

# Opengist 1.15.3 - generated on first boot by opengist-firstboot.service
# This administrator was created on THIS instance; no account was baked into the image. Opengist stores only a hash
# of the password. Keep this file secret and change the password after your first sign-in (Settings > Authentication).

OPENGIST_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
OPENGIST_ADMIN_USER=admin
OPENGIST_ADMIN_PASSWORD=<OPENGIST_ADMIN_PASSWORD>
#
# Open OPENGIST_URL in a browser (self-signed certificate minted on this instance's first boot; port 80 redirects to
# https) and sign in. This instance ships LOCKED DOWN: open sign-up is off (add users in Admin panel > Users or with
# invitations), login is required to view anything, anonymous gists are off and Gravatar is off. Each is a toggle in
# Admin panel > Configuration.
# Every gist is a Git repository: clone and push over HTTPS with your username and password or an access token.
# The built-in SSH git server is switched off in this image.
# Self-test:  sudo opengist-selftest
# Change the name it is served as:  sudo opengist-set-hostname <your-dns-name>
# User guide: https://www.cloudimg.co.uk/guides/opengist-1-15-3-on-ubuntu-24-04-aws/

The URL uses the instance's public DNS name from EC2 instance metadata. The certificate also names the public and private IP addresses, so https://<public-ip>/ works too. To serve Opengist under your own DNS name, see Step 12.

Step 5: Sign in

Open the OPENGIST_URL in your browser. The certificate is self signed, so your browser asks you to confirm it the first time (or install your own certificate, Step 12). Sign in as admin with the password from Step 4. There is no Register link: sign-up is off.

The Opengist sign in page on cloudimg, with the user name and password fields and no registration link

Then open your avatar menu, choose Settings, and change the password under Authentication to one only you know.

Step 6: Create your first gist

Choose New. Give the gist a title and description, name the file (the extension picks the syntax highlighting) and type or paste the content. Use Add file for more files, or drop files onto the upload area. Create public gist creates it (on this instance "public" still means "visible to signed in users"); the arrow next to it offers unlisted and private instead, and Expires removes the gist automatically after a time you choose.

Creating a new gist in Opengist: a deploy.sh file in the editor, with the title, description, topics and expiry settings beside it

The gist page shows each file with syntax highlighting, and has Raw, copy and download buttons, the revision history and the Code menu with its clone address:

A gist in Opengist showing the deploy.sh script with Bash syntax highlighting, the Raw, copy and download buttons and the Revisions, Likes and Forks links

All gists lists every gist you can see, newest first, and the search box at the top searches the contents of all of them:

The Opengist All gists page listing two gists, a Bash deploy helper and an nginx gzip snippet, with a preview of each

Step 7: Run the self test

The image has a self test that checks HTTPS, that anonymous visitors and sign-up are refused, that guessed passwords are refused, then signs in, creates a gist, reads it back over HTTPS and with a real git clone, deletes it and checks the listening ports:

sudo opengist-selftest
SELFTEST-OK https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ : anonymous refused, sign-up refused, guessed passwords refused, admin signed in, gist round trip over HTTPS + git clone, listeners 22/80/443

Step 8: Clone and push gists with Git

Every gist's Code menu shows its clone address, https://<your-host>/<user>/<gist-id> (no .git on the end). Git asks for your Opengist user name and password; for scripts and CI, create an access token under Settings > Access tokens and use it in place of the password.

From your workstation (until you install a trusted certificate, Step 12, tell Git to accept the instance's self signed one for this address only):

git config --global http.https://<public-ip>/.sslVerify false
git clone https://<public-ip>/admin/<gist-id> my-gist
cd my-gist
echo "one more line" >> deploy.sh
git commit -am "Update from my laptop"
git push

To create a brand new gist from a local repository, push it to the special init address. Opengist creates the gist and prints its address:

cd my-new-snippet
git push https://<public-ip>/init HEAD:main
remote: Your new gist has been created here: https://<public-ip>/admin/<gist-id>

Opengist's own SSH git server is switched off on this image, so use HTTPS. If you need git over SSH, see the Opengist documentation and open only the port you configure, from your own networks.

Step 9: Users, sign-up and visibility

Admin (in the sidebar) opens the admin panel. Users lists the accounts, Invitations creates single use sign-up links for people you want to add while open sign-up stays off, and Configuration holds the switches this image sets:

The Opengist admin panel configuration page: Disable signup, Require login and Disable Gravatar switched on; Allow individual gists without login and Disable login form switched off

The same settings, read from Opengist's database:

sudo -u opengist sqlite3 -readonly /opt/opengist/opengist.db "SELECT key||' = '||value FROM admin_settings ORDER BY key;"
allow-gists-without-login = 0
disable-gravatar = 1
disable-login-form = 0
disable-signup = 1
require-login = 1
  • To let anyone who can reach the instance register, switch off Disable signup. Only do this on a private network: anyone who registers can create gists.
  • To share individual gists with people who have no account (for example a link in a ticket), switch on Allow individual gists without login; listing and searching still need a login. To open everything to anonymous readers, switch off Require login as well.

Step 10: Sign in with GitHub, GitLab, Gitea or OpenID Connect (optional)

OAuth and OpenID Connect sign-in are not configured, and nginx closes Opengist's /oauth/ routes so that an unconfigured provider cannot be used. To enable one, register Opengist as an OAuth application with the provider (callback https://<your-host>/oauth/<provider>/callback), add its keys to /etc/opengist/config.yml as the Opengist documentation describes, then open the routes and restart:

sudo nano /etc/opengist/config.yml          # e.g. github.client-key / github.secret, or the oidc.* keys
sudo truncate -s 0 /etc/nginx/opengist-oauth.conf
sudo systemctl restart opengist && sudo systemctl reload nginx

Step 11: The data volume

Opengist's database, gist repositories, search index and sessions are on their own EBS volume, mounted at /opt/opengist by filesystem UUID:

findmnt -no SOURCE,FSTYPE,SIZE /opt/opengist

To grow it, increase the volume's size in the EC2 console (Volumes > Modify volume), then grow the filesystem online:

lsblk
sudo resize2fs "$(findmnt -no SOURCE /opt/opengist)"
df -h /opt/opengist

To back up, take an EBS snapshot of the data volume (or use AWS Backup). For a consistent copy, stop Opengist for the moment you start the snapshot: sudo systemctl stop opengist, start the snapshot, then sudo systemctl start opengist.

Step 12: Your own DNS name and certificate

Point a DNS name at the instance, then set it as the name Opengist is served as. This writes it into the nginx configuration and Opengist's external URL, generates a new self signed certificate for it and restarts Opengist:

sudo opengist-set-hostname <your-domain>

To use a certificate from your own certificate authority (or one you obtained for the name), replace /etc/ssl/opengist/opengist.crt and /etc/ssl/opengist/opengist.key (keep the key mode 0600, owner root) and reload nginx with sudo systemctl reload nginx. Running opengist-set-hostname again generates a new self signed certificate, so install your own after it.

Step 13: Check the security posture from the command line

H=$(sudo sed -n 's#^OPENGIST_URL=https://\([^/]*\)/#\1#p' /var/lib/cloudimg/opengist-credentials.txt)
c() { curl -sk --resolve "$H:443:127.0.0.1" --resolve "$H:80:127.0.0.1" -o /dev/null "$@"; }
c -w 'port 80: %{http_code} -> %{redirect_url}\n' "http://$H/"
c -w 'API without a token: %{http_code}\n' "https://$H/api/gists"
c -w 'gist list without login: %{http_code} -> %{redirect_url}\n' "https://$H/-/all"
c -w 'cross-site logout link: %{http_code}\n' -H 'Sec-Fetch-Site: cross-site' "https://$H/-/logout"
c -w 'cross-origin form post: %{http_code}\n' -X POST -H 'Origin: https://evil.example' "https://$H/-/login"
c -w 'OAuth sign-in routes: %{http_code}\n' "https://$H/oauth/github"
curl -s -o /dev/null -w 'unknown host name: %{http_code} (connection closed)\n' -H 'Host: other.example' http://127.0.0.1/ || true
port 80: 301 -> https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
API without a token: 401
gist list without login: 302 -> https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/-/login
cross-site logout link: 403
cross-origin form post: 403
OAuth sign-in routes: 404
unknown host name: 000 (connection closed)

Opengist and nginx cannot reach the instance metadata service:

for u in opengist nginx; do echo "$u denies: $(systemctl show -p IPAddressDeny --value $u | tr ' ' '\n' | sort | xargs)"; done
opengist denies: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
nginx denies: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128

Step 14: Server components

Item Location
Opengist binary /usr/local/bin/opengist
Configuration /etc/opengist/config.yml (root:opengist, mode 0640)
Data (database, repositories, index, sessions) /opt/opengist (its own EBS volume)
Service units opengist.service, nginx.service, opengist-firstboot.service
nginx site /etc/nginx/sites-available/cloudimg-opengist
Certificate and key /etc/ssl/opengist/
First boot script /usr/local/sbin/opengist-firstboot.sh
Host name helper /usr/local/sbin/opengist-set-hostname
Self test /usr/local/sbin/opengist-selftest
Credentials /var/lib/cloudimg/opengist-credentials.txt (mode 0600)
/usr/local/bin/opengist version
command -v go || echo "no Go toolchain"
nginx -v 2>&1
git --version
sed -n '1,3p' /usr/share/doc/cloudimg-opengist/BUILD-INFO.txt
Opengist v1.15.3
no Go toolchain
nginx version: nginx/1.24.0 (Ubuntu)
git version 2.43.0
opengist          1.15.3 (tag v1.15.3, commit 2acf3dae87f9c3d536e0a870787941bbd06d0b46), AGPL-3.0 - the OFFICIAL release binary
                  https://github.com/thomiceli/opengist/releases/download/v1.15.3/opengist1.15.3-linux-amd64.tar.gz
                  tarball sha256 fb843f3dab89164c7b3a96018d8ea7a97ab3dc90fea05a45770719d23ddf836a (= GitHub's asset digest); binary sha256 008e12ecc149ffd5a18afa894e89fcf7483da4f74b8391d6cb6b69a738a68737

/usr/share/doc/cloudimg-opengist/BUILD-INFO.txt records the release archive and binary checksums, the Go version and modules the release was built with, and the govulncheck result; govulncheck-opengist-binary.txt holds the full report.

What cloudimg changed on the operating system: SSH accepts keys only (no passwords, no root login), the root account has no password, the firmware metadata refresh timer (fwupd-refresh) is masked because EC2 has no updatable firmware, the golden image's boot time updater and the SSM user's passwordless sudo are removed, and unattended security upgrades are on.

Step 15: Security notes and recommendations

  • Allow ports 22, 80 and 443 in the security group from your own networks only.
  • Change the administrator password after your first sign-in (Step 5), keep the credentials file secret, and give each person their own account (Step 9).
  • Use your own DNS name and a certificate your clients trust (Step 12).
  • Gists can hold sensitive snippets: keep Require login on unless the instance is for public sharing, and prefer private gists for anything internal.
  • govulncheck lists advisories for three modules Opengist's build includes but whose vulnerable packages it never uses, so no vulnerable code is reachable: GO-2026-6866 and GO-2026-6860 (the golang.org/x/net/html package; fixed in x/net 0.62.0) and GO-2026-5932 (the golang.org/x/crypto/openpgp package is unmaintained; there is no fixed version). cloudimg rechecks this at each Opengist release.
  • Keep the operating system patched; unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else.

Support and licensing

Opengist is open source under the GNU Affero General Public License v3 (AGPL-3.0, Thomas Miceli and contributors); the licence text is in /usr/share/doc/cloudimg-opengist/, and the source of this exact release is at https://github.com/thomiceli/opengist/tree/v1.15.3. Its built in web UI includes open source packages under the MIT, BSD and MPL 2.0 / Apache 2.0 licences. There is no per user or per CPU licence fee. The AMI price covers cloudimg's build, 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