Gs
Applications AWS

GlobaLeaks Whistleblowing Platform on AWS User Guide

| Product: GlobaLeaks on AWS

Overview

This image runs GlobaLeaks, the open source platform for receiving confidential reports. Newsrooms, NGOs, regulators, universities and companies use it to run a reporting channel that the public, employees or suppliers can use to raise concerns.

A reporter opens the platform in a browser, answers the questions your organisation configured, optionally attaches files, and receives a randomly generated receipt code. That code is the only handle on the report. It lets the reporter come back later to read replies and continue the conversation without ever creating an account or supplying an email address.

On the receiving side, reports land in an inbox only designated recipients can open. GlobaLeaks separates duties across distinct roles so no single person holds every power: administrators configure the platform, recipients read and work reports, custodians can be required to approve access to a reporter's identity, and analysts see statistics without report content.

GlobaLeaks is published under the GNU Affero General Public License version 3 or later, with additional terms permitted by section 7 of that licence which require the project's attribution notices to be preserved. This image ships the official upstream package unmodified, installed from the project's own signed package repository, so those notices appear exactly as the project publishes them. The repository stays configured on the instance, so you keep receiving upstream security updates, and it is also where the corresponding source is available.

The platform is a single service with an embedded database. There is no separate database server, application server or web server to operate.


Read this before you accept real reports

This image gets you a working platform in minutes. It does not, on its own, make your reporting channel safe for a source who is genuinely at risk. Three things are your decision, and two of them should be settled before you publish the address to anyone.

1. The certificate is self signed until you replace it

The instance generates its own TLS certificate at first boot, so HTTPS works immediately and browsers warn on every visit. A self signed certificate encrypts the connection, but it does not let a reporter verify they reached your platform rather than an impostor. Anyone able to intercept traffic could present their own certificate and a reporter has no way to tell the difference.

Point a DNS name at the instance and install a trusted certificate before you publish the address. Step 7 walks through it; the platform has a built in ACME client that can obtain one automatically.

2. This image is not an anonymity network

By default a reporter connects to your instance directly over the internet. Their network operator, your cloud provider and anyone observing the path can see that a connection to your platform happened, even though its contents are encrypted. For many organisations, running an internal integrity or speak up channel, that is perfectly acceptable. For a source whose safety depends on nobody knowing they contacted you, it is not.

GlobaLeaks can also publish a Tor onion service, which is the mechanism that hides a reporter's network address from observers and from the platform itself. This image publishes no onion service unless you switch it on. That is deliberate: upstream GlobaLeaks generates and publishes one automatically the first time it creates its database, and an image that quietly joined the Tor network and published a hidden service from your account before you had even finished the setup wizard would be making that decision for you. The capability is fully intact and one click away. Step 8 covers it.

The platform tells reporters this itself: the landing page carries a banner advising visitors to use Tor Browser.

3. cloudimg does not certify this image against any compliance regime

Whether a deployment satisfies a legal obligation depends on how you configure, operate, host and document it. That assessment is yours to make. Nothing in this image or this guide is a statement that it is compliant with any standard or directive.

What the platform does not record

GlobaLeaks does not write reporters' IP addresses to its access log. The log's client address field is a literal - unless the request carries an authenticated session whose role is explicitly not whistleblower, so submissions and reporter logins are never attributed to an address. Optional access logging applies only to signed in staff accounts, which is an accountability feature rather than a reporter one. Step 5 shows you how to confirm this on your own instance.

This is also why the image does not put a reverse proxy in front of GlobaLeaks. A proxy would add a second request log, outside the application's control, that does record reporter addresses.

One upstream behaviour worth knowing about

GlobaLeaks always starts a Tor client process, even when no onion service is configured, and that process makes outbound connections to Tor relays. Nothing is published and nothing extra listens, but if you do not want any Tor traffic leaving your account, restrict the instance's outbound rules. The platform serves normally either way; it simply records in its log that Tor is unavailable.


The security model of this image

Two ports carry your traffic and are the only application ports this image expects to be open:

Port Purpose
80 The platform over HTTP. Redirects to HTTPS.
443 The platform over HTTPS. This is what reporters and staff use.

GlobaLeaks runs unprivileged, so it actually binds the high ports 8080 and 8443, and its own startup helper installs kernel redirect rules that put ports 80 and 443 onto them. You do not need to configure that.

Nothing sensitive is baked into the image. There is no administrator account and no platform database at all. The first person to open the platform completes the setup wizard and chooses the administrator credentials and recovery key on that instance. The database, the receipt salt, the node identity and the TLS key pair are all created on your own instance at first boot, so no two customers ever share a secret.

