AdventureLog 0.13.1
Overview
AdventureLog is the open-source (GPL-3.0) travel journal and trip planner. You log the places you have been and want to go, with dates, ratings, notes, links and photos. You group them into collections with itineraries, checklists, notes, lodging and transport, and you track the countries, regions and cities you have visited on a world map. Everything is private to your account unless you choose to share it.
This guide covers launching and verifying AdventureLog 0.13.1 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud self-hosted personal apps listing on AWS Marketplace. You choose this version when you subscribe and launch.
What you get:
- AdventureLog 0.13.1 from the three official upstream container images, each pinned by digest:
ghcr.io/seanmorley15/adventurelog-backend:v0.13.1(Django API and admin),ghcr.io/seanmorley15/adventurelog-frontend:v0.13.1(the web app) andpostgis/postgis:16-3.6(PostgreSQL 16 with PostGIS) - Docker CE from the official Docker apt repository, running the stack under the systemd unit
adventurelog.service - The world reference data (countries, regions and cities, plus country flags) already on the image, so first boot needs no internet access
- nginx as the only network-facing service, with HTTPS on port 443 using a self-signed certificate created on first boot, and port 80 redirecting to HTTPS
- A per-instance admin password, Django secret key and database password, generated on first boot into root-only files
adventurelog-set-hostname, a helper that serves AdventureLog under your own DNS name and re-issues the certificate for itadventurelog-reset-password, a root-only recovery command- Default user:
ubuntu - Architecture: x86_64
- Root volume: 20 GiB gp3
Security posture
- No default login. Upstream's example configuration ships a fixed admin password, Django secret key and database password. None of them is on this image. Instead, first boot generates a 28-character admin password, a 64-character Django
SECRET_KEYand a 40-character database password on each instance, so no two instances share one. The only account isadmin. - No open sign-up. Self-registration and social sign-up are off (
403), so nobody can create an account on your instance. You add users yourself in the Django admin. - Fails closed. AdventureLog does not start unless the secrets exist, are root-only and are long enough,
DEBUGis off, registration is off and every URL names a real HTTPS host. nginx stays closed until first boot has proved that the admin password signs in. - No secret in the container configuration. The containers read their secrets from root-only files when they start.
docker inspect, the compose files and the logs therefore never show a secret. - No example data. A new instance has exactly one account and no locations or collections.
- Only nginx faces the network. The web app listens on
127.0.0.1:3000and the API on127.0.0.1:8016. PostgreSQL sits on an internal Docker network with no host port and no route off the instance. nginx answers only for the configured hostname and closes the connection for any otherHostheader. It uses TLS 1.2 or 1.3, refuses cross-originPOSTrequests (403), sends no CORS grants and rate-limits sign-in attempts. It also forces the session cookie toSecure,HttpOnlyandSameSite=Lax, and replaces any client-suppliedX-Forwarded-For,X-Real-IPorForwardedheader with the real peer address. - The hostname comes from configuration, never from a request. First boot reads the instance's public address from EC2 instance metadata (IMDSv2). nginx hands AdventureLog that fixed name, so a request cannot steer links, redirects or cookies.
- The containers cannot reach your private network or instance metadata. AdventureLog can fetch an image from a URL you enter. Its own URL filter refuses private, loopback and link-local addresses. Behind that filter, a firewall chain on the stack's Docker bridge rejects every new connection from the containers to link-local addresses (including the metadata service), carrier-grade NAT (
100.64.0.0/10, which the app's filter does not cover), RFC 1918 (your VPC), loopback and reserved ranges, and to the instance itself. Only DNS to the instance's own resolver is allowed. The rules are in place before Docker starts any container and are reloaded in one atomic step. nginx, Docker and the AdventureLog units are also blocked from metadata by systemdIPAddressDeny. This was proved at build time from inside the containers and through AdventureLog's own image fetcher. - Least-privilege containers. The web app runs as an unprivileged user (uid 65532) on a read-only filesystem with every Linux capability dropped. The API and database containers drop every capability except the few their own process managers need. All three containers run with
no-new-privileges, a memory limit and core dumps off. - No scheduled firmware-metadata refresh. The
fwupdfirmware updater stays installed, but its LVFS metadata refresh (fwupd-refresh.timerand.service) is masked. An LVFS outage therefore never marks your instance unhealthy at boot. If you use it, runsudo fwupdmgr refreshyourself. - No core dumps. nginx, the AdventureLog units and the containers run with core dumps disabled, so process memory holding your credentials is never written to disk.
- IMDSv2 required. The AMI is registered with
ImdsSupport v2.0, so instances refuse token-less (IMDSv1) metadata requests. - Per-instance identity. SSH host keys, the machine ID, the TLS certificate and Docker's engine ID are generated fresh on every instance.
Prerequisites
- An AWS account and permission to launch EC2 instances
- An EC2 key pair in the Region you launch in
- Outbound internet access from the instance, if you want map tiles, geocoding and remote images (the browser loads map tiles directly)
Recommended instance type: m5.large. AdventureLog, PostgreSQL and the web app run comfortably on 2 vCPUs and 8 GiB of memory for a household or a small team. Grow the root volume if you upload many photos.
Connecting to your instance
Connect to AdventureLog 0.13.1 on Ubuntu 24.04 (Ubuntu 24.04 LTS) over SSH as the ubuntu user.
Launch the instance
Option A: AWS Marketplace console
- Open the SecureAnyCloud Hardened Actual Budget & Self-Hosted Personal Apps AMIs listing on AWS Marketplace. Choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- When the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace, or Launch from EC2 Console for the full launch wizard. In Version, choose AdventureLog 0.13.1 on Ubuntu 24.04, then choose your Region.
- Pick an instance type and your key pair.
m5.largeis recommended, and the software charge is $0.04 per vCPU per hour. - Set the security group. The listing's default group opens SSH (22), HTTP (80) and HTTPS (443). Restrict SSH to your own IP address, and restrict ports 80 and 443 to the networks you work from.
- Choose your VPC and subnet, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.
Option B: AWS CLI
Run this on your own workstation. It creates a security group that allows SSH from your management address and HTTPS from your own network, then launches the instance. Replace the AMI ID with the one shown for your Region on the Marketplace launch page. Replace the VPC, subnet, key pair and CIDR ranges with your own:
SG=$(aws ec2 create-security-group --group-name adventurelog \
--description "AdventureLog" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 443 --cidr 203.0.113.0/24
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 80 --cidr 203.0.113.0/24
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=adventurelog}]'You do not need --metadata-options, because the AMI already requires IMDSv2. To keep the address across a stop and start, associate an Elastic IP.
Connect and find your login
Connect as ubuntu with the key pair you chose.
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>First boot takes a few minutes. It sets the hostname AdventureLog is served as, which is the instance's public IP address, so the session cookie works without a DNS name. It then creates the TLS certificate for that name, generates the secrets, creates the database, imports the world reference data and creates the admin account. It proves that the password signs in and writes /root/adventurelog-credentials.txt (mode 0600, root). Only then does it open nginx.
The commands below show the entries in that file, then the names of every key it holds. The password itself is not shown:
sudo grep -E '^ADVENTURELOG_(URL|ADMIN_URL|ADMIN_USERNAME)=' /root/adventurelog-credentials.txt
sudo grep -oE '^[A-Z_]+=' /root/adventurelog-credentials.txt | tr -d '='
sudo stat -c '%a %U:%G' /root/adventurelog-credentials.txtADVENTURELOG_URL=https://100.61.157.28/ ADVENTURELOG_ADMIN_URL=https://100.61.157.28/admin/ ADVENTURELOG_ADMIN_USERNAME=admin ADVENTURELOG_URL ADVENTURELOG_ADMIN_URL ADVENTURELOG_ADMIN_USERNAME ADVENTURELOG_ADMIN_PASSWORD 600 root:rootValue What it is for
ADVENTURELOG_URL The address of this instance's AdventureLog
ADVENTURELOG_ADMIN_URL The Django admin, where you manage users
ADVENTURELOG_ADMIN_USERNAME admin, the only account
ADVENTURELOG_ADMIN_PASSWORD The admin password, generated on this instance
To read the password, run sudo cat /root/adventurelog-credentials.txt in your own session, then store the password in your password manager.
Confirm AdventureLog is running
Confirm that Docker, the firewall unit, AdventureLog and nginx are active. Only sshd and nginx listen beyond loopback. The web app and the API are on loopback, and PostgreSQL has no host port at all:
systemctl is-active docker.service sac-docker-imds-deny.service adventurelog.service nginx.service
sudo docker ps --format '{{.Names}} {{.Image}} {{.Ports}}' | sed -E 's/@sha256:[0-9a-f]+//' | sort
sudo ss -Htlnp | awk '{print $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort -u
H=$(sudo sed -n 's/^set \$app_host "\(.*\)";$/\1/p' /etc/nginx/adventurelog-host.conf)
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/healthz"active active active active adventurelog-db postgis/postgis:16-3.6 5432/tcp adventurelog-server ghcr.io/seanmorley15/adventurelog-backend:v0.13.1 8000/tcp, 127.0.0.1:8016->80/tcp adventurelog-web ghcr.io/seanmorley15/adventurelog-frontend:v0.13.1 127.0.0.1:3000->3000/tcp 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:3000 users:(("docker-proxy")) 127.0.0.1:8016 users:(("docker-proxy")) 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")) oknginx answers /healthz itself and reveals nothing, so you can safely use it as a load balancer health check.
Prove the login and the web defaults
Check the web defaults. A signed-out visit to the dashboard is sent to the sign-in page, and the session API says nobody is signed in. Sign-up is refused, a cross-origin POST is refused, an unknown Host header gets no answer and plain HTTP redirects to HTTPS.
The last command signs in as admin with this instance's password, and once with a wrong one, and reports the result:
H=$(sudo sed -n 's/^set \$app_host "\(.*\)";$/\1/p' /etc/nginx/adventurelog-host.conf) R=(--resolve "$H:443:127.0.0.1") curl -sk "${R[@]}" -o /dev/null -w 'dashboard, signed out -> %{http_code}\n' "https://$H/dashboard" curl -sk "${R[@]}" -o /dev/null -w 'session API, signed out -> %{http_code}\n' "https://$H/auth/browser/v1/auth/session" jq -nc '{username:"newuser",email:"newuser@example.com",password:"Correct-Horse-Battery-9",first_name:"New",last_name:"User"}' | curl -sk "${R[@]}" -o /dev/null -w 'sign-up -> %{http_code}\n' -H "Origin: https://$H" -H 'Content-Type: application/json' \
--data-binary @- "https://$H/auth/browser/v1/auth/signup" curl -sk "${R[@]}" -o /dev/null -w 'cross-origin POST -> %{http_code}\n' -X POST -H 'Origin: https://evil.example' -d 'username=x&password=x' "https://$H/login" curl -sk -o /dev/null -w 'unknown Host -> %{http_code}\n' -H 'Host: evil.example' https://127.0.0.1/ || true curl -s -o /dev/null -w 'http -> %{http_code}\n' -H "Host: $H" http://127.0.0.1/
sudo adventurelog-roundtrip.shdashboard, signed out -> 302 session API, signed out -> 401 sign-up -> 403 cross-origin POST -> 403 unknown Host -> 000 http -> 301 OK round-trip https://100.61.157.28/: healthz 200; anonymous dashboard to /login; anonymous session API 401 and admin to its login; wrong password 400 and no session; per-VM admin login session cookie Secure HttpOnly SameSite=Lax; dashboard 200 and session API 200 with the sessionSign in to AdventureLog
Browse to ADVENTURELOG_URL (https://<public-ip>/). The certificate is self-signed, so your browser warns once. Accept it for this host, or install your own certificate (Step 8).
Sign in as admin with ADVENTURELOG_ADMIN_PASSWORD. The page still shows upstream's Signup link, but sign-up is switched off on this image and refuses every request.
A new instance has no locations, no collections and no visited places.
Add locations and a collection
Add locations from Locations > New by searching for a place or clicking the map. You can also use the API that the web app uses. The commands below sign in once, add three locations and a trip collection, and list them. The password goes to curl on standard input, so it never appears on a command line:
H=$(sudo sed -n 's/^set \$app_host "\(.*\)";$/\1/p' /etc/nginx/adventurelog-host.conf) R=(--resolve "$H:443:127.0.0.1");
J=$(mktemp); chmod 600 "$J" al() { curl -sk "${R[@]}" -b "$J" -c "$J" -H "Origin: https://$H" "$@"; }
sudo grep '^ADVENTURELOG_ADMIN_PASSWORD=' /root/adventurelog-credentials.txt | cut -d= -f2- | tr -d '\n' | al -o /dev/null -w 'sign in -> %{http_code}\n' --data-urlencode 'username=admin' --data-urlencode 'password@-' "https://$H/login" for p in 'Edinburgh Castle|Castlehill, Edinburgh, Scotland|55.9486|-3.1999' \
'Lake Bled|Bled, Slovenia|46.3625|14.0936' \
'Fushimi Inari Taisha|Kyoto, Japan|34.9671|135.7727'; do IFS='|' read -r n l la lo <<<"$p" jq -nc --arg n "$n" --arg l "$l" --arg la "$la" --arg lo "$lo" \
'{name:$n, location:$l, latitude:$la, longitude:$lo, is_public:false}' | al -H 'Content-Type: application/json' --data-binary @- "https://$H/api/locations" | jq -r '"added \(.name)"' done jq -nc '{name:"Summer in Europe", description:"Castles and lakes", start_date:"2027-06-12", end_date:"2027-06-26", is_public:false}' | al -H 'Content-Type: application/json' --data-binary @- "https://$H/api/collections" | jq -r '"collection \(.name)"' al "https://$H/api/locations" | jq -r '.results[] | "\(.name): \(.location)"' | sort rm -f "$J"sign in -> 200 added Edinburgh Castle added Lake Bled added Fushimi Inari Taisha collection Summer in Europe Edinburgh Castle: Castlehill, Edinburgh, Scotland Fushimi Inari Taisha: Kyoto, Japan Lake Bled: Bled, SloveniaThe Locations page lists them, each with its place and visibility.
World Travel shows the 250 countries from the reference data that shipped on the image. Open a country to mark the regions and cities you have visited.
Your browser or the instance fetches map tiles, place search results and remote images from the internet. An instance with no outbound access still works, but it shows no map background.
Check the security controls
Check that the security controls are in place. AdventureLog's image fetcher refuses the instance metadata service. The certificate was made for this instance on first boot and is a plain server certificate. The firewall chain on the stack's bridge rejects private destinations, and the units are denied metadata. The containers run with dropped capabilities, the database network is internal, and the secrets are closed to other users:
H=$(sudo sed -n 's/^set \$app_host "\(.*\)";$/\1/p' /etc/nginx/adventurelog-host.conf) R=(--resolve "$H:443:127.0.0.1");
J=$(mktemp); chmod 600 "$J" al() { curl -sk "${R[@]}" -b "$J" -c "$J" -H "Origin: https://$H" "$@"; }
sudo grep '^ADVENTURELOG_ADMIN_PASSWORD=' /root/adventurelog-credentials.txt | cut -d= -f2- | tr -d '\n' | al -o /dev/null --data-urlencode 'username=admin' --data-urlencode 'password@-' "https://$H/login" jq -nc '{url:"http://169.254.169.254/latest/meta-data/"}' | al -o /dev/null -w 'image fetch of instance metadata -> %{http_code}\n' -H 'Content-Type: application/json' \
--data-binary @- "https://$H/api/images/fetch_from_url" rm -f "$J" openssl s_client -connect 127.0.0.1:443 -servername "$H" </dev/null 2>/dev/null | openssl x509 -noout -subject -enddate -ext basicConstraints,extendedKeyUsage
sudo iptables -S DOCKER-USER
sudo iptables -S SAC-AL-EGRESS | grep -oE '\-d [0-9./]+ -j REJECT' | awk '{print $2}' | paste -sd' ' for u in nginx docker adventurelog; do echo "$u.service IPAddressDeny=$(systemctl show -p IPAddressDeny --value $u.service)"; done
sudo docker inspect --format '{{.Name}} user={{.Config.User}} cap_drop={{.HostConfig.CapDrop}} read_only={{.HostConfig.ReadonlyRootfs}}' \
adventurelog-web adventurelog-server adventurelog-db
sudo docker network inspect adventurelog-db --format 'database network {{.Name}}: internal={{.Internal}}'
sudo stat -c '%a %U:%G %n' /opt/adventurelog/secrets /opt/adventurelog/secrets/admin_password /root/adventurelog-credentials.txt
sudo stat -c '%a uid=%u %n' /var/lib/adventurelog/pgdataimage fetch of instance metadata -> 400 subject=CN = 100.61.157.28, O = sac notAfter=Feb 9 12:41:39 2029 GMT X509v3 Basic Constraints: critical CA:FALSE X509v3 Extended Key Usage: TLS Web Server Authentication -N DOCKER-USER -A DOCKER-USER -d 168.63.129.16/32 -j DROP -A DOCKER-USER -d 169.254.169.254/32 -j DROP -A DOCKER-USER -i al-web0 -j SAC-AL-EGRESS 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.168.0.0/16 198.18.0.0/15 224.0.0.0/4 240.0.0.0/4 nginx.service IPAddressDeny=169.254.169.254/32 168.63.129.16/32 docker.service IPAddressDeny=169.254.169.254/32 168.63.129.16/32 adventurelog.service IPAddressDeny=169.254.169.254/32 168.63.129.16/32 /adventurelog-web user=65532:65532 cap_drop=[ALL] read_only=true /adventurelog-server user= cap_drop=[ALL] read_only=false /adventurelog-db user= cap_drop=[ALL] read_only=false database network adventurelog-db: internal=true 700 root:root /opt/adventurelog/secrets 600 root:root /opt/adventurelog/secrets/admin_password 600 root:root /root/adventurelog-credentials.txt 700 uid=999 /var/lib/adventurelog/pgdataThe API and database containers start as root inside the container only so that their own process managers can drop to the www-data and postgres users. They keep no other capabilities.
Serve AdventureLog under your own DNS name
Point a DNS record at the instance (an Elastic IP keeps the address stable), then tell AdventureLog the name. The helper re-issues the self-signed certificate for the name and updates nginx's accepted names. It also updates AdventureLog's site, CSRF and cookie settings and the cross-origin guard. It records the name in /etc/sac/adventurelog-hostname, which is kept across reboots, restarts AdventureLog and updates ADVENTURELOG_URL:
sudo adventurelog-set-hostname travel.example.comadventurelog-set-hostname: AdventureLog is served at https://travel.example.com/Until you set a name, the instance follows its own public IP address. If the instance comes back from a stop and start with a new address, boot updates the certificate and settings.
To use a certificate from your own CA or from Let's Encrypt instead, first set the name with adventurelog-set-hostname, so the automatic refresh leaves your certificate alone. Then replace /etc/ssl/adventurelog/adventurelog.crt and /etc/ssl/adventurelog/adventurelog.key, keeping the key at mode 0600, owner root. Finally, run sudo systemctl reload nginx.
Add users and change settings
Sign-up is off, so you create accounts yourself. Sign in to AdventureLog as admin (Step 5). In the same browser, open ADVENTURELOG_ADMIN_URL (https://<public-ip>/admin/), because the Django admin uses that session.
Find Users in the model list and choose Add user. Set a username and a password of at least 8 characters that is not too common. Each user then signs in at ADVENTURELOG_URL and sees only their own locations and collections, plus anything shared with them.
Each user can change their name, email, password, measurement units, public profile and the optional Immich photo integration on the Settings page, which is in the avatar menu.
Change the admin password, or recover from a lock-out
Change the admin password in Settings > Password. If you lose the password, remove the admin's password, or switch off password sign-in for it, restore access from the shell. Put the new password (at least 20 characters) into the root-only first-boot password file, then run the recovery command. It sets that password, re-activates admin as a superuser and switches password sign-in back on:
sudo nano /opt/adventurelog/secrets/admin_password
sudo adventurelog-reset-passwordKeep the file at mode 0600, owner root. Update /root/adventurelog-credentials.txt with sudo nano, or delete that file, so that it does not hold a stale password.
Maintenance
- Logs: use
sudo docker logs adventurelog-serverfor the API andsudo docker logs adventurelog-webfor the web app. HTTPS access logs are in/var/log/nginx/. For first boot, runsudo journalctl -u adventurelog-firstboot.service -u adventurelog-postboot.service. - Restart: run
sudo systemctl restart adventurelogorsudo systemctl restart nginx. - Backups: the database is in
/var/lib/adventurelog/pgdata, and uploaded photos and files are in/var/lib/adventurelog/media. Take EBS snapshots of the root volume. Alternatively, dump the database withsudo docker exec adventurelog-db pg_dump -U adventure adventurelog > adventurelog.sqland copy the media directory. - Operating system updates: Ubuntu's unattended security upgrades stay on, so nginx, Docker and the rest of the OS keep receiving patches. Apply the remaining updates with
sudo apt update && sudo apt upgradein a maintenance window. - Upgrading AdventureLog: the images are pinned by digest, and first boot never pulls. To upgrade deliberately, read the release notes and back up. Then pull the new backend and frontend releases by digest, change the two
image:lines in/opt/adventurelog/docker-compose.ymland runsudo systemctl restart adventurelog. Keep thecap_drop,security_opt,read_only,ulimits, loopbackportsand network settings, including theal-web0bridge name that the firewall chain is keyed on. Never publish a port on all interfaces, and never use host networking, which would bypass both nginx and the firewall chain.
Troubleshooting
The sign-in page says the password is wrong. Use admin and ADVENTURELOG_ADMIN_PASSWORD from /root/adventurelog-credentials.txt exactly, over https://. After several failed attempts, AdventureLog locks sign-in for that username for a few minutes, and nginx answers 429 to quick repeated attempts. Wait and try again.
nginx is not running. By design, nginx on a new instance waits until first boot has proved the credentials. Check with sudo journalctl -u adventurelog-postboot.service --no-pager | tail -20 and sudo systemctl status adventurelog.
AdventureLog does not start. Run sudo journalctl -u adventurelog --no-pager | tail -20 to see the reason from the start-up check. Typical causes are a secret file whose mode was changed, or a settings file edited to turn DEBUG or registration on. Put the setting back and run sudo systemctl restart adventurelog.
You are signed in, but the page shows an error after you change the address. AdventureLog's cookies and cross-origin checks are tied to the configured name. Browse to the exact ADVENTURELOG_URL, or set the name you use with adventurelog-set-hostname.
An image from a URL will not load. The URL points at a private, loopback, link-local or carrier-grade NAT address, or at a name that resolves to one. This image refuses such addresses by design. Images from your VPC are not supported, so download the image and upload it instead.
Support
SecureAnyCloud provides 24/7 support for this image by email and live chat. Support covers launching and connecting, users and sharing, TLS and hostnames, and upgrades.
AdventureLog is developed by Sean Morley and contributors and is released under the GNU General Public License v3.0. The licence text, a pointer to the corresponding source and the attribution for the world reference data ship on the instance in /usr/share/doc/adventurelog/. PostGIS and PostgreSQL are released under their own open-source licences. Ubuntu is a registered trademark of Canonical Ltd. Docker is a trademark of Docker, Inc. All other product and company names are trademarks or registered trademarks of their respective holders. SecureAnyCloud is not affiliated with or endorsed by them.
Deploy on AWS
Launch AdventureLog 0.13.1 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com