Adventurelog
Overview
AdventureLog is a self-hosted travel companion. You log the countries and regions you have visited, plan future trips, pin adventures on an interactive world map and keep your travel photos in one private place.
This SecureAnyCloud image installs the official AdventureLog self-host Docker Compose stack, pinned to v0.12.1. The stack has 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 geospatial features. Every secret is generated uniquely on the first boot of every VM, and a fresh admin account is seeded on a clean database.
What you get:
- 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, with 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 and API) are exposed - A unique PostgreSQL password, Django SECRET_KEY and admin password for every VM
- 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting size for the three-container stack.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network, and 80/tcp and 8016/tcp from the clients that will use AdventureLog. The app serves plain HTTP, so 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 SecureAnyCloud, and select Create.
On the Basics tab, 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). Add ports 80 and 8016 after deployment.
Select Review + create, then Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:adventurelog-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name adventurelog \
--image sac1647283583153:adventurelog-ubuntu-24-04:default:latest \
--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 1020Step 3 - Connect to your VM
Connect to the VM over SSH:
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 and re-points its URLs at your VM's address. It then 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. Check the unit:
systemctl is-active adventurelog.serviceThe command reports active. List the running containers with:
sudo docker compose -f /var/lib/adventurelog/docker-compose.yml psThe 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 that the file exists. It is mode 0600, root-only:
sudo ls -l /root/adventurelog-credentials.txtThen read the file to get your credentials:
sudo cat /root/adventurelog-credentials.txtThe 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. Check the frontend first:
curl -s -o /dev/null -w 'frontend -> HTTP %{http_code}\n' http://localhost/It returns HTTP 200. Now check the backend REST API on port 8016:
curl -s -o /dev/null -w 'backend -> HTTP %{http_code}\n' http://localhost:8016/api/It also returns HTTP 200. Finally, confirm which ports are published. PostgreSQL is deliberately not among them, because 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 imagesStep 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.
The dashboard summarises your travels: the number of adventures logged, the countries and regions visited, and your most recent entries.
Step 9 - Log adventures and explore the map
Open Locations to see every adventure you have logged, with its category, rating and whether you have visited it or still plan to.
Open Map to see each adventure plotted on an interactive world map. The map also tracks your progress 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 the location a name, a place (city and country) and coordinates so that it appears on the map. Set a rating, mark it visited or planned, and optionally add it to a collection, for example a specific trip.
Under World Travel, 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.
You can also use 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 headerThe AdventureLog documentation has 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 your first sign-in. - Custom domain. The URLs are pinned to the VM's address at first boot. If you reach the VM by 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 and backups. The PostgreSQL database and your uploaded media live in the
postgres_dataandadventurelog_mediaDocker volumes. For backups, snapshot the OS disk or runpg_dumpagainst thedbcontainer. - Stack control. Manage the whole stack with
sudo systemctl <status|restart|stop> adventurelog. Manage individual containers 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 you run it in production.
- Security patches. Unattended upgrades remain enabled, so the OS keeps receiving security updates automatically.
Support
SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.
Deploy on Azure
Launch AdventureLog on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
AdventureLog is a self-hosted travel tracker and trip planner. You log the countries and regions you have visited, plan upcoming trips, pin adventures on an interactive map, organise them into collections and store your travel photos. It is a single web application that stays entirely on your own instance.
This SecureAnyCloud image runs AdventureLog as the three official upstream containers, each pinned by immutable digest and orchestrated by docker compose under a single systemd service. AdventureLog itself is a Django and GeoDjango REST backend with PostgreSQL and the PostGIS spatial extension, paired with a SvelteKit web frontend.
Security is enforced from first boot. Upstream AdventureLog ships build-time defaults for its Django secret key, PostgreSQL password and administrator password. This image never ships those defaults. Before the stack starts, each instance generates a unique Django secret key, PostgreSQL password and administrator password on a fresh database. Every customer-facing URL is re-pointed at the instance's own reachable address.
What you get:
- AdventureLog v0.12.1, the GPL-3.0 licensed travel tracker and trip planner, shipped as the three official upstream containers pinned by immutable digest
- The SvelteKit frontend on host port 80 and the Django and GeoDjango backend (REST API, uploaded media and the Django admin) on host port 8016
- A bundled PostgreSQL 16 with the PostGIS spatial extension, reachable only inside the private container network and never published to a host port
- Docker Engine and the docker-compose plugin from the official Docker APT repository
- A unique Django secret key, PostgreSQL password and administrator password generated on each instance's first boot, on a fresh database
- The Docker data root, holding the pre-pulled digest-pinned images, the travel database and uploaded media, on a dedicated data volume at
/var/lib/docker. Your travel data survives OS-disk changes, and you can resize the volume independently. docker.service,adventurelog-firstboot.serviceandadventurelog.serviceas systemd units, enabled and active- 24/7 SecureAnyCloud support
Prerequisites
You need an AWS account, an EC2 key pair in the target region, and a VPC with a public subnet.
m5.large (2 vCPU / 8 GiB RAM) is the recommended instance type.
Configure the security group to allow inbound 22/tcp from your management network for SSH. Also allow 80/tcp and 8016/tcp for the web UI and backend API from wherever your users browse.
Step 1 - Launch the AMI
Subscribe to the listing in AWS Marketplace. Then launch an instance from the AMI into your VPC with the security group described above. Choose the m5.large instance type and attach your EC2 key pair.
The three container images are pre-pulled onto the dedicated data volume. The AdventureLog stack therefore comes up within a few minutes of first boot, with no image re-pull, while it rotates its secrets and initialises a fresh database.
Step 2 - Connect to your instance
Connect over SSH as the default login user for the OS variant you launched. The login user differs per OS, so use the row for your variant:
OS variant SSH login user Example
Ubuntu 24.04 ubuntu ssh -i your-key.pem ubuntu@<instance-public-ip>
ssh -i your-key.pem ubuntu@<public-ip>Step 3 - Read your unique credentials
On first boot the instance generates a unique administrator password and seeds a fresh administrator on a clean database. It writes the credentials, together with the resolved web URL, to a root-only file. Read the file with sudo:
sudo cat /root/adventurelog-credentials.txtThe output looks like the example below. The URL and password are unique to your instance:
# AdventureLog self-host — generated on first boot by adventurelog-firstboot.service
# These credentials are unique to this instance. Store them somewhere safe. adventurelog.url=http://<instance-public-ip> adventurelog.admin.username=admin adventurelog.admin.email=admin@sac.local DJANGO_ADMIN_PASSWORD=<unique-per-instance-password>
# The Django admin backend is at http://<instance-public-ip>:8016/admin/ .
# Browse to http://<instance-public-ip>/ and sign in as 'admin' with the password above.The image contains no default or shared login. Every secret is unique to this instance.
Step 4 - Verify the security model from the command line
Confirm the three services are active and the stack is running the digest-pinned images:
systemctl is-active docker adventurelog adventurelog-firstboot
sudo docker compose -f /var/lib/adventurelog/docker-compose.yml ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"active active active SERVICE STATUS PORTS server Up 6 minutes 8000/tcp, 0.0.0.0:8016->80/tcp, [::]:8016->80/tcp db Up 6 minutes 5432/tcp web Up 6 minutes 0.0.0.0:80->3000/tcp, [::]:80->3000/tcpThe db (PostgreSQL with PostGIS) container exposes 5432/tcp on the container only. There is no host mapping, so the database is reachable only inside the private container network. Confirm this from the host's listening sockets. Only SSH, the frontend and the backend are bound, never PostgreSQL:
sudo ss -tlnp | grep -E ":80 |:8016 |:5432 " | awk '{print $1, $4}'LISTEN 0.0.0.0:80 LISTEN 0.0.0.0:8016Port 5432 returns nothing on the host, so PostgreSQL is never exposed. Next, confirm that the frontend and backend both answer locally:
curl -s -o /dev/null -w 'frontend %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'backend %{http_code}\n' http://127.0.0.1:8016/api/frontend 200 backend 200Step 5 - Sign in to the web UI
Open the web UI in a browser at http://<instance-public-ip>/. Sign in as admin with the password from /root/adventurelog-credentials.txt. The dashboard summarises how many adventures you have logged and how much of the world you have visited.
The Locations view lists every adventure you have logged, with a filter and sort sidebar. Each card shows its place, rating and visited or planned status.
The Map view pins every adventure on an interactive world map, so you can see your travels at a glance.
The World Travel view tracks which of the world's countries and regions you have visited, with per-region progress.
Step 6 - Log an adventure through the REST API
AdventureLog exposes a REST API on the backend port (8016). The web UI uses it, and you can call it directly.
The example below authenticates as your per-instance administrator and creates a collection. It then shows that an unauthenticated create is rejected. The script reads the admin password into a shell variable first, so the password never appears on screen:
PW=$(sudo grep '^DJANGO_ADMIN_PASSWORD=' /root/adventurelog-credentials.txt | cut -d= -f2-) B=http://127.0.0.1:8016
J=$(mktemp)
# establish a CSRF-protected session as the admin curl -s -c $J -b $J -o /dev/null $B/accounts/login/
C=$(awk '$6=="csrftoken"{print $7}' $J | tail -1)
curl -s -c $J -b $J -o /dev/null -w 'login %{http_code}\n' \
-H "Referer: $B/accounts/login/" -H "Origin: $B" \
--data-urlencode "login=admin" --data-urlencode "password=$PW" \
--data-urlencode "csrfmiddlewaretoken=$C" $B/accounts/login/
# create a collection, then read it back
C=$(awk '$6=="csrftoken"{print $7}' $J | tail -1)
curl -s -c $J -b $J -H 'Content-Type: application/json' -H "X-CSRFToken: $C" \
-H "Origin: $B" -H "Referer: $B/" -X POST $B/api/collections/ \
-d '{"name":"My first trip"}' -w '\ncreate %{http_code}\n'
# an unauthenticated create is rejected (no anonymous data)
curl -s -o /dev/null -w 'unauth %{http_code}\n' -H 'Content-Type: application/json' \
-X POST $B/api/collections/ -d '{"name":"nope"}' rm -f $JThe authenticated login returns 302 and the create returns 201. The unauthenticated create returns a non-2xx status, which shows that the API assigns your identity on write and never persists anonymous objects.
Step 7 - Point the instance at your own domain
First boot points every URL at the instance's public IP, so login and CSRF work out of the box. If you reach the instance by a DNS name or a different address, for example behind an Application Load Balancer, edit the four URL settings in the environment file and restart the service:
sudo sed -i \
-e 's|^ORIGIN=.*|ORIGIN=https://<your-domain>|' \
-e 's|^FRONTEND_URL=.*|FRONTEND_URL=https://<your-domain>|' \
-e 's|^PUBLIC_URL=.*|PUBLIC_URL=https://<your-domain>:8016|' \
-e 's|^CSRF_TRUSTED_ORIGINS=.*|CSRF_TRUSTED_ORIGINS=https://<your-domain>,https://<your-domain>:8016|' \
/var/lib/adventurelog/.env
sudo systemctl restart adventurelog.serviceFor production, terminate TLS at an Application Load Balancer or your own reverse proxy in front of ports 80 and 8016, using a certificate for your domain.
Data volume, backups and updates
The Docker data root at /var/lib/docker is a dedicated EBS data volume. It holds the three digest-pinned images, the PostgreSQL and PostGIS travel database (the postgres_data volume) and your uploaded photos (the adventurelog_media volume).
Because the volume is a separate disk, you can grow it independently of the OS disk. You can back it up with EBS snapshots or AWS Backup. SecureAnyCloud support can help you plan backups and schedule restores.
Open source and source availability
AdventureLog is licensed under the GNU General Public License version 3. This image ships the official upstream container images unmodified; the complete corresponding source for the version shipped here (v0.12.1) is available from the upstream project at github.com/seanmorley15/AdventureLog. SecureAnyCloud's charges are for the packaging, hardening and support services described here, not for the software licence. SecureAnyCloud is not affiliated with, endorsed by, or sponsored by the AdventureLog project; the AdventureLog name and logo are used nominatively to identify the software.
Support
SecureAnyCloud provides 24/7 technical support for this product by email and live chat at sales@secureanycloud.com. We help with deployment, re-pointing the instance at your own domain or DNS name, reverse-proxy TLS termination, and backup planning for your travel database and uploaded media.
Deploy on AWS
Launch AdventureLog with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com