Your passphrase never leaves your browser. GlobaLeaks derives an encryption key from it locally and sends only that derived key, and report content is encrypted to account keys derived the same way. An operator with disk access cannot simply read submissions. That also means a lost passphrase and lost recovery key mean lost reports, so store the recovery key the wizard gives you somewhere safe.


Prerequisites

Before you deploy this image you need:

  • 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 allowing inbound port 22 from your management network, and ports 80 and 443 from wherever your reporters and staff will reach the platform
  • A DNS name you can point at the instance, if you intend to accept real reports

m5.large is the recommended instance type and is what this listing is priced against.


Step 1: Launch the instance

From the AWS Marketplace, subscribe to the product, choose Launch through EC2, and pick your Region, instance type, key pair, subnet and security group.

From the AWS CLI, launch it directly. Replace the AMI id with the one shown on the listing for your Region, and the key pair, subnet and security group with your own:

aws ec2 run-instances \
  --image-id ami-xxxxxxxxxxxxxxxxx \
  --instance-type m5.large \
  --key-name your-key-pair \
  --subnet-id subnet-xxxxxxxx \
  --security-group-ids sg-xxxxxxxx \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=globaleaks}]'

The image carries a dedicated 50 GiB data volume for the platform's own state, attached and mounted automatically. You do not need to add one.

Allow a couple of minutes after the instance reaches the running state. First boot creates the platform database, generates the TLS key pair and writes an instance note before the platform starts.

Step 2: Connect over SSH

Log in with the key pair you selected at launch, as the login user for your variant:

AMI variant Login user
GlobaLeaks on Ubuntu 24.04 ubuntu
ssh -i your-key.pem ubuntu@<public-ip>

The login banner summarises the state of the instance and points at the instance note.

Step 3: Confirm the platform is up

Everything in this step is read only, and every command fails loudly rather than quietly, so you can paste the block as it stands.

systemctl is-active globaleaks.service globaleaks-firstboot.service
systemctl is-enabled globaleaks.service
active
active
enabled

Check the platform answers its health endpoint. GlobaLeaks terminates HTTPS itself and the kernel redirect does not apply to traffic originating on the instance, so on box checks talk to port 8443 directly:

