AdventureLog on Ubuntu 24.04 on Azure User Guide
Overview
AdventureLog is a self-hosted travel companion. It lets you log the countries and regions you have visited, plan future trips, pin your adventures on an interactive world map and keep your travel photos in one private place. The cloudimg image installs the official AdventureLog self-host Docker Compose stack, pinned to v0.12.1: a SvelteKit frontend (the web UI), a Django/GeoDjango + Gunicorn backend (the REST API, media and Django admin) and a PostgreSQL 16 database with the PostGIS extension for the geospatial features. Every secret - the PostgreSQL password, the Django SECRET_KEY and the admin password - is generated uniquely on the first boot of every VM, and a fresh admin account is seeded on a clean database. Backed by 24/7 cloudimg support.
What is included:
- The official AdventureLog v0.12.1 self-host stack running under Docker (the
webfrontend, theserverbackend and a PostgreSQL 16 + PostGISdb), pinned so it never silently upgrades - The SvelteKit frontend published on port
80and the backend (REST API, media and Django admin) on port8016 - A per-VM admin account generated on first boot - a unique password recorded in a root-only file - so every VM is secured independently
- The customer-facing URLs (
ORIGIN,PUBLIC_URL,CSRF_TRUSTED_ORIGINS) resolved to your VM's reachable address at first boot, so sign-in and CSRF work out of the box - The whole stack managed as one
adventurelog.servicesystemd unit, plusdocker.service, both enabled - PostgreSQL bound to the internal Docker network only - just
22/tcp(SSH),80/tcp(UI) and8016/tcp(backend/media/API) are exposed - 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting size for the three-container stack. NSG inbound: allow 22/tcp from your management network, and 80/tcp and 8016/tcp from the clients that will use AdventureLog. The app serves plain HTTP; for production, put it behind your own domain and TLS.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for AdventureLog by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22), then add 80 and 8016 after deployment. Review + create -> Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name adventurelog \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name adventurelog --port 80 --priority 1010
az vm open-port --resource-group <your-rg> --name adventurelog --port 8016 --priority 1020
Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 - Confirm the stack is running
AdventureLog runs as a Docker Compose stack managed by a single systemd unit. On first boot the stack rotates every secret, re-points its URLs at your VM's address, recreates itself on a fresh database and seeds the admin account; the multi-container stack can take a minute or two to become fully healthy after the VM is created.
systemctl is-active adventurelog.service
It reports active. You can list the running containers with:
sudo docker compose -f /var/lib/adventurelog/docker-compose.yml ps

The whole stack is managed as one systemd unit - use sudo systemctl status adventurelog and sudo systemctl restart adventurelog to control every container together.
Step 5 - Retrieve your per-VM admin credentials
The admin password is generated uniquely on the first boot of your VM and written to a root-only file. Confirm the file exists (it is 0600, root-only):
sudo ls -l /root/adventurelog-credentials.txt
Then read it to get your credentials:
sudo cat /root/adventurelog-credentials.txt
The file contains adventurelog.url (the address to browse to), adventurelog.admin.username (admin), adventurelog.admin.email and DJANGO_ADMIN_PASSWORD (for the web UI). Store them somewhere safe.

Step 6 - Confirm the endpoints are healthy
The SvelteKit frontend answers on port 80 and the Django backend answers on port 8016:
curl -s -o /dev/null -w 'frontend -> HTTP %{http_code}\n' http://localhost/
It returns HTTP 200. The backend REST API is reachable on port 8016:
curl -s -o /dev/null -w 'backend -> HTTP %{http_code}\n' http://localhost:8016/api/
It also returns HTTP 200. You can confirm which ports are published (PostgreSQL is deliberately not among them - it stays on the internal Docker network):
sudo ss -tlnp | grep -E ':80 |:8016 ' | awk '{print $1, $4}'

Step 7 - Confirm the pinned release
The images are pinned to AdventureLog v0.12.1 so the appliance never silently upgrades:
sudo docker compose -f /var/lib/adventurelog/docker-compose.yml images

Step 8 - Sign in to the web UI
Browse to http://<vm-public-ip>/ and sign in with the username admin and the password from Step 5.

After signing in, the dashboard welcomes you and summarises your travels - the number of adventures logged, countries and regions visited, and your most recent entries.

Step 9 - Log adventures and explore the map
Under Locations you see every adventure you have logged, with its category, rating and whether you have visited it or are still planning to.

The Map plots each adventure on an interactive world map and tracks your completion across the places you want to see.

Logging your first adventure
AdventureLog groups your travels into collections and pins individual adventures on the map. In the web UI: select Add New Location, give it a name, a place (city and country) and coordinates so it appears on the map, set a rating and mark it visited or planned, and optionally add it to a collection (for example a specific trip). Under World Travel you can mark the countries and regions you have visited to build up your world map. Everything you create is stored in PostgreSQL with PostGIS on your own VM.
If you prefer the REST API, the backend is served on port 8016 and uses session authentication - sign in at /accounts/login/ to obtain a session, then create objects under /api/collections/ and /api/locations/:
# Illustrative - substitute your admin password for <DJANGO_ADMIN_PASSWORD>
BASE=http://<vm-public-ip>:8016
# 1. Get a CSRF cookie, 2. sign in, 3. create a collection with the session cookie
curl -c cj -b cj "$BASE/accounts/login/" -o /dev/null
# ... POST login=admin, password=<DJANGO_ADMIN_PASSWORD>, csrfmiddlewaretoken to /accounts/login/
# ... POST {"name":"European Summer 2026"} to /api/collections/ with the X-CSRFToken header
See the AdventureLog documentation for the full API and feature reference.
Maintenance
- Admin credentials: the per-VM admin account is in
/root/adventurelog-credentials.txt; change the password from your profile settings in the web UI after first sign-in. - Custom domain: the URLs are pinned to the VM's address at first boot. If you reach the VM via a DNS name or a different IP, update
ORIGIN,FRONTEND_URL,PUBLIC_URLandCSRF_TRUSTED_ORIGINSin/var/lib/adventurelog/.env, then runsudo systemctl restart adventurelog. - Data: the PostgreSQL database and your uploaded media live in the
postgres_dataandadventurelog_mediaDocker volumes - snapshot the OS disk, or usepg_dumpagainst thedbcontainer, for backups. - Stack: manage the whole stack with
sudo systemctl <status|restart|stop> adventurelog, or per-container withsudo docker compose -f /var/lib/adventurelog/docker-compose.yml <ps|logs|restart>. - TLS: AdventureLog serves plain HTTP; front it with your own domain and TLS before production use.
- Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.
Support
cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.