M2
Applications AWS

MicroBin 2.1.0 on AWS User Guide

| Product: MicroBin 2.1.0 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the MicroBin 2.1.0 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg documents, forms and scheduling listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

MicroBin is a small, self hosted pastebin and file sharing web application. Your team pastes text such as code, configuration, notes and logs (with syntax highlighting), uploads files, shortens URLs and makes QR codes, then shares the link. Pastes can expire after a set time or after a number of reads, can be unlisted, and can be encrypted on the server with a password or in the browser before they are sent. Everything stays on your own instance in your own VPC.

Upstream MicroBin listens on plain HTTP, lets anyone create pastes and upload files, lists every public paste, and ships with the admin login admin / m1cr0b1n. The cloudimg image changes that:

  • HTTPS from the first boot. nginx serves MicroBin on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS. MicroBin itself listens on 127.0.0.1:8080 only.
  • Two passwords unique to your instance. The uploader password is needed to create a paste or upload a file, so the instance is not an open file host for the internet. The admin password opens the /admin panel and is needed to delete a paste. Both are generated on first boot and written to /root/microbin-credentials.txt (root only). The upstream default admin login is refused. Anyone you give a paste's link can read it, which is what a pastebin is for.
  • No public paste list, unlisted, server encrypted ("private") and browser encrypted ("secret") pastes, burn after reading, and a 24 hour default expiry.
  • Fail closed. MicroBin and nginx refuse to start until first boot has generated the certificate and both passwords, so the app is never served with a default or empty login.
  • Hardened. Requests for host names the instance does not serve are dropped, the client address nginx passes on is always the real one (a forged X-Forwarded-For is overwritten), cross site form posts are refused, admin logins and deletes are rate limited, MicroBin runs as its own user in a systemd sandbox, MicroBin and nginx are blocked from the instance metadata service, the AMI requires IMDSv2, and telemetry and update checks are off.
  • Your data on its own disk. Pastes, uploaded files and MicroBin's database live on a separate 32 GiB EBS volume mounted at /var/lib/microbin, which you can resize or snapshot on its own.
  • The official release, verified. The MicroBin 2.1.0 release binary is checked against a pinned SHA-256 checksum before it is installed, and the image is fully patched Ubuntu 24.04 LTS with unattended security upgrades on.

What is on the image: MicroBin 2.1.0 (the official static release binary in /usr/local/bin/microbin, licence in /usr/share/doc/microbin), nginx, 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 (MicroBin) and TCP 80 (redirects to HTTPS). Open 22 from your own networks only; open 443 and 80 to the people you share pastes with.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick MicroBin 2.1.0 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair and a security group as above. The AMI brings two volumes: the 8 GiB root volume and the 32 GiB data volume for /var/lib/microbin; increase the data volume at launch if you expect large uploads.

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

Step 2: Connect to your instance

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

Step 3: Check the services

First boot generates the certificate and the passwords, then MicroBin and nginx start:

systemctl is-active microbin nginx microbin-firstboot
sudo test -f /var/lib/cloudimg/microbin-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; MicroBin listens on loopback only, behind nginx:

sudo ss -lntp | awk 'NR>1 {print $4, $6}' | 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:8080 users:(("microbin",...))
127.0.0.53%lo:53 users:(("systemd-resolve",...))
127.0.0.54:53 users:(("systemd-resolve",...))
[::]:22 users:(("sshd",...),("systemd",...))
[::]:443 users:(("nginx",...),("nginx",...),("nginx",...))
[::]:80 users:(("nginx",...),("nginx",...),("nginx",...))

Step 4: Get your URL and passwords

sudo cat /root/microbin-credentials.txt

The file is readable by root only and holds the URL, the admin login and the uploader password of this instance:

# MicroBin 2.1.0 - generated on first boot by microbin-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.

