Applications AWS

AdventureLog 0.13.1 on AWS User Guide

| Product: AdventureLog 0.13.1 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and verifying AdventureLog 0.13.1 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg self-hosted personal apps listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

AdventureLog is the open-source (GPL-3.0) travel journal and trip planner. Log the places you have been and want to go, with dates, ratings, notes, links and photos; group them into collections with itineraries, checklists, notes, lodging and transport; and 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.

What is on the image:

  • 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) and postgis/postgis:16-3.6 (PostgreSQL 16 with PostGIS)
  • Docker CE (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: HTTPS on port 443 with a self-signed certificate created on first boot, 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 it, and adventurelog-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: first boot generates a 28-character admin password, a 64-character Django SECRET_KEY and a 40-character database password on each instance, so no two instances share one. The only account is admin.
  • 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 will not start unless the secrets exist, are root-only and long enough, DEBUG is off, registration is off and every URL names a real HTTPS host. nginx stays closed until first boot has proved that the admin password really signs in.
  • No secret in the container configuration. The containers read their secrets from root-only files when they start, so docker inspect, the compose files and the logs never show one.
  • 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:3000 and the API on 127.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 (any other Host header gets its connection closed), uses TLS 1.2 or 1.3, refuses cross-origin POST requests (403), sends no CORS grants, rate-limits sign-in attempts, forces the session cookie to Secure, HttpOnly and SameSite=Lax, and replaces any client-supplied X-Forwarded-For, X-Real-IP or Forwarded header 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 links, redirects and cookies cannot be steered by a request.
  • 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 it, a firewall chain on the stack's Docker bridge rejects every new connection from the containers to link-local (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, are reloaded in one atomic step, and nginx, Docker and the AdventureLog units are also blocked from metadata by systemd IPAddressDeny. 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 run with no-new-privileges, a memory limit and core dumps off.
  • No scheduled firmware-metadata refresh. The fwupd firmware updater stays installed, but its LVFS metadata refresh (fwupd-refresh.timer and .service) is masked, so an LVFS outage never marks your instance unhealthy at boot; run sudo fwupdmgr refresh yourself if you use it.
  • 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

  1. An AWS account and permission to launch EC2 instances
  2. An EC2 key pair in the Region you launch in
  3. 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 are comfortable 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

Version Operating system SSH user
AdventureLog 0.13.1 on Ubuntu 24.04 Ubuntu 24.04 LTS ubuntu

Step 1: Launch the instance

Option A: AWS Marketplace console

  1. Open the cloudimg Hardened Actual Budget & Self-Hosted Personal Apps AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
  2. Once the subscription is active, choose Launch your software.
  3. 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.
  4. Pick an instance type (m5.large recommended; the software charge is $0.04 per vCPU per hour) and your key pair.
  5. Security group: the listing's default group opens SSH (22), HTTP (80) and HTTPS (443). Restrict SSH to your own IP address, and 80 and 443 to the networks you work from.
  6. 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, and 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: the AMI already requires IMDSv2. If you want the address to survive a stop and start, associate an Elastic IP.

Step 2: 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 (the instance's public IP address, so the session cookie works without a DNS name), creates the TLS certificate for it, generates the secrets, creates the database, imports the world reference data, creates the admin account, proves the password signs in, and writes /root/adventurelog-credentials.txt (mode 0600, root). Only then does it open nginx. These are the entries in that file, then the names of every key it holds (the password itself is not shown here):

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.txt
ADVENTURELOG_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:root
Value 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 and store it in your password manager.

Step 3: Confirm AdventureLog is running

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 cloudimg-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"))
ok

/healthz is answered by nginx itself and reveals nothing, so it is safe to use as a load balancer health check.

Step 4: Prove the login and the web defaults

A signed-out visit to the dashboard is sent to the sign-in page, 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.sh
dashboard, 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 session

Step 5: Sign 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:

The AdventureLog sign-in page with username and password fields and a Login button

A new instance has no locations, no collections and no visited places.

Step 6: Add locations and a collection

Add locations from Locations > New (search a place or click the map), or with the API the web app uses. This signs in once, adds three locations and a trip collection, and lists 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, Slovenia

The Locations page lists them, each with its place and visibility:

The AdventureLog Locations page with three location cards, Edinburgh Castle, Lake Bled and Fushimi Inari Taisha

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:

The AdventureLog World Travel page listing countries with their flags, region counts and visited filters

The map tiles, place search and remote images are fetched from the internet by your browser or the instance, so an instance with no outbound access still works but shows no map background.

Step 7: Check the security controls

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, 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 CLOUDIMG-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/pgdata
image fetch of instance metadata -> 400
subject=CN = 100.61.157.28, O = cloudimg
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 CLOUDIMG-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/pgdata

The API and database containers start as root inside the container only so their own process managers can drop to the www-data and postgres users; they keep no other capabilities.

Step 8: 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 it, updates nginx's accepted names, AdventureLog's site, CSRF and cookie settings and the cross-origin guard, records the name in /etc/cloudimg/adventurelog-hostname (kept across reboots), restarts AdventureLog and updates ADVENTURELOG_URL:

sudo adventurelog-set-hostname travel.example.com
adventurelog-set-hostname: AdventureLog is served at https://travel.example.com/

Until you set a name, the instance follows its own public IP address: if it comes back from a stop and start with a new address, the certificate and settings are updated at boot.

To use a certificate from your own CA or from Let's Encrypt instead, replace /etc/ssl/adventurelog/adventurelog.crt and /etc/ssl/adventurelog/adventurelog.key (keep the key mode 0600, owner root), set the name with adventurelog-set-hostname first so the automatic refresh leaves your certificate alone, and run sudo systemctl reload nginx.

Step 9: Add users and change settings

Sign-up is off, so you create accounts yourself. Sign in to AdventureLog as admin (Step 5), then open ADVENTURELOG_ADMIN_URL (https://<public-ip>/admin/) in the same browser; the Django admin uses that session. Find Users in the model list, choose Add user, and 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.

The AdventureLog Django administration site listing the Accounts and Adventures models, with Add and Change links

Each user's Settings page (the avatar menu) changes their name, email, password, measurement units, public profile and the optional Immich photo integration.

Step 10: Change the admin password, or recover from a lock-out

Change the admin password in Settings > Password. If you lose it, 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-password

Keep the file at mode 0600, owner root, and update /root/adventurelog-credentials.txt with sudo nano (or delete that file) so it does not hold a stale password.

Maintenance

  • Logs: sudo docker logs adventurelog-server (API), sudo docker logs adventurelog-web (web app), /var/log/nginx/ for HTTPS access, sudo journalctl -u adventurelog-firstboot.service -u adventurelog-postboot.service for first boot.
  • Restart: sudo systemctl restart adventurelog, or sudo systemctl restart nginx.
  • Backups: the database is in /var/lib/adventurelog/pgdata and uploaded photos and files in /var/lib/adventurelog/media. Take EBS snapshots of the root volume, or dump the database with sudo docker exec adventurelog-db pg_dump -U adventure adventurelog > adventurelog.sql and 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 rest with sudo apt update && sudo apt upgrade in a maintenance window.
  • Upgrading AdventureLog: the images are pinned by digest and first boot never pulls. To upgrade deliberately, read the release notes, back up, pull the new backend and frontend releases by digest, change the two image: lines in /opt/adventurelog/docker-compose.yml and run sudo systemctl restart adventurelog. Keep the cap_drop, security_opt, read_only, ulimits, loopback ports and network settings (including the al-web0 bridge name 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. On a new instance it waits until first boot has proved the credentials, by design. Check with sudo journalctl -u adventurelog-postboot.service --no-pager | tail -20 and sudo systemctl status adventurelog.

AdventureLog does not start. sudo journalctl -u adventurelog --no-pager | tail -20 shows the start-up check's reason, for example 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.

Signed in, but the page shows an error after changing 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 a name that resolves to one), which this image refuses by design. Images from your VPC are not supported; download the image and upload it instead.

Support

cloudimg provides 24/7 support for this image by email and live chat: 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. cloudimg is not affiliated with or endorsed by them.