Opengist
Overview
Opengist is an open source, self-hosted pastebin powered by Git. Every snippet you save, called a gist, is a real Git repository, so each paste carries full version history and can be cloned and pushed over HTTP.
This SecureAnyCloud image serves Opengist 1.13.1 behind an nginx reverse proxy on a hardened Ubuntu 24.04 LTS base, patched at build time. It ships with no administrator account, so the first user to register becomes the admin. Each instance also generates its own session secret on first boot, so no shared or default credential is baked into the image.
What you get:
- Opengist 1.13.1 served behind nginx, managed by systemd
- The Opengist web interface, Git over HTTP and the REST API on
:80 - Syntax highlighting, code search, public, unlisted and private visibility, and optional sign-in through OAuth, OpenID Connect or LDAP
- No default administrator: the first user to register becomes the admin
- An embedded SQLite datastore and on-disk Git repositories, with no separate database to run
- The server bound to
127.0.0.1:6157only, never exposed directly to the network - A dedicated Azure data disk at
/opt/opengistfor the database, the gist repositories and the search index opengist.serviceandnginx.serviceas enabled systemd units- 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting size. Choose a larger size for busier instances or larger repositories.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the web interface. Opengist serves plain HTTP on port 80, so for production terminate TLS in front of it with your own domain. The server listens on 127.0.0.1:6157 only, so port 6157 stays off the network.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Opengist by SecureAnyCloud, and select Create.
On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).
Review the dedicated data disk on the Disks tab, then select Review + create and Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:opengist-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name opengist \
--image sac1647283583153:opengist-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku StandardOpen port 80 for the web interface:
az vm open-port --resource-group <your-rg> --name opengist --port 80Step 3 - Confirm the services are running
SSH in as azureuser and confirm that Opengist and nginx are active. The server listens only on 127.0.0.1:6157, while nginx serves the web interface on port 80.
systemctl is-active opengist nginx opengist-firstbootsudo ss -tlnp | grep -E ':80 |:6157 ' | sed 's/ */ /g'Step 4 - Read the instance info note
Opengist ships with no administrator account. On the first boot of every VM, a one-shot service writes an instance info note that records the site URL and the register instruction. The note contains no password, because the first user to register becomes the admin. Read it with sudo:
sudo cat /root/opengist-credentials.txtThen check that the server is healthy. The health endpoint returns 200:
curl -s -o /dev/null -w 'GET /healthcheck -> HTTP %{http_code}\n' http://127.0.0.1/healthcheckStep 5 - Register your admin on first visit
Browse to http://<vm-public-ip>/. The image ships with no user, so open the Register page and create the first account. The first user to register automatically becomes the administrator.
Choose a username and a strong password, then select Register. There are no default credentials to change, because none ship.
Step 6 - Create your first gist
Once you are signed in, select New to open the gist editor. Give the file a name with an extension (for example healthcheck.sh) and paste or type your snippet into the editor. Opengist detects the language from the file extension and applies syntax highlighting.
Choose the visibility: public, unlisted or private. To add a title, description and topics, use Metadata.
Step 7 - View and share the gist
Select Create. Opengist saves the snippet as a Git repository and opens its view page.
The page shows the highlighted code and a Revisions tab that tracks every change. Use the controls to Like, Edit or Download ZIP, to view the Raw file, or to copy an Embed snippet for a blog or wiki.
Step 8 - Browse your gists
Your profile page lists every gist you own, with a preview of each snippet and filters for visibility, language and topics. Public and unlisted gists from other users appear under All in the top navigation. The code search box searches across the whole instance.
Step 9 - Clone and push over Git
Every gist is a real Git repository, so you can clone it, commit locally and push changes back over HTTP. Copy the gist URL from its view page and use ordinary Git commands. Sign in with the account you registered in Step 5:
git clone http://<vm-public-ip>/<username>/<gist-id>.git cd <gist-id>
# edit files, then
git add -A && git commit -m "update snippet"
git pushTo create a new gist by pushing a repository, create the gist in the web interface first. Then set its URL as a remote and push.
Step 10 - Verify the stack
Check the Opengist version, confirm that the services are enabled and that the web interface responds through nginx, and confirm the dedicated data disk mount:
/usr/local/bin/opengist versionsystemctl is-enabled opengist nginxcurl -s -o /dev/null -w 'GET /healthcheck -> HTTP %{http_code}\n' http://127.0.0.1/healthcheckfindmnt -no SOURCE,TARGET,FSTYPE /opt/opengistStep 11 - Where your data lives
The SQLite database, every gist Git repository and the search index live on a dedicated Azure data disk mounted at /opt/opengist, separate from the OS disk. The disk is captured into the image and re-provisioned on every VM. You can snapshot and resize it independently.
Confirm the mount and the free space:
df -h /opt/opengist | tail -1sudo ls -la /opt/opengistSecurity notes
- Encrypt web traffic. Opengist serves plain HTTP on port 80. For production, put it behind your own TLS-terminating reverse proxy or an Azure Application Gateway with a certificate for your domain, and restrict port 80 in the NSG to trusted networks. A common approach is
certbotwith your domain on a front-end proxy. - Keep the server private. It listens on
127.0.0.1:6157only, so only nginx on port 80 faces the network. The built-in Git over SSH server is disabled, so only ports 22, 80 and 443 are in play. - Secure the first admin. The image ships with no administrator, so there are no shared or default credentials to rotate. After you register, open the admin settings and disable open sign-up if the instance is not meant to be public. Keep your admin password somewhere safe.
- Keep the VM patched. The image is patched at build time and ships with unattended security upgrades enabled.
Support
SecureAnyCloud images come with 24/7 support. For questions about this Opengist image or help with your deployment, contact us through the SecureAnyCloud website.
Deploy on Azure
Launch Opengist on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Opengist is a self-hosted pastebin powered by Git. You paste code or text into a browser, and what you get back is a real Git repository that you can clone, commit to, push back and browse revision by revision.
This image runs Opengist inside your own VPC, so content never leaves your AWS account. It gives you a private alternative to a public gist service, with TLS, per-instance credentials and a locked-down default configuration.
What you get:
- Opengist, distributed under the GNU Affero General Public License version 3, installed from the official prebuilt single Go binary at
/usr/local/bin/opengistwith its checksum pinned at build time, and a copy of the licence at/usr/share/doc/opengist/LICENSE - No Node build, no runtime interpreter and no external database to operate, because the binary embeds the whole web interface
- A service that runs under systemd and starts on boot
- All state, including the SQLite database, every gist repository, the full-text search index and uploaded avatars, under
/opt/opengiston a dedicated, independently resizable EBS data volume - An nginx reverse proxy that terminates TLS on port 443, in front of an application bound to the loopback interface only
- A unique administrator password, session signing secret and TLS certificate generated on the first boot of every instance
- Sign-up disabled and login required by default
- 24/7 SecureAnyCloud support
Security model
This image differs from a stock Opengist install. It exposes three ports:
- 22: SSH to the instance.
- 80: Serves the unauthenticated /healthz probe and redirects everything else to HTTPS.
- 443: The web interface and Git over HTTPS. This is the only way in to the application.
The application is bound to 127.0.0.1:6157 and cannot be reached from outside the instance. An nginx reverse proxy terminates TLS on port 443 and is the sole path to it.
There is deliberately no HTTP Basic layer in front. Opengist's REST API authenticates with a Bearer token in the same Authorization header that a basic auth layer would consume, so stacking one would break every authenticated request and every Git operation. Opengist's own session and token authentication is the control.
Every instance generates its own administrator password, its own session signing secret and its own TLS certificate at first boot. The password is written to /root/opengist-credentials.txt with mode 0600. It is seeded through the application's own command line, so it never appears in the process list. Nothing secret is baked into the image, so two instances launched from it never share a secret.
This image ships locked down. Upstream Opengist lets anyone who can reach an instance register an account, and the first person to register becomes the administrator. On an instance that gets a public address the moment it launches, that is a race and an abuse risk. This image therefore applies three policies before the service starts:
- Disable signup: On. Nobody can self-register. The administrator creates accounts.
- Require login: On. Nothing is readable without an account.
- Allow individual gists without login: Off. Individual gists are not anonymously readable.
Each policy is a single toggle on the Admin panel, Configuration tab. Step 7 explains how to relax them if you want a more open instance.
The image also switches off two upstream listeners that are not appropriate for a machine image. The built-in SSH Git server, which upstream enables by default on 0.0.0.0:2222, is disabled. Shipping it would add a second, unrequested port and give every customer instance the same SSH host identity, so Git works over HTTPS instead. The Prometheus metrics endpoint, which defaults to 0.0.0.0:6158, is also disabled.
Prerequisites
Before you deploy this image, make sure you have:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 from your management network and ports 80 and 443 from wherever your users are
- An SSH client, and
giton your workstation if you want to clone gists m5.largeas the recommended instance type, which is what this listing is priced against
Launch the instance
From the AWS Marketplace console
- Open the product page in AWS Marketplace, choose Continue to Subscribe, then choose Continue to Configuration.
- Pick the software version, the Region and the fulfilment option, then choose Continue to Launch.
- Choose Launch through EC2. Select
m5.large, your key pair, your VPC and subnet, and a security group that allows inbound 22, 80 and 443. - Launch the instance and wait for both status checks to pass.
From the AWS CLI
Replace the example values with the AMI ID shown on the listing, your key pair, your subnet and your security group.
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--instance-type m5.large \
--key-name your-key-pair \
--subnet-id subnet-xxxxxxxxxxxxxxxxx \
--security-group-ids sg-xxxxxxxxxxxxxxxxx \
--associate-public-ip-address \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=opengist}]'First boot takes a few seconds after the instance reaches the running state. It resolves the instance's public address, creates the session secret and the administrator password, seeds the account, issues the TLS certificate and writes the credentials file. The steps below assume first boot has finished.
Connect over SSH and read your credentials
The SSH login user depends on the AMI variant you launched. For the Ubuntu 24.04 variant, the login user is ubuntu.
Connect with your key pair, replacing the address with your own instance address:
ssh -i your-key.pem ubuntu@<public-ip>The login banner tells you where things are. Read the unique administrator credentials for this instance:
sudo cat /root/opengist-credentials.txtOnly root can read the file. Confirm the account name and the URLs it recorded for this instance:
sudo grep -E '^OPENGIST_(ADMIN_USER|URL|HEALTH_URL|APP_LISTEN)=' /root/opengist-credentials.txtOPENGIST_ADMIN_USER=admin OPENGIST_URL=https://44.201.83.181/ OPENGIST_HEALTH_URL=https://44.201.83.181/healthz OPENGIST_APP_LISTEN=127.0.0.1:6157The password is in the same file, on the line that begins OPENGIST_ADMIN_PASSWORD=. Keep it out of your shell history, and change it from the account settings page after you sign in.
Sign in to the web interface
Open https://<public-ip>/ in a browser. The certificate was issued for this instance at first boot and is self-signed, so your browser warns on the first visit. Accept the warning to reach the login page. Step 8 replaces the certificate with your own.
Sign in with the username and password from /root/opengist-credentials.txt. Open registration is disabled in this image, so the register link does not offer a usable form.
After you sign in, you land on the gist index. On a freshly launched instance it is empty.
Create your first snippet
Choose New in the top navigation. Give the file a name with an extension, because the extension selects the highlighter, then paste your content. Expand Metadata to add a title, a description, a URL and topics. Use Expires if the snippet should delete itself later.
Use the split button at the bottom right to choose the visibility as you create the snippet:
- Public: listed on the index and searchable by anyone signed in.
- Unlisted: reachable only by its URL, and not listed.
- Private: visible only to you.
Save the snippet to open the gist page. It shows the file rendered with highlighting, a Revisions tab, an Embed box for putting the snippet into a wiki or documentation page, Raw and Download ZIP links, and edit, archive and delete actions.
Clone a gist with git
Cloning is what sets Opengist apart from an ordinary paste service. Every gist is a real Git repository, served over HTTPS at the same address as the web interface. Copy the gist URL from your browser and clone it. Replace the values in angle brackets with your instance address, your username and the gist ID:
git clone https://<public-ip>/<user>/<gist-id>Git prompts for your Opengist username and password. The certificate is self-signed until you replace it, so add -c http.sslVerify=false on the first clone, or trust the certificate on your workstation.
Edit the file, commit and push. The new revision appears on the gist's Revisions tab immediately:
cd <gist-id> git commit -am "tighten the retry loop" git pushThe verification section below runs this whole round trip automatically against your own running instance.
Search across your snippets
The search box at the top of every page queries the built-in full-text index. You can search free text or scope a search by field:
- systemctl: finds snippets whose content mentions systemctl.
- language:go: finds snippets that contain Go files.
- extension:yml: finds snippets that contain YAML files.
- filename:backend.tf: finds snippets that contain that filename.
- user:alice: finds snippets owned by that user.
- topic:platform: finds snippets tagged with that topic.
Add users and choose how open the instance is
Open Admin panel from the account menu. The Configuration tab shows the effective configuration on the left and the policy toggles on the right. This image changes the top three toggles.
Confirm the shipped policy on your own instance:
sudo sqlite3 -readonly /opt/opengist/opengist.db 'select key,value from admin_settings order by key;'allow-gists-without-login|0 disable-gravatar|0 disable-login-form|0 disable-signup|1 require-login|1To add people without opening registration to the internet, use one of these options, in order of preference:
- Invitations. The Invitations tab creates a time-limited invitation link with a use count. Send the link to a colleague. They create their own account, and nobody else can.
- Create the account yourself. On the instance, run the command below. It reads the password from standard input, so the password never lands in your shell history or the process list. Add
--adminto grant administrator rights.
sudo opengist --config /etc/opengist/config.yml admin create-user --username alice --password-stdin
- Connect your identity provider. Opengist authenticates against OpenID Connect, LDAP, GitHub, GitLab or Gitea. Add the provider keys to
/etc/opengist/config.ymland restart the service. Withoidc.admin-groupset, membership of that group grants administrator rights automatically.
Turn Disable signup off only if this instance is meant to accept public registrations.
Turn Require login off to make public gists readable without an account, which suits a shared internal paste board. Turn on Allow individual gists without login instead to keep the index private while letting anyone with a link read a single gist.
The Users and Gists tabs list and manage everything on the instance. The General tab carries maintenance actions such as reindexing and garbage-collecting repositories.
Replace the self-signed certificate
The certificate issued at first boot carries the instance's address and is self-signed. Once a DNS name points at the instance, copy your own certificate and key into place and reload nginx. The paths are fixed, so nothing else needs editing:
- /etc/nginx/tls/opengist.crt: your certificate, followed by any intermediates.
- /etc/nginx/tls/opengist.key: the matching private key, mode 0600 and owned by root.
After you copy them in, test the configuration and reload nginx:
sudo nginx -t sudo systemctl reload nginxNext, set the public URL so that links, redirects and clone URLs use your domain rather than the IP address. Edit external-url in /etc/opengist/config.yml with no trailing slash, then restart:
sudo sed -i 's#^external-url:.*#external-url: https://gists.example.com#' /etc/opengist/config.yml
sudo systemctl restart opengistA trailing slash produces double-slash redirects that return 404, so leave it off.
Verifying the deployment
Run every block below on the instance. Each one asserts its result rather than only printing it, so a non-zero exit means something is wrong.
Both services should be active:
sudo systemctl is-active opengist.service nginx.serviceactive activeThe application must listen on loopback only, with just SSH and the two web ports reachable from outside. Look for 127.0.0.1:6157, not 0.0.0.0:6157, and confirm that nothing is listening on 2222 or 6158:
sudo ss -Hltnp | awk '{print $4}' | sort0.0.0.0:22 0.0.0.0:443 0.0.0.0:80 127.0.0.1:6157 127.0.0.53%lo:53 127.0.0.54:53 [::]:22 [::]:443 [::]:80The health endpoint answers without authentication on 443, and port 80 redirects:
curl -sk -o /dev/null -w 'healthz HTTP %{http_code}\n' https://127.0.0.1/healthz
curl -s -o /dev/null -w 'port 80 HTTP %{http_code}\n' http://127.0.0.1/healthz HTTP 200 port 80 HTTP 301Check the version and the licence file that ships with the image:
/usr/local/bin/opengist version head -1 /usr/share/doc/opengist/LICENSEOpengist v1.14.0 GNU AFFERO GENERAL PUBLIC LICENSECheck that the configuration keeps the application on loopback and the two optional listeners off:
sudo grep -E '^(http\.host|http\.port|ssh\.git-enabled|metrics\.enabled|index)' /etc/opengist/config.ymlindex: bleve http.host: 127.0.0.1 http.port: 6157 ssh.git-enabled: disabled metrics.enabled: falseCheck that the certificate belongs to this instance and is not shared:
sudo openssl x509 -in /etc/nginx/tls/opengist.crt -noout -subject -datessubject=C = GB, O = sac, CN = 44.201.83.181 notBefore=Jul 26 21:24:40 2026 GMT notAfter=Jul 23 21:24:40 2036 GMTFull credential and round-trip check
The image ships a self-test that proves, by exit code, four things. An unauthenticated caller is refused. A wrong password grants no session. This instance's own generated password is accepted through the same code path. A real snippet can be created, read back over HTTP and cloned over Git.
The test creates a temporary gist and deletes it again, so it leaves no state behind:
sudo /usr/local/sbin/opengist-selftest.shOK anonymous refused (api 401, settings and index land on /login), sign-up disabled and proven to create no account, wrong password grants no session, this instance's own password accepted, gist round trip verified over HTTP and over a real git clone, exposure cleanThe data volume, backup and growth
Everything Opengist owns lives on a dedicated EBS volume mounted at /opt/opengist by filesystem UUID. The volume survives an instance replacement and can be resized without touching the operating system disk:
df -h /opt/opengist | tail -1 grep ' /opt/opengist ' /etc/fstab/dev/nvme1n1 40G 948K 38G 1% /opt/opengist UUID=96f498c5-4cc9-4348-b2f7-9ff1dd98bce8 /opt/opengist ext4 defaults,nofail 0 2The volume holds:
- /opt/opengist/opengist.db: accounts, gist metadata, sessions, access tokens and the admin settings.
- /opt/opengist/repos: one real Git repository per gist.
- /opt/opengist/index: the bleve full-text search index.
To back up, take an EBS snapshot of the data volume. For a consistent copy of the database while the service is running, use SQLite's own online backup rather than copying the file:
sudo sqlite3 /opt/opengist/opengist.db ".backup '/var/backups/opengist-$(date -u +%Y%m%d).db'"To grow the volume, modify it in the EC2 console or CLI, then extend the filesystem on the instance:
sudo resize2fs /dev/nvme1n1The search index is derived data. If it is lost or looks stale, rebuild it from the General tab of the admin panel rather than restoring it.
Service management and troubleshooting
Use these commands to manage the service:
- Service status: sudo systemctl status opengist nginx
- Restart the application: sudo systemctl restart opengist
- Reload the proxy after a certificate change: sudo systemctl reload nginx
- Application logs: sudo journalctl -u opengist -n 100
- Proxy access and error logs: sudo tail -n 50 /var/log/nginx/error.log
- First-boot log: sudo journalctl -u opengist-firstboot
- Re-check exposure: sudo /usr/local/sbin/opengist-exposure-check.sh '22 80 443'
The browser warns about the certificate. This is expected until you complete Step 8. The certificate is generated on your instance and is not shared with anyone.
The credentials file contains only comments. First boot has not finished. Check its status with:
sudo systemctl status opengist-firstboot.serviceLinks or clone URLs point at the wrong address. external-url in /etc/opengist/config.yml is set from the public address the instance had at first boot. If the address changed or you moved to a DNS name, update it as shown in Step 8 and restart the service.
A push is rejected as too large. The proxy accepts request bodies up to 512 MB. To allow more, raise client_max_body_size in /etc/nginx/sites-available/sac-opengist, then reload nginx.
Nobody can sign up. This is the shipped policy. Use an invitation, create the account from the command line, or turn the toggle off, as described in Step 7.
Support
SecureAnyCloud provides 24/7 technical support for this image by email at sales@secureanycloud.com and by live chat on secureanycloud.com. We can help with deployment, TLS certificates, identity provider integration, Git over HTTPS, access tokens and the REST API, search index tuning, data volume resizing and backup, and hardening.
Opengist itself is community-supported upstream at github.com/thomiceli/opengist, with documentation at opengist.io.
Deploy on AWS
Launch Opengist on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com