wanderer
Overview
wanderer is an open source, self-hosted database for outdoor routes. You upload or draw trails on an interactive map, attach GPX tracks, waypoints, photos and notes, and keep your hiking, cycling and running routes together with distance, elevation and other stats in one place. Trails group into lists, can be private or shared, and are searchable instantly across everything you have recorded.
wanderer pairs a SvelteKit web frontend with PocketBase (a single Go binary that embeds an SQLite database) for your account and route data, and Meilisearch for fast full-text search. This SecureAnyCloud image runs the GPL-3.0 licensed wanderer application the officially supported way, as upstream containers pinned by image digest, alongside the MIT-licensed Meilisearch engine. All images are captured into the VM, so your instance starts in seconds.
The upstream project ships with open registration enabled and its search and backend keys set to public example values. This image ships with no known secret. On first boot of each VM, before the app is reachable, it generates a unique Meilisearch master key, a unique PocketBase encryption key, a per-instance app account and a separate backend superuser, each with a random password. Open sign-up is switched off by default.
wanderer, PocketBase and Meilisearch are trademarks of their respective owners. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by any of them. It ships the free and open source self-hosted software, unmodified.
What you get:
- wanderer v0.20.0 (the GPL-3.0 licensed SvelteKit frontend and PocketBase backend), pinned by image digest
- Meilisearch v1.36.0 (the MIT-licensed search engine) in production mode, so every request requires a key
- PocketBase's embedded SQLite database, created empty on first boot and stored on a persistent volume
- Docker Engine with the web frontend, PocketBase and Meilisearch on a private network, fronted by an in-network nginx proxy. The proxy is the only container published to the host, on port
80(/= web app,/pb/= PocketBase API) wanderer.service,wanderer-firstboot.serviceandwanderer-postboot.serviceas systemd units, enabled and active on boot- A unique Meilisearch master key, PocketBase encryption key, per-instance app account and separate backend superuser, each with a random password generated per VM on first boot and never baked into the image
- Open registration disabled by default, and the PocketBase admin console kept off the public port
- No default login, no shipped secret and an empty database on first boot
- Ubuntu 24.04 LTS base with the latest security patches applied at build time
- Azure Linux Agent for cloud integration and SSH key injection
- 24/7 SecureAnyCloud support with a 24-hour response SLA
Prerequisites
You need an active Azure subscription, an SSH public key, and a VNet with a subnet in the target region. You also need a subscription to the wanderer listing on Azure Marketplace.
Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) is a sensible starting point for a person, a household or a small club. For larger route libraries or many concurrent users, use Standard_D2s_v5 or larger.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the web app from the networks that use it.
Deploy from the Azure Portal
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for wanderer 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) and HTTP (80).
Select Review + create, then Create.
Deploy with the Azure CLI
Accept the Marketplace terms once per subscription, then create the VM:
RG="wanderer-prod"; LOCATION="eastus"; VM_NAME="wanderer-01" IMAGE_URN="sac1647283583153:wanderer-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name wanderer-vnet --address-prefix 10.100.0.0/16 --subnet-name wanderer-subnet --subnet-prefix 10.100.1.0/24 az network nsg create -g "$RG" --name wanderer-nsg az network nsg rule create -g "$RG" --nsg-name wanderer-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name wanderer-nsg --name allow-http --priority 110 \
--destination-port-ranges 80 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:wanderer-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name wanderer-vnet --subnet wanderer-subnet --nsg wanderer-nsg --public-ip-sku StandardReplace <sub-id> and <version> with your subscription ID and the image version shown on the listing. Replace <your-mgmt-cidr> with the network you administer from.
First boot and per-instance credentials
On the first boot of each VM, before the app is reachable, wanderer generates its own per-instance secrets and accounts. Nothing is baked into the image.
Wait a minute after first boot, then connect over SSH and read the credentials file. The file is 0600 root:root:
ssh azureuser@<vm-ip>
sudo cat /root/wanderer-credentials.txtThe file contains two accounts, both with per-instance random passwords:
WANDERER_USER_EMAIL/WANDERER_USER_PASSWORD: the app login you use in the web UI.PB_SUPERUSER_EMAIL/PB_SUPERUSER_PASSWORD: the PocketBase backend superuser for administering collections. Its admin console is not exposed on the public port (see Step 4).
Confirm that the services and containers are healthy:
sudo systemctl is-active docker wanderer-firstboot wanderer wanderer-postbootactive active active activedocker compose -f /opt/wanderer/docker-compose.yml psThe db (PocketBase) and search (Meilisearch) containers publish only to loopback and the internal network. The nginx proxy container is the single public entry point, on port 80.
The security model
SecureAnyCloud hardens every instance before the port is ever public. The web app, PocketBase and Meilisearch run as containers on a private Docker network. Only the nginx proxy is published, on port 80, routing / to the web app and /pb/ to the PocketBase API.
The PocketBase admin console (/pb/_/) is blocked at the proxy and returns 403. Meilisearch is never published to any host port. Open user registration is disabled by default (PUBLIC_DISABLE_SIGNUP=true).
Verify the proxy behaviour:
# the app is public on :80; PocketBase API is reachable for the browser via /pb/ curl -s -o /dev/null -w "app / -> %{http_code}\n" http://127.0.0.1/ curl -s -o /dev/null -w "pb /pb/api/health -> %{http_code}\n" http://127.0.0.1/pb/api/health
# the admin console is NOT public curl -s -o /dev/null -w "admin /pb/_/ -> %{http_code}\n" http://127.0.0.1/pb/_/app / -> 200 pb /pb/api/health -> 200 admin /pb/_/ -> 403To reach the PocketBase admin console, tunnel to the loopback container port over SSH. Then sign in with the superuser credentials:
ssh -L 8091:127.0.0.1:8091 azureuser@<vm-ip>
# then open http://localhost:8091/_/ in your browserVerify the end-to-end round trip
The image ships a verification script. It authenticates as the per-instance app account, creates a trail list through the public front door and reads it back. It also confirms that an unauthenticated create is rejected. Run it with:
sudo /usr/local/sbin/wanderer-roundtrip.shSign in to the web app
Open http://<vm-ip>/ in your browser. Sign in with the WANDERER_USER_EMAIL and WANDERER_USER_PASSWORD from the credentials file.
The home view shows your activity feed of trails and lists, each with its recorded distance, elevation gain and loss, and duration.
Choose New Trail to open the route planner. You can Draw a route directly on the interactive map or choose Upload file to import a GPX track. wanderer computes the distance, duration and elevation profile as you go.
Use Lists to organise trails into collections, such as a set of favourite routes. You can keep each list private or share it.
A note on the PocketBase URL and using your own domain
wanderer's web frontend talks to PocketBase from both the browser and its server-side rendering, using the same address. To keep both paths correct on a plain IP deployment, the image sets the browser-facing PocketBase URL to http://<vm-ip>.nip.io/pb. Here nip.io is a public wildcard-DNS service that resolves <vm-ip>.nip.io back to <vm-ip>.
Your VM still serves everything on port 80. Only DNS resolution uses nip.io.
For production, put wanderer behind your own domain and TLS. Point a hostname at the VM. In /opt/wanderer/.env, set ORIGIN (the app) to https://wanderer.example.com and PUBLIC_POCKETBASE_URL to https://pb.example.com/pb, a distinct host from ORIGIN. Then run sudo systemctl restart wanderer.
Managing the service
View recent container logs, or restart the whole stack:
# view recent logs for a container docker compose -f /opt/wanderer/docker-compose.yml logs --tail 50 web
# restart the whole stack
sudo systemctl restart wandererSupport
SecureAnyCloud provides 24/7 support with a 24-hour response SLA. For help with this image, contact sales@secureanycloud.com.
Deploy on Azure
Launch wanderer 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
wanderer is a free, open source, self-hosted database for outdoor routes. You upload GPX tracks or draw trails directly on an interactive map, attach waypoints, photos and notes, and keep your hiking, cycling and running routes together with distance, elevation and other statistics in one place. Trails group into lists, can be private or shared, and are searchable instantly across everything you have recorded.
This SecureAnyCloud image runs wanderer the officially supported way. The SvelteKit web frontend, a PocketBase backend and a Meilisearch full-text search engine all run as upstream release containers, pinned by image digest, on a private internal network. PocketBase is a Go binary that embeds an SQLite database and provides your account and route data plus an admin console.
A single in-network reverse proxy on port 80 is the only public entry point: / serves the web app and /pb/ serves the PocketBase API. Meilisearch is never published to any host port. PocketBase is published only to the loopback interface, for an administrator's SSH tunnel.
The upstream project ships with open registration enabled and its search and backend keys set to public example values. This image ships with no known secret. On first boot of every instance, before the app is reachable, it generates a unique Meilisearch master key, a unique PocketBase encryption key, a per-instance app account and a separate backend superuser, each with a random password. Open sign-up is switched off by default.
All application data lives on a dedicated data volume, separate from the OS disk and independently resizable. This covers the database, uploaded GPX tracks and photos, and the search index.
wanderer, PocketBase and Meilisearch are trademarks of their respective owners. This image is produced by SecureAnyCloud and is not affiliated with, endorsed by, or sponsored by any of them. It ships the free and open source self-hosted software, unmodified.
What you get:
- wanderer v0.20.0 (the AGPL-3.0 licensed SvelteKit frontend and PocketBase backend), pinned by image digest
- Meilisearch v1.36.0 (the MIT-licensed search engine) in production mode, so every request requires a key
- PocketBase's embedded SQLite database, created empty on first boot and stored on the dedicated data volume
- Docker Engine with the web frontend, PocketBase and Meilisearch on a private network, fronted by an in-network nginx proxy. The proxy is the only container published to the host, on port
80(/= web app,/pb/= PocketBase API) docker.service,wanderer-firstboot.service,wanderer.serviceandwanderer-postboot.serviceas systemd units, enabled and active on boot- A unique Meilisearch master key, PocketBase encryption key, per-instance app account and separate backend superuser, each with a random password generated per instance on first boot and never baked into the image
- Open registration disabled by default, and the PocketBase admin console kept off the public port
- A dedicated data volume at
/var/lib/wandererholding the database, GPX uploads, photos and the search index - No default login, no shipped secret and an empty database on first boot
- Ubuntu 24.04 LTS base with the latest security patches applied at build time
- 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. A larger route library or many concurrent users benefit from more memory.
Configure the security group to allow inbound 22/tcp from your management network for SSH and 80/tcp for the web app from the networks that use it.
Step 1 - Launch the AMI
Subscribe to the listing in AWS Marketplace, then launch an instance from the AMI. Use the Marketplace Launch action or the CLI.
Attach your key pair and a security group that allows inbound 22/tcp and 80/tcp. Leave the dedicated data volume in the launch template in place.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <your-key-pair> \
--security-group-ids <security-group-id> \
--subnet-id <subnet-id> \
--associate-public-ip-address \
--metadata-options "HttpTokens=required,HttpEndpoint=enabled" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=wanderer}]'The instance uses IMDSv2. On first boot, the image reads the instance's public IP from instance metadata to build the app's public URL.
Step 2 - Connect to your instance
Connect over SSH as the default login user for your OS variant. For Ubuntu 24.04 LTS, the login user is ubuntu and the SSH command is ssh ubuntu@<instance-public-ip>.
Step 3 - Confirm the services are running
On the first boot of each instance, before the app is reachable, wanderer generates its own per-instance secrets and accounts and brings the stack up. Wait a minute, then confirm that the four systemd units are active:
sudo systemctl is-active docker wanderer-firstboot wanderer wanderer-postbootactive active active activeStep 4 - Review the security model
SecureAnyCloud hardens every instance before the port is ever public. The web app, PocketBase and Meilisearch run as containers on a private Docker network. Only the nginx proxy is published, on port 80, routing / to the web app and /pb/ to the PocketBase API.
The PocketBase admin console (/pb/_/) is blocked at the proxy and returns 403. Meilisearch is never published to any host port. Open user registration is disabled by default (PUBLIC_DISABLE_SIGNUP=true).
Verify the proxy behaviour:
# the app is public on :80; the PocketBase API is reachable for the browser via /pb/ curl -s -o /dev/null -w "app / -> %{http_code}\n" http://127.0.0.1/ curl -s -o /dev/null -w "pb /pb/api/health -> %{http_code}\n" http://127.0.0.1/pb/api/health
# the admin console is NOT public curl -s -o /dev/null -w "admin /pb/_/ -> %{http_code}\n" http://127.0.0.1/pb/_/app / -> 200 pb /pb/api/health -> 200 admin /pb/_/ -> 403Only port 80 (the proxy) and the loopback-only 127.0.0.1:8091 (the PocketBase admin tunnel) listen. Meilisearch (7700) and the web frontend (3000) are internal to the Docker network:
sudo ss -tlnp | grep -E ':80 |8091|7700|3000'LISTEN 0.0.0.0:80 LISTEN 127.0.0.1:8091Step 5 - Read your per-instance credentials
Nothing is baked into the image. Read the credentials file, which is 0600 root:root:
sudo cat /root/wanderer-credentials.txtThe file contains two accounts, both with per-instance random passwords:
WANDERER_USER_EMAIL/WANDERER_USER_PASSWORD: the app login you use in the web UI.PB_SUPERUSER_EMAIL/PB_SUPERUSER_PASSWORD: the PocketBase backend superuser for administering collections. Its admin console is not exposed on the public port.
To reach the PocketBase admin console, tunnel to the loopback container port over SSH from your workstation. Then sign in with the superuser credentials:
ssh -L 8091:127.0.0.1:8091 ubuntu@<instance-public-ip>
# then open http://localhost:8091/_/ in your browserStep 6 - Verify the end-to-end round trip
The image ships a verification script. It authenticates as the per-instance app account, creates a trail list through the public front door and reads it back. It also confirms that an unauthenticated create is rejected. Run it with:
sudo /usr/local/sbin/wanderer-roundtrip.shOK round-trip: web=http://<instance-public-ip>/ pb=http://<instance-public-ip>.nip.io/pb user=user@wanderer.local created+readback list ag3dgmq07uwdsdw; admin UI blocked 403; unauth create 400Step 7 - Sign in to the web app
Open http://<instance-public-ip>/ in your browser. Sign in with the WANDERER_USER_EMAIL and WANDERER_USER_PASSWORD from the credentials file.
The trail library offers search and filters by category, tags, author, visibility and difficulty. Each trail appears as a card with a route thumbnail, location and statistics.
Step 8 - Upload a GPX trail
Choose New Trail to open the route planner. You can Draw a route directly on the interactive map or choose Upload file to import a GPX track.
As you go, wanderer computes the distance, estimated duration and elevation profile, and reverse-geocodes the location. Open a saved trail to see it on the map with its elevation profile and statistics.
Step 9 - Browse trails on the map
Open the Map view to browse every stored trail as clustered markers on one interactive map, with a filterable sidebar of trail cards.
Use Lists to organise trails into collections. You can keep each list private or shared.
Data volume
All application data lives on a dedicated EBS data volume mounted at /var/lib/wanderer. The volume holds the Docker data root for the stack: the PocketBase SQLite database, the uploaded GPX tracks and trail photos, and the Meilisearch search index.
The volume is separate from the OS disk, so you can resize it independently. As your route library grows, back it up with EBS snapshots or AWS Backup.
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/wandererA note on the PocketBase URL and using your own domain
wanderer's web frontend talks to PocketBase from both the browser and its server-side rendering, using the same address. To keep both paths correct on a plain IP deployment, the image sets the browser-facing PocketBase URL to http://<instance-public-ip>.nip.io/pb. Here nip.io is a public wildcard-DNS service that resolves <instance-public-ip>.nip.io back to <instance-public-ip>.
Your instance still serves everything on port 80. Only DNS resolution uses nip.io.
For production, put wanderer behind your own domain and TLS, for example an Application Load Balancer that terminates your certificate. Point a hostname at the instance. In /opt/wanderer/.env, set ORIGIN (the app) to https://wanderer.example.com and PUBLIC_POCKETBASE_URL to https://pb.example.com/pb, a distinct host from ORIGIN. Then run sudo systemctl restart wanderer.
Optional: self-hosted turn-by-turn routing
Map display, GPX upload, trail browsing and search work out of the box against the public OpenStreetMap map, geocoding and routing services. wanderer can also use a self-hosted Valhalla routing engine for turn-by-turn route drawing.
Valhalla needs large OpenStreetMap tile extracts, so it is not bundled in the appliance. To add it, run a Valhalla instance with the tile data for your region. Point VALHALLA_URL in /opt/wanderer/.env at it, then run sudo systemctl restart wanderer.
Managing the service
View recent container logs, or restart the whole stack:
# view recent logs for a container
sudo docker compose -f /opt/wanderer/docker-compose.yml logs --tail 50 web
# restart the whole stack
sudo systemctl restart wandererSupport
SecureAnyCloud provides 24/7 support with a 24-hour response SLA. For help with this image, contact sales@secureanycloud.com.
Deploy on AWS
Launch wanderer with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com