code=$(curl -ks -o /dev/null -w '%{http_code}' --max-time 10 https://127.0.0.1:8443/api/health)
echo "GlobaLeaks /api/health -> HTTP ${code}"
[ "${code}" = "200" ] || { echo "platform is not healthy"; exit 1; }
GlobaLeaks /api/health -> HTTP 200

Confirm the installed version:

dpkg-query -W -f='${Package} ${Version}\n' globaleaks
globaleaks 5.0.99

Step 4: Check what is listening, and what is not

A whistleblowing platform should not be exposing anything you did not ask for. Only three sockets on this image accept traffic from outside the instance: SSH, and the platform's two ports behind the kernel redirect.

sudo ss -tlnH | awk '{print $4}' | sort
*:8080
*:8443
0.0.0.0:22
127.0.0.1:8083
127.0.0.53%lo:53
127.0.0.54:53
[::]:22

127.0.0.1:8083 is the platform's own backend for the Tor onion service. It is bound to the loopback address, so it is unreachable from outside the instance whether or not you ever enable that feature. The two entries on port 53 are the operating system's local DNS resolver. Nothing is listening on port 9050: the standalone system Tor service is masked in this image, because GlobaLeaks manages its own Tor process when you enable the onion service and does not use the system one.

The kernel rules that put the standard ports onto the platform:

sudo iptables -t nat -S PREROUTING | grep globaleaks
-A PREROUTING -p tcp -m comment --comment globaleaks -m tcp --dport 80 -j REDIRECT --to-ports 8080
-A PREROUTING -p tcp -m comment --comment globaleaks -m tcp --dport 443 -j REDIRECT --to-ports 8443

Step 5: Verify the image shipped clean

This is the check worth running before you trust the instance with anything. It asserts, against the live platform, that the image shipped with no completed wizard, no account, no onion service and no reporter address in the access log, and it exits non zero if any of those is untrue.

sudo /usr/local/sbin/globaleaks-selfcheck.sh
OK: health 200, setup wizard pending, 0 user accounts, no onion service, outgoing anonymisation off, system Tor masked, no client IP in the access log

The two facts that matter most, on their own:

users=$(sudo sqlite3 -readonly /var/globaleaks/globaleaks.db 'select count(*) from user;')
wiz=$(curl -ks --max-time 10 https://127.0.0.1:8443/api/public | jq -r '.node.wizard_done')
echo "accounts on this platform: ${users}"
echo "setup wizard completed:    ${wiz}"
[ "${users}" = "0" ] || { echo "this platform already holds accounts"; exit 1; }
[ "${wiz}" = "false" ] || { echo "the setup wizard has already been completed"; exit 1; }
accounts on this platform: 0
setup wizard completed:    false

Administrative endpoints refuse anonymous callers. GlobaLeaks answers with HTTP 412 and the message Not Authenticated, so this block treats anything else as a failure:

code=$(curl -ks -o /dev/null -w '%{http_code}' --max-time 10 https://127.0.0.1:8443/api/admin/users)
echo "unauthenticated GET /api/admin/users -> HTTP ${code}"
[ "${code}" = "412" ] || { echo "an admin endpoint answered an anonymous caller with ${code}"; exit 1; }
echo "refused as expected"
unauthenticated GET /api/admin/users -> HTTP 412
refused as expected

And no reporter address has been recorded. The access log's second field is the client address, and on this platform it is always -:

sudo awk '$2 != "-" {bad++} END {print "lines:", NR+0, "with a client IP recorded:", bad+0; exit (bad+0)>0}' /var/globaleaks/log/access.log
lines: 14 with a client IP recorded: 0

The number of lines will differ on your instance. The number with a client address recorded should always be zero.

The instance note first boot wrote for you carries this instance's URL and the same warnings as this guide. It holds no secret, because there is no secret to hold:

sudo grep '^GLOBALEAKS_URL=' /root/globaleaks-credentials.txt
sudo stat -c '%a %U:%G' /root/globaleaks-credentials.txt
GLOBALEAKS_URL=https://44.204.74.241/
600 root:root

The URL will show your own instance's address.

Step 6: Complete the first run setup wizard

Browse to https://<public-ip>/. Your browser will warn about the certificate, because the instance generated its own; accept the warning for now and fix it properly later in this step.

Because no account exists yet, the platform takes you straight to its setup wizard.

The GlobaLeaks first run setup wizard on a freshly launched instance

Work through the wizard:

  1. Language, then Project name, which is what reporters see at the top of your channel.
  2. Admin account: username, name, email address and password. This is created on your instance at this moment and nowhere else.
  3. Recipient account: the person who will read reports. You can add more later, and you can skip this if your administrator will also be the recipient.
  4. Licence: read and accept the GNU Affero General Public License. Leave Notify developers of software problems unticked unless you actively want to send diagnostics upstream.

The wizard then shows you an account recovery key. Store it somewhere safe and offline. Report content is encrypted to keys derived from account passphrases, so if you lose both the passphrase and the recovery key, the reports cannot be recovered by anyone, including us.

Once the wizard is done, the administration console is at https://<public-ip>/#/login.

The GlobaLeaks administration console

Under Users you can see the role separation the platform is built around, and add recipients, custodians and analysts:

Role separated accounts in the GlobaLeaks user list

Step 7: Install a trusted certificate for a real domain

Do this before you publish the address.

  1. Create a DNS A record pointing your chosen name at the instance's public address, and confirm it resolves.
  2. Make sure ports 80 and 443 are open inbound in the security group. The ACME challenge needs port 80.
  3. In the console go to Network, then the HTTPS tab, enter your hostname and save.
  4. Follow the ACME option to have the platform request and install a certificate automatically, or upload your own key, certificate and chain if your organisation issues its own.

The platform renews ACME certificates itself. You do not need certbot on this instance, and you should not install a separate web server to terminate TLS: doing so adds a request log outside the application's control.

Verify what is being presented at any point with:

echo | openssl s_client -connect 127.0.0.1:8443 2>/dev/null | openssl x509 -noout -subject -issuer -dates

On a freshly launched instance, before you have configured anything, the subject and issuer are the same, which is exactly what a self signed certificate looks like:

subject=CN = 127.0.0.1
issuer=CN = 127.0.0.1
notBefore=Jul 26 21:53:26 2026 GMT
notAfter=Jan  1 00:00:00 3000 GMT

After a trusted certificate is installed, the issuer will be your certificate authority instead.

Step 8: Decide about anonymous reporting

Go to Network, then the Tor tab. On a fresh instance the Tor Onion Service field is empty, because this image publishes none until you ask:

The Tor onion service settings, with no onion service published

  • If your reporters need genuine anonymity, use Regenerate to create and publish an onion service, then publish the .onion address alongside your normal one and tell reporters to reach it with Tor Browser. This is the only configuration in which a reporter's network address is hidden from observers and from your platform.
  • If your channel is an internal speak up line where the identity of the network a report came from is not the risk you are managing, leaving it off is a reasonable choice. Say so plainly on your reporting page so nobody assumes protection they are not getting.

Anonymize outgoing connections routes the platform's own outbound traffic, such as email notifications, over Tor. Let the platform be reachable without Tor controls, per role, whether people may use the ordinary address at all; you can require staff to use Tor while leaving the clearnet path open for reporters, or the reverse.

Step 9: Configure your channel and test it end to end

Under Questionnaires and Channels, adapt the default questionnaire to what your organisation actually needs to ask. Under Notifications, point the platform at your SMTP server so recipients are told when a report arrives.

Then send yourself a test report before you go live. Open https://<public-ip>/ in a private browser window, choose Submit a report, and fill in the form:

The reporter's submission form

Save the receipt code the platform gives you at the end. Then:

  1. Sign in as the recipient and confirm the report is in the inbox and readable.
  2. Reply to it from the recipient view.
  3. Return to the landing page, enter the receipt code in the Have you already submitted a report? box, and confirm you can read the reply as the reporter would.
  4. Delete the test report when you are done. Deleting reports is a permission an administrator grants to a recipient under Users; a new recipient does not have it by default.

If all four work, your channel is functioning.

The data volume

All platform state, the report database, the receipt salt, the node identity, the TLS key pair, encrypted attachments and the logs, lives on a dedicated EBS volume mounted at /var/globaleaks. It is separate from the operating system disk, so you can resize, snapshot and encrypt the report store on its own.

findmnt -no SOURCE,TARGET,FSTYPE,SIZE /var/globaleaks
grep ' /var/globaleaks ' /etc/fstab
df -h /var/globaleaks | tail -1
/dev/nvme1n1 /var/globaleaks ext4   48.9G
UUID=30488071-4e77-463c-a95e-e03533110cbc /var/globaleaks ext4 defaults,nofail 0 2
/dev/nvme1n1     49G  780K   47G   1% /var/globaleaks

The mount is recorded by filesystem UUID, so it survives reboots and instance replacement. To grow it, modify the EBS volume in the EC2 console, then run sudo resize2fs /dev/nvme1n1 on the instance.

Backups

Everything worth backing up is under /var/globaleaks. An EBS snapshot of that volume is the simplest complete backup, and because the report content is encrypted to account keys, the snapshot is not readable without those credentials.

If you prefer a file level backup, stop the platform first so the database is quiescent:

sudo systemctl stop globaleaks
sudo tar -czf /var/tmp/globaleaks-backup.tar.gz -C /var globaleaks
sudo systemctl start globaleaks

Store backups somewhere at least as protected as the instance itself. Remember that restoring a backup restores the reports inside it.

Updates

The official GlobaLeaks package repository stays configured on this instance, so security updates come from the project itself:

sudo apt-get update
sudo apt-get install --only-upgrade globaleaks
sudo systemctl restart globaleaks

Take a snapshot of the data volume before a major version upgrade. GlobaLeaks migrates its database on first start after an upgrade, and that migration is not reversible.

Troubleshooting

The platform does not answer. Check the service and, if it is not running, read its log:

systemctl is-active globaleaks.service
active
sudo journalctl -u globaleaks.service --no-pager | tail -40
sudo tail -40 /var/globaleaks/log/globaleaks.log

The platform never started after launch and the service reports a condition failure. The platform is deliberately gated behind first boot completing, so it will not start against an unprepared instance. Check first boot ran:

test -f /var/lib/cloudimg/globaleaks-firstboot.done && echo "first boot completed" || { echo "first boot has not completed"; exit 1; }
first boot completed

If it has not, inspect sudo journalctl -u globaleaks-firstboot.service.

The browser warns about the certificate. That is expected until you complete Step 7. It is a warning about trust, not a fault.

Reporters say the site is slow to load the first time. The platform starts a Tor client at startup regardless of whether an onion service is configured, and that has no bearing on the ordinary HTTPS path. If your outbound rules block Tor, the platform logs that Tor is unavailable and continues serving normally.

I forgot the administrator passphrase. Use the account recovery key from the wizard. Without either, the encrypted report content cannot be recovered by anyone.

Support

cloudimg provides 24/7 technical support for this image by email at support@cloudimg.co.uk and by live chat, covering deployment, TLS and ACME setup, the optional Tor onion service, SMTP notifications, recipient and role configuration, data volume resizing and hardening.

For questions about GlobaLeaks itself, the project maintains documentation at docs.globaleaks.org and a community forum at forum.globaleaks.org.