MICROBIN_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
MICROBIN_ADMIN_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/admin
MICROBIN_ADMIN_USERNAME=admin
MICROBIN_ADMIN_PASSWORD=<MICROBIN_ADMIN_PASSWORD>
MICROBIN_UPLOADER_PASSWORD=<MICROBIN_UPLOADER_PASSWORD>
#
# Open MICROBIN_URL in a browser (self-signed certificate minted on this instance's first boot; port 80
# redirects to https). Creating a paste or uploading a file needs MICROBIN_UPLOADER_PASSWORD. Anyone you
# give a paste's link can read it. The admin panel (MICROBIN_ADMIN_URL) and deleting a paste need the
# admin username and password.
# New admin password:           sudo microbin-set-password --admin
# New uploader password:        sudo microbin-set-password --uploader
# Change the name it serves as: sudo microbin-set-hostname <your-dns-name>
# User guide: https://www.cloudimg.co.uk/guides/microbin-2-1-0-on-ubuntu-24-04-aws/

The URL uses the instance's public DNS name from EC2 instance metadata, and the links and QR codes MicroBin shows are built from that configured name, never from the request. The certificate also names the public and private IP addresses, so https://<public-ip>/ works too. To serve MicroBin under your own DNS name, see Step 9.

Give the uploader password to the people who should be able to create pastes. Keep the admin password for whoever looks after the instance.

Step 5: Create a paste

Open the MICROBIN_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 9). Type or paste your text into Content, choose how long it should live (Expiration), whether it should disappear after a number of reads (Burn After), the Syntax for highlighting and the Privacy level, enter the uploader password next to Save, and select Save:

The MicroBin new paste page with a Bash script in the Content box, Syntax set to Bash Shell, Expiration 24 hours, Privacy Public and the uploader password entered next to the Save button

MicroBin opens the new paste at a link made of three animal names, such as /upload/monkey-bee-fish. Copy URL copies the link to share, Raw Text Content gives the plain text (handy for curl), and QR shows a QR code of the link:

A shared MicroBin paste showing the Bash script with syntax highlighting and line numbers, with Copy Text, Raw Text Content, QR, Remove and Copy URL controls

To share a file, select Select or drop file attachment (or drop the file on the page) before you save. Files up to 256 MB are accepted, and recipients download them with Download:

A MicroBin paste with the note Quarterly report draft attached and a report-q3.pdf attachment with a Download button

Step 6: Private and secret pastes

The Privacy list offers:

Privacy What it does
Public Anyone with the link can read it. There is no public list of pastes on this image.
Unlisted The same as Public here, since no list is shown.
Private Encrypted on the server with the password you type in Password; readers need the link and the password.
Secret Encrypted in your browser before it is sent, so the server only stores ciphertext; readers need the link and the password.

Someone who opens a private paste is asked for its password first:

The MicroBin password prompt shown before a private paste can be read

With the right password the paste opens:

The private paste unlocked, showing a maintenance window note

Step 7: The admin panel

Open the MICROBIN_ADMIN_URL and sign in as admin with the admin password. The panel lists every paste with its expiry, size and type, and lets you remove any of them:

The MicroBin admin panel listing uploads with their keys, validity, size and content type, each with a Remove link

The panel shows "Version 2.0.4": that is a display string upstream did not update in the 2.1.0 release. The binary is 2.1.0 (microbin --version, Step 11).

Deleting a paste (the Remove link on a paste or in the panel) asks for the admin username and password in a browser login box. Upstream MicroBin lets anyone holding a public link delete it; on this image only the admin can.

Step 8: Check the security posture from the command line

Port 80 redirects to HTTPS, there is no paste list (it redirects to the home page), an upload without the uploader password is refused, and a request for a host name the instance does not serve is dropped without an answer:

