Apache Allura 1.22.1 on AWS User Guide
Overview
This guide covers launching and using the Apache Allura 1.22.1 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg Apache Subversion (SVN) and CI/CD Tools listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
Apache Allura is the Apache Software Foundation's open source forge, the software behind SourceForge. Every project gets its own space with a Git repository, a ticket tracker, a wiki, discussion forums, a blog, file releases and an activity feed, with fine grained permissions, merge requests, full text search and a REST API.
The cloudimg image adds:
- The current release, verified. Allura 1.22.1 is the official Apache release tarball, checked against the SHA-512 the ASF publishes. It carries the fixes for every Allura security advisory published up to its release, including the critical CVE-2026-118196 that every release up to 1.22.0 is affected by (source: Apache Allura's own 1.22.1 release note), and the earlier CVE-2026-75099, CVE-2026-80180, CVE-2026-80181, CVE-2026-80190, CVE-2026-81270, CVE-2026-92116, CVE-2026-92119 and CVE-2026-92120 among them.
- Its Python dependencies pinned and patched. Every Python package is pinned by hash at the versions Allura 1.22.1 ships, with anyio raised past its published advisory within Allura's own version range, and a
pip-auditof the shipped environment is a build gate. - No MongoDB, no SSPL. Allura speaks the MongoDB protocol. This image gives it FerretDB 2.7.0 (Apache-2.0) on PostgreSQL 17 with the DocumentDB extension instead of MongoDB, so every component is under an open source licence. FerretDB is compiled from its source with a current Go toolchain and patched modules, so the binary carries no known reachable vulnerability.
- Search on a supported Solr. Allura's search runs on Apache Solr 10.1.0, the current Solr release line, with Allura's search schema ported to it.
- Debug mode off. Upstream's sample configuration runs Allura in debug mode, which puts an interactive Python debugger on every error page. This image switches it off.
- A datastore, keys and an administrator of your instance's own. Nothing secret is baked into the image: there is no database at all until your instance's first boot creates its own PostgreSQL cluster, its datastore password, Allura's session signing key and the master key for Allura's field level encryption, then runs Allura's own setup with exactly one administrator,
admin, with a password generated on your instance. Upstream's demo accounts (with the published passwordfoo) are never created. Secrets never appear on a command line or in a log. - HTTPS from the first boot. nginx serves Allura on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS and the session cookie is HTTPS only.
- Fail closed. nginx and Allura do not start until first boot has finished; if first boot cannot complete, the site stays offline rather than open.
- Closed by default. Public registration is off (the administrator creates accounts), and Allura does not call out to check passwords against an online breach list.
- Links from other sites cannot act for you. Every form submission and every other request that changes something, and the log out, only work when they come from your site itself. Allura's sign in and API pages cannot be pulled into another page as an image or a frame.
- A rate-limited sign in. nginx allows 10 attempts a minute from one address at every sign in, password recovery and OAuth endpoint (after a burst of 10), using the address of the connection, never a header a client sends.
- The real host and client address. nginx hands Allura the host name you configure and nothing a request claims, removes
X-Forwarded-Forand every other forwarding header a client sends, and Allura records the address of the connection. - Backends on loopback only. PostgreSQL has no network listener at all (local socket only), and FerretDB, Solr (with its admin interface switched off) and Allura's own web server listen on
127.0.0.1only. The open ports are 22, 80 and 443. - Every backend asks for a credential. Being on loopback is not treated as being safe. Solr requires a password generated on your instance's first boot (Solr's own BasicAuth), FerretDB requires its own password and its debug endpoint is switched off, and PostgreSQL accepts local socket logins only.
- Allura cannot be turned against your network. Allura fetches addresses that its users type in: webhooks, project importers, repository imports and video embeds. Every one of those requests is refused if it is aimed at this instance's own services, a private network, a link-local address or the instance metadata service, however the address is written. The check runs on the address actually connected to, after the DNS lookup and again at every redirect. A kernel level block backs it up for every program Allura runs, Git included, and Git may only use the
https,http,gitand local transports, without following redirects. - Hardened defaults. Allura, Solr, FerretDB and PostgreSQL each run as their own unprivileged user in a systemd sandbox. All program files belong to root and are read only to the services; nothing in Allura's data folders (repositories and their hooks, caches) can run as a program. Every service is blocked from the instance metadata service at the kernel level, the AMI requires IMDSv2, and requests for a host name the instance does not serve are dropped.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Apache Allura 1.22.1, FerretDB 2.7.0, PostgreSQL 17 with DocumentDB 0.107.0, Apache Solr 10.1.0 on OpenJDK 21, Python 3.12, Git, 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 (administrator SSH), TCP 443 (Allura) 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 Apache Allura 1.22.1 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (Allura, Solr and the database share the instance; 8 GiB of memory leaves room to grow), your key pair and a security group as above. The root volume holds the database, the search index and your repositories: size it for your projects.
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> \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=50,VolumeType=gp3}' \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=allura}]'
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Apache Allura 1.22.1 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot takes about a minute (it creates the database, starts Solr and runs Allura's setup). Then the six services and the first boot unit are active:
systemctl is-active allura-firstboot postgresql@17-main ferretdb solr allura-web allura-taskd nginx
active
active
active
active
active
active
active
Only SSH and nginx listen on the network. FerretDB, Solr and Allura's web server listen on 127.0.0.1 (Solr's second port is its local stop port), and PostgreSQL has no TCP port at all:
sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|gunicorn|ferretdb|java|postgres/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
State Local Peer
LISTEN 127.0.0.1:27017 users:(("ferretdb"))
LISTEN 127.0.0.1:8080 users:(("gunicorn:
LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:22 users:(("sshd"),("systemd"))
LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::ffff:127.0.0.1]:7983 users:(("java"))
LISTEN [::ffff:127.0.0.1]:8983 users:(("java"))
LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:22 users:(("sshd"),("systemd"))
LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))
The versions on the image:
grep -m1 '^Version' /opt/allura/CHANGES
/usr/local/bin/ferretdb --version | head -1
sudo -u postgres psql -tAc 'show server_version'
ls /opt/solr-10.1.0/server/solr-webapp/webapp/WEB-INF/lib/ | grep -m1 '^solr-core-'
echo "MongoDB packages installed: $(dpkg -l | grep -Eic 'mongodb-org|percona-server-mongodb' || true)"
Version 1.22.1 (November 2026)
version: v2.7.0
17.11 (Ubuntu 17.11-1.pgdg24.04+2)
solr-core-10.1.0.jar
MongoDB packages installed: 0
Step 4: Get your sign-in details
The credentials file holds the address Allura is served as (your instance's public DNS name by default) and the administrator's user name and password, generated on this instance:
sudo grep -E '^ALLURA_(URL|ADMIN_USER)=' /root/allura-credentials.txt
sudo grep -c '^ALLURA_ADMIN_PASSWORD=[A-Za-z0-9]\{24\}$' /root/allura-credentials.txt
ALLURA_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/
ALLURA_ADMIN_USER=admin
1
To see the password itself, sudo cat /root/allura-credentials.txt. Check the sign in end to end (the administrator signs in through the real form, a wrong password is refused, and port 80 redirects to HTTPS):
sudo allura-cred-roundtrip
OK https 301
Step 5: Sign in from your browser
Open ALLURA_URL in your browser. The certificate is self signed (generated on your instance), so your browser warns once: compare the certificate's SHA-256 fingerprint with the one on the instance (sudo openssl x509 -in /etc/nginx/ssl/allura.crt -noout -fingerprint -sha256) and continue, or install a certificate from your own certificate authority (Step 10). A fresh forge shows the projects home page:

Choose Log In and sign in with admin and the password from Step 4:

You land on your dashboard, which lists your projects, tickets, merge requests and recent activity (empty on a new forge):

Step 6: Create a project
Choose Add Project (or open /p/add_project). Give the project a name and a short URL name (letters, digits and dashes, at most 15 characters), keep the tools you want and choose Create:

Allura's background worker sets the tools up in a few seconds. The project has a summary page, a wiki, a Git repository (Code), tickets, discussion forums and an admin section:

Step 7: Wiki, tickets and search
Open Wiki and edit the Home page. Allura's Markdown editor has formatting buttons and a preview (rendered by the server, with Allura's own HTML sanitising):

Saving renders the page and keeps every revision:

Tickets is the project's issue tracker; every ticket has a status, owner, milestone, labels and a threaded discussion:

Allura's task worker indexes wiki pages, tickets, forum posts and commits into Solr a few seconds after you save them, and the project's Search finds them:

Step 8: Your Git repository
Each project's Code tool is a Git repository, created by Allura under /var/lib/allura/scm/git. Browse files, commits and branches in the browser, compare and merge branches with merge requests, or fork a repository into another project:

The repository folders belong to the allura service user. Allura does not include a Git server for pushes from workstations, and this image does not add one, so nobody can push a repository (or plant a hook in one) over the network. You can also import an existing repository: Admin, Import (Allura clones it, as the service user, without copying any hooks).
To push from your workstation as the instance administrator, push over your SSH login and run Git's receiving side as the allura user (replace the values in angle brackets; the repository path is /var/lib/allura/scm/git/p/<project>/<tool>.git):
git remote add allura ssh://ubuntu@<instance-dns-name>/var/lib/allura/scm/git/p/webapp/code.git
git push --receive-pack='sudo -n -u allura git-receive-pack' allura main
Allura's own post-receive hook then refreshes the repository, so the commits show up in the browser. On the instance, every repository and its hooks belong to allura:
sudo find /var/lib/allura/scm/git -mindepth 3 -maxdepth 3 -name '*.git' -printf '%u:%g %p\n'
sudo find /var/lib/allura/scm/git -path '*.git/hooks/post-receive' -printf '%u %m %p\n'
allura:allura /var/lib/allura/scm/git/p/webapp/code.git
Step 9: Security checks
Port 80 sends browsers to HTTPS, a visitor cannot register, nginx closes the connection for a host name the instance does not serve (000 means no answer), and Allura's debugger is not reachable:
H=$(sudo sed -n 's#^ALLURA_URL=https://\([^/]*\)/.*#\1#p' /root/allura-credentials.txt)
curl -s -o /dev/null -D - --resolve "$H:80:127.0.0.1" "http://$H/" | tr -d '\r' | awk 'NR==1{print "port 80:", $2} tolower($1)=="location:"{print " to:", ($2 == "https://'"$H"'/" ? "https://<this host>/" : $2)}'
curl -sk -o /dev/null -w 'sign in page: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/auth/"
curl -sk -o /dev/null -w 'registration page: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/auth/create_account"
curl -sk -o /dev/null -w 'debugger: %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/?__debugger__=yes&cmd=resource&f=style.css"
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
to: https://<this host>/
sign in page: 200
registration page: 404
debugger: 302
unknown host name: 000
A form submitted from another site is refused before it reaches Allura, and so is a sign in page requested as an image or a frame inside another page (the refusals come from nginx):
H=$(sudo sed -n 's#^ALLURA_URL=https://\([^/]*\)/.*#\1#p' /root/allura-credentials.txt)
curl -sk --resolve "$H:443:127.0.0.1" -H 'Origin: https://example.com' -d 'username=x&password=y' "https://$H/auth/do_login"
curl -sk --resolve "$H:443:127.0.0.1" -H 'Sec-Fetch-Site: cross-site' -X DELETE "https://$H/p/webapp/wiki/Home/"
curl -sk --resolve "$H:443:127.0.0.1" -H 'Sec-Fetch-Dest: iframe' "https://$H/auth/"
cloudimg: cross-site state-changing request refused
cloudimg: cross-site state-changing request refused
cloudimg: /auth/ or /rest/ requested as a subresource refused
Scripts that use Allura's REST API with an OAuth bearer token in the Authorization header (and no browser cookie) are not affected.
The settings behind this, in Allura's configuration file:
sudo grep -E '^(set )?debug = |^(base_url|domain|session\.secure|auth\.allow_user_registration|ip_address_header) = ' /opt/allura/Allura/cloudimg.ini | sed -E 's#(base_url = https://|domain = ).*#\1<this host>#'
debug = false
set debug = false
ip_address_header = X-Real-IP
domain = <this host>
base_url = https://<this host>
session.secure = true
auth.allow_user_registration = false
The datastore, the search engine and the web server are reachable on loopback only, and PostgreSQL accepts local socket logins only. FerretDB requires a login (its debug endpoint is off), and Solr answers 401 to any request without the password Allura uses:
sudo -u postgres psql -tAc "show listen_addresses" | sed 's/^$/(no TCP listener)/'
sudo grep -vE '^\s*(#|$)' /etc/postgresql/17/main/pg_hba.conf
sudo grep -E '^FERRETDB_(LISTEN_ADDR|AUTH|DEBUG_ADDR)=' /etc/ferretdb/ferretdb.env
systemctl show -p ExecStart --value ferretdb | grep -o 'argv\[\]=[^;]*'
grep -E '^SOLR_(HOST_BIND|UI_ENABLED)=' /etc/default/solr.in.sh
/opt/allura-venv/bin/python -c 'import pymongo; c = pymongo.MongoClient("mongodb://127.0.0.1:27017/", serverSelectionTimeoutMS=5000)
try:
c.admin.command("listDatabases"); print("anonymous read: allowed")
except Exception as e:
print("anonymous read:", "refused" if "requires authentication" in str(e) else e)'
curl -s -o /dev/null -w 'Solr without a password: %{http_code}\n' 'http://127.0.0.1:8983/solr/allura/select?q=*:*'
sudo sed -n 's/^solr\.pass = \(.*\)/user = "allura:\1"/p' /opt/allura/Allura/cloudimg.ini | curl -s -o /dev/null -K - -w "Solr with Allura's password: %{http_code}\n" 'http://127.0.0.1:8983/solr/allura/admin/ping'
(no TCP listener)
local all postgres peer
local all all peer map=cloudimg
FERRETDB_LISTEN_ADDR=127.0.0.1:27017
FERRETDB_AUTH=true
argv[]=/usr/local/bin/ferretdb --debug-addr=
SOLR_HOST_BIND="127.0.0.1"
SOLR_UI_ENABLED="false"
anonymous read: refused
Solr without a password: 401
Solr with Allura's password: 200
Allura's own Python refuses to connect to the metadata service, to this instance's backends and to private networks, while a public address works (the same check applies to webhooks, importers and embeds):
/opt/allura-venv/bin/python -c '
import urllib.request
for u in ("http://169.254.169.254/latest/meta-data/", "http://127.0.0.1:8983/solr/", "http://2130706433:27017/", "http://[::ffff:10.0.0.1]/", "https://www.apache.org/"):
try:
print(u, "->", urllib.request.urlopen(u, timeout=10).status)
except Exception as e:
print(u, "-> refused" if "cloudimg egress guard" in str(e) else "-> %s" % e)'
http://169.254.169.254/latest/meta-data/ -> refused
http://127.0.0.1:8983/solr/ -> refused
http://2130706433:27017/ -> refused
http://[::ffff:10.0.0.1]/ -> refused
https://www.apache.org/ -> 200
Every service runs as its own user and is blocked from the instance metadata service (Allura's two services are also blocked from private and link-local networks, which is why their list is longer):
for u in allura-web allura-taskd solr ferretdb postgresql@17-main nginx; do printf '%s: %s %s\n' "$u" "$(systemctl show -p User --value $u)" "$(systemctl show -p IPAddressDeny --value $u)"; done
allura-web: allura 192.168.0.0/16 10.0.0.0/8 198.18.0.0/15 169.254.0.0/16 192.0.0.0/24 ::/128 224.0.0.0/3 fe80::/10 fec0::/10 172.16.0.0/12 168.63.129.16/32 100.64.0.0/10 ::1/128 127.0.0.0/8 0.0.0.0/8 64:ff9b:1::/48 fc00::/7 ff00::/8
allura-taskd: allura 172.16.0.0/12 ::1/128 fe80::/10 100.64.0.0/10 0.0.0.0/8 fc00::/7 64:ff9b:1::/48 192.168.0.0/16 198.18.0.0/15 168.63.129.16/32 ::/128 224.0.0.0/3 10.0.0.0/8 192.0.0.0/24 127.0.0.0/8 ff00::/8 169.254.0.0/16 fec0::/10
solr: solr 169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
ferretdb: ferretdb 169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
postgresql@17-main: 169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
nginx: 169.254.169.254/32 fd00:ec2::254/128 168.63.129.16/32
The certificate was generated on this instance and names its own addresses:
H=$(sudo sed -n 's#^ALLURA_URL=https://\([^/]*\)/.*#\1#p' /root/allura-credentials.txt)
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -ext basicConstraints,extendedKeyUsage | sed -E 's/^ +//'
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Server Authentication
Step 10: Your own DNS name and certificate
Point a DNS record at the instance, then set the name Allura is served as. This mints a new self signed certificate for the name, updates nginx, Allura's base_url and domain (so links and notification mails use it) and the URL in /root/allura-credentials.txt, and restarts Allura:
sudo allura-set-hostname forge.example.com
To use a certificate from your certificate authority instead, replace /etc/nginx/ssl/allura.crt and /etc/nginx/ssl/allura.key (keep the key 0600 root) and run sudo systemctl reload nginx. Behind a load balancer or proxy that terminates TLS, forward to port 443 of the instance and keep the Host header as the name above.
Step 11: Accounts, e-mail, passwords and backups
- Accounts. Public registration is off. To let people register themselves, set
auth.allow_user_registration = truein/opt/allura/Allura/cloudimg.iniand runsudo systemctl restart allura-web allura-taskd; otherwise create accounts for them asadminunder Site Admin. - E-mail. Allura sends notifications and password resets to
localhost:25, and the image has no mail server. Pointsmtp_server,smtp_port(andsmtp_tls,smtp_user,smtp_passwordif needed) incloudimg.iniat your mail relay, such as Amazon SES, then restartallura-webandallura-taskd. - The admin password.
sudo allura-set-passwordsets a new random password foradminand writes it to/root/allura-credentials.txt(orsudo allura-set-password <user>for another account; it prints the new password). - Backups. Allura's data is the PostgreSQL cluster (
/var/lib/allura/pg17), the repositories (/var/lib/allura/scm) and/opt/allura/Allura/cloudimg.ini, which holds the field level encryption master key: without it, Allura's encrypted fields (e-mail addresses and other personal data) cannot be read. Snapshot the EBS volume, or stopallura-web allura-taskd ferretdband back up those paths. The Solr index (/var/lib/solr/data) can be rebuilt from the datastore. - Webhooks and imports from your private network. Allura refuses to send webhooks to, or import from, private addresses. To allow one internal network (for example
10.0.5.0/24), runsudo systemctl edit allura-taskdandsudo systemctl edit allura-web, add these lines to each, seturlopen_allow_internal_hostnames = trueincloudimg.iniand restart both services. This instance's own services, link-local addresses and the metadata service stay blocked whatever you allow.
text
[Service]
Environment=CLOUDIMG_EGRESS_ALLOW=10.0.5.0/24
IPAddressAllow=10.0.5.0/24
- Upgrades. Ubuntu security updates install automatically. For a new Allura release, follow the upgrade notes in
/opt/allura/CHANGES.
Step 12: Server components
| Component | Version | Listens on | Runs as |
|---|---|---|---|
| Apache Allura (gunicorn) | 1.22.1 | 127.0.0.1:8080 | allura |
| Allura task worker | 1.22.1 | - | allura |
| FerretDB | 2.7.0 | 127.0.0.1:27017 | ferretdb |
| PostgreSQL + DocumentDB | 17 + 0.107.0 | local socket only | postgres |
| Apache Solr | 10.1.0 | 127.0.0.1:8983 | solr |
| nginx | 1.24 | 0.0.0.0:80, 0.0.0.0:443 | www-data |
Files: the application in /opt/allura and /opt/allura-venv (root's, read only), the configuration in /opt/allura/Allura/cloudimg.ini (0640 root:allura), the data in /var/lib/allura, Allura's logs in /var/log/allura and journalctl -u allura-web -u allura-taskd.
Step 13: Security recommendations
- Keep port 22 open to your own networks only, and use your own certificate (Step 10) before inviting users.
- Keep the backends on loopback: never open 8080, 8983 or 27017 in your security group. Solr's password is in
cloudimg.ini; keep that file0640 root:allura. - Back up
cloudimg.initogether with your data (Step 11). - If you open registration, review new accounts under Site Admin and consider requiring e-mail confirmation (configure e-mail first).
Support and licensing
Apache Allura, Apache Solr and FerretDB are licensed under the Apache License 2.0, PostgreSQL under the PostgreSQL Licence and DocumentDB under the MIT licence. cloudimg provides the image, its hardening and support; Allura itself is developed by the Apache Software Foundation. For help with this image, contact cloudimg support through the AWS Marketplace listing.