H=$(sudo grep '^MICROBIN_URL=' /root/microbin-credentials.txt | sed -E 's#^MICROBIN_URL=https://([^/]+)/.*#\1#')
curl -s -o /dev/null -w 'http://  -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -o /dev/null -w 'home page -> HTTP %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/"
curl -sk -o /dev/null -w 'paste list -> %{http_code} %{redirect_url}\n' --resolve "$H:443:127.0.0.1" "https://$H/list"
curl -sk -o /dev/null -w 'upload without password -> %{http_code} %{redirect_url}\n' --resolve "$H:443:127.0.0.1" -H "Origin: https://$H" -F content=test "https://$H/upload"
curl -sk -o /dev/null -w 'unknown host -> %{http_code}\n' --resolve "evil.example:443:127.0.0.1" "https://evil.example/" || true
http://  -> 301 https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
home page -> HTTP 200
paste list -> 302 https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
upload without password -> 302 https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/incorrect
unknown host -> 000

000 means nginx closed the connection without answering, which is how it treats any host name it does not serve.

With the uploader password a paste is created and can be read back as plain text; deleting it needs the admin login. The passwords are passed to curl on standard input, so they never appear in the process list or your shell history:

sudo bash -c '
  F=/root/microbin-credentials.txt
  U=$(grep "^MICROBIN_UPLOADER_PASSWORD=" $F | cut -d= -f2-)
  A=$(grep "^MICROBIN_ADMIN_PASSWORD=" $F | cut -d= -f2-)
  H=$(grep "^MICROBIN_URL=" $F | sed -E "s#^MICROBIN_URL=https://([^/]+)/.*#\1#")
  R="--resolve $H:443:127.0.0.1"
  L=$(printf "form = \"content=Hello from MicroBin on AWS\"\nform = \"expiration=1hour\"\nform = \"uploader_password=%s\"\n" "$U" \
      | curl -K - -sk $R -H "Origin: https://$H" -o /dev/null -w "%{redirect_url}" "https://$H/upload")
  echo "new paste -> $L"
  ID=${L##*/upload/}
  curl -sk $R "https://$H/raw/$ID"; echo
  curl -sk $R -o /dev/null -w "delete without admin login -> HTTP %{http_code}\n" "https://$H/remove/$ID"
  printf "user = \"admin:%s\"\n" "$A" | curl -K - -sk $R -o /dev/null -w "delete with admin login -> HTTP %{http_code}\n" "https://$H/remove/$ID"
  curl -sk $R -o /dev/null -w "paste after delete -> HTTP %{http_code}\n" "https://$H/raw/$ID"
'
new paste -> https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/upload/<three-animal-names>
Hello from MicroBin on AWS
delete without admin login -> HTTP 401
delete with admin login -> HTTP 302
paste after delete -> HTTP 404

The passwords live in two root only files: the credentials note and /etc/microbin/secrets.env, which systemd hands to MicroBin as its environment. nginx keeps only a SHA-512 crypt hash of the admin password for deletes:

sudo stat -c '%a %U:%G %n' /root/microbin-credentials.txt /etc/microbin/secrets.env /etc/nginx/.microbin-htpasswd /etc/microbin/microbin.env
sudo sed -E 's/=.*/=<value>/' /etc/microbin/secrets.env
600 root:root /root/microbin-credentials.txt
600 root:root /etc/microbin/secrets.env
640 root:www-data /etc/nginx/.microbin-htpasswd
644 root:root /etc/microbin/microbin.env
MICROBIN_ADMIN_USERNAME=<value>
MICROBIN_ADMIN_PASSWORD=<value>
MICROBIN_UPLOADER_PASSWORD=<value>

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

H=$(sudo grep '^MICROBIN_URL=' /root/microbin-credentials.txt | sed -E 's#^MICROBIN_URL=https://([^/]+)/.*#\1#')
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

MicroBin and nginx cannot reach the instance metadata service, MicroBin runs as its own user with the passwords from a root only file, and it will not start until first boot has finished and both passwords are in place:

systemctl show microbin nginx -p Id -p IPAddressDeny
systemctl cat microbin | grep -E '^(ExecStartPre|ExecStart|EnvironmentFile|User)='
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=microbin.service

IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
Id=nginx.service
User=microbin
EnvironmentFile=/etc/microbin/microbin.env
EnvironmentFile=/etc/microbin/host.env
EnvironmentFile=/etc/microbin/secrets.env
ExecStartPre=/usr/bin/test -f /var/lib/cloudimg/microbin-firstboot.done
ExecStartPre=+/usr/local/sbin/microbin-auth-guard
ExecStart=/usr/local/bin/microbin --json-db --no-listing --readonly --private --encryption-client-side --encryption-server-side --enable-burn-after --highlightsyntax --qr --disable-telemetry --disable-update-checking

The flags on the ExecStart line are the MicroBin features this image turns on. --readonly together with the uploader password is what makes uploads password protected. To change a feature, run sudo systemctl edit --full microbin, then sudo systemctl restart microbin.

Step 9: Your own DNS name and certificate

Point a DNS record at the instance, then set the name MicroBin is served as. This mints a new self signed certificate for the name, updates nginx, MicroBin's links and the URL in the credentials file, restarts MicroBin and keeps the name across reboots:

sudo microbin-set-hostname <your-domain>

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

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

Step 10: Change the passwords

microbin-set-password generates a new random admin password (--admin, the default) or uploader password (--uploader), writes it to /etc/microbin/secrets.env and /root/microbin-credentials.txt, updates nginx's hash of the admin password and restarts MicroBin:

sudo microbin-set-password --uploader

To choose a password yourself, hand it over on standard input (printf is a shell builtin, so the password never appears in the process list; start the line with a space so most shells keep it out of your history). Passwords are 12 to 128 characters from A-Z a-z 0-9 . _ ~ @ % + = , -:

 printf '%s\n' '<new-password>' | sudo microbin-set-password --admin --stdin

Step 11: Data, backups and server components

Pastes, uploaded files and MicroBin's JSON database live on the data volume:

df -h /var/lib/microbin | sed 1d
grep /var/lib/microbin /etc/fstab | sed -E 's/UUID=[0-9a-f-]+/UUID=<uuid>/'
microbin --version
nginx -v 2>&1
/dev/nvme1n1     32G   40K   30G   1% /var/lib/microbin
UUID=<uuid> /var/lib/microbin ext4 defaults,nofail 0 2
microbin 2.1.0
nginx version: nginx/1.24.0 (Ubuntu)

To back up MicroBin, take an EBS snapshot of the data volume (or copy /var/lib/microbin while microbin is stopped). To give it more room, grow the volume in the EC2 console and run sudo resize2fs on its device.

Component Path
MicroBin binary /usr/local/bin/microbin
Licence and source note /usr/share/doc/microbin/
Settings /etc/microbin/microbin.env
Public URL (set by microbin-set-hostname) /etc/microbin/host.env
Passwords (set by microbin-set-password) /etc/microbin/secrets.env (mode 0600)
Data: database, uploads /var/lib/microbin (its own EBS volume)
nginx site /etc/nginx/sites-available/cloudimg-microbin
Delete login file /etc/nginx/.microbin-htpasswd (SHA-512 crypt)
Certificate and key /etc/ssl/microbin/
First boot script /usr/local/sbin/microbin-firstboot.sh
Credentials /root/microbin-credentials.txt (mode 0600)

Step 12: Security recommendations

  • Allow port 22 in the security group from your own networks only, and ports 443 and 80 only to the people you share pastes with.
  • Give the uploader password only to people who should create pastes, and rotate both passwords if they may have leaked (Step 10).
  • Use your own DNS name and a certificate your clients trust (Step 9).
  • Use Private or Secret for anything sensitive, and short expiries.
  • 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

MicroBin is open source under the BSD 3-Clause License; there is no per user or per CPU licence fee. The licence is in /usr/share/doc/microbin/. cloudimg is not affiliated with or endorsed by the MicroBin project. 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