uMap
Overview
uMap is an open-source web application for creating and sharing maps on OpenStreetMap layers. You draw markers, lines and polygons in the browser, import your own geodata from GeoJSON, GPX, KML or CSV, and share the finished map with a link or embed it in any web page. By default anyone can create a map without an account and edit it privately through a secret link, which is how the public uMap service works.
uMap is a GeoDjango application, so the SecureAnyCloud image supplies the production stack around it. uMap 3.7.3 is installed at a pinned upstream release into a dedicated Python virtual environment, served by gunicorn behind nginx, and backed by PostgreSQL 16 with the PostGIS spatial extension for map metadata and Redis for caching, all on the same instance. gunicorn is bound to loopback 127.0.0.1:8019 and is never exposed directly. nginx on port 80 is the only way in, plus an unauthenticated /healthz endpoint for load balancer probes. Map data layers are stored as GeoJSON files on disk and served by nginx.
The image is secure by default. No credential ships in the image, and nothing listens on the public port until first boot completes, so a freshly launched VM is never reachable with a known password. On the first boot of every VM, a fresh Django secret key, PostgreSQL password and Redis password are created, along with a unique randomly generated administrator password. They are written to a root-only file, and only then is the public site brought up. The image is backed by 24/7 SecureAnyCloud support.
What you get:
- uMap 3.7.3 installed in a dedicated Python virtual environment and running as the
umapgunicorn systemd service - Django 5.2 LTS on Python 3.12, within uMap's supported range
- The uMap web application on
:80, fronted by nginx with gunicorn bound to loopback only - A PostgreSQL 16 database with the PostGIS extension on loopback, holding map metadata, with a per-VM database password generated on first boot
- Redis on loopback as the Django cache, with a per-VM password generated on first boot
- Anonymous map creation enabled by default, which is the public-by-design uMap posture, with the Django admin reserved for a single instance administrator
- A ready-made example map, Welcome to uMap by SecureAnyCloud, with markers, so the home page shows a real map as soon as the VM boots
- No default account and no shipped secret: the administrator user and the Django secret key are both created on first boot with unique random values
- Host settings configured so the app works on the public IP address or a custom domain, with no baked-in hostname
- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes postgresql.service,redis-server.service,umap.service(gunicorn) andnginx.serviceas systemd units- 24/7 SecureAnyCloud support
Key facts
Item Value
Platform Ubuntu 24.04 LTS (Gen2)
Default SSH user azureuser
Application root /srv/umap
Python virtual environment /srv/umap/venv
Settings file /etc/umap/umap.conf
Per-VM environment file /srv/umap/umap.env
Map data layers (GeoJSON) /srv/umap/var/data
Service account umap (non-login system user)
Per-VM credentials /root/umap-credentials.txt
Recommended size Standard_B2s (2 vCPU / 4 GiB RAM)
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point.
Configure the NSG inbound rules to allow 22/tcp from your management network, 80/tcp for uMap, and 443/tcp if you add TLS. The image serves plain HTTP on port 80. For production, terminate TLS with your own domain and restrict access to trusted IP ranges (see Security Recommendations).
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure portal, choose Create a resource, search the Marketplace for uMap 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). Then select Review + create, followed by Create.
Step 2 - Deploy from the Azure CLI
Accept the Marketplace terms, then create the VM:
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:umap:default:latest
az vm create \
--resource-group <your-rg> \
--name umap \
--image sac1647283583153:umap:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku StandardOpen port 80 to your network to reach uMap:
az vm open-port --resource-group <your-rg> --name umap --port 80Step 3 - Connect to your VM
Connect over SSH as the default user, azureuser:
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
First boot generates the per-VM secrets, creates the administrator account and then brings the public site up. It normally completes within a minute of the VM reaching Running. Check all four services:
systemctl is-active postgresql redis-server umap nginxAll four report active.
Confirm the health endpoint answers:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/healthzIt returns 200.
Check that first boot completed. systemctl show reports the state and the outcome separately. A first boot that ran and succeeded shows ActiveState=active (it is a oneshot unit with RemainAfterExit=yes) together with Result=success.
systemctl show -p ActiveState -p Result -p ExecMainStatus umap-firstboot.serviceThe application server, the database and the cache are deliberately reachable only on the loopback interface. nginx on port 80 is the single public entry point. Confirm the listeners:
sudo ss -tlnp | grep -E ':(80|8019|5432|6379)\b'Step 5 - Retrieve your per-VM administrator password
Every VM generates its own administrator password on first boot and writes it to a root-only file. Nothing is shared between deployments, and no password is baked into the image. Read the file:
sudo cat /root/umap-credentials.txtThe file lists UMAP_URL, UMAP_ADMIN_USER (which is umapadmin) and UMAP_ADMIN_PASSWORD, along with the map creator and Django admin addresses. Store the password in your password manager and change it after your first sign in.
The credentials file and the environment file that holds the Django secret key are both restricted. The image also ships a checker that confirms no secret has leaked into the system journal, the authentication log, /var/backups, shell history or any other log:
sudo ls -l /root/umap-credentials.txt /srv/umap/umap.env
sudo bash /usr/local/sbin/umap-secret-leak-check.shThe checker prints LEAKCHECK_OK.
Step 6 - Open uMap and the example map
Browse to http://<vm-public-ip>/. uMap opens on its home page, which has a search box, a summary of what uMap does, a Create a map button, and a feed of maps on the instance.
The image ships one example map, Welcome to uMap by SecureAnyCloud, so a real map is visible immediately. Open it from the feed. It shows markers for three cities and a route drawn between them, on OpenStreetMap tiles, with the Points of interest data layer listed in the panel.
Step 7 - Create a map with markers
Anonymous map creation is enabled by default, so you do not need an account to make a map. Choose Create a map on the home page. The editor opens with a whole-world view, the drawing tools on the right (marker, line, polygon), and the map layers, import, settings and share controls.
Select the marker tool, click a point on the map to drop a marker, give it a name and a description, then choose Save. uMap creates the map, stores your marker as a GeoJSON data layer, and gives you a shareable URL for the map plus a secret edit link for later changes.
To list the map and make it viewable by others, change the visibility in the map settings from Draft (private) to public.
Step 8 - Sign in to the Django administration area
The Django admin is reserved for the single instance administrator. Use it to moderate maps, manage licenses and tile layers, and remove content. Browse to http://<vm-public-ip>/admin/ and sign in as umapadmin with the password from Step 5.
The uMap section lists Maps, Data layers, Licences, Pictograms, Teams and Tile layers. Use it to review or delete maps created on your instance, add custom tile layers, or manage the licenses offered to map authors.
Self-service account sign-up and third-party sign-in are switched off by default. This administrator is the only account on the instance until you configure otherwise.
Step 9 - Verify the whole workflow yourself
The image ships the same end-to-end check that it is built and tested with. The check does the following:
- Confirms PostGIS is present.
- Proves a Redis cache round trip.
- Creates a map with a marker through uMap's own models.
- Reopens the map by its public URL and reads the data layer GeoJSON served through nginx to confirm the marker is there.
- Proves that an unauthenticated write to that data layer is rejected.
- Removes the map it created, so nothing is left behind.
Run it:
sudo bash /usr/local/sbin/umap-verify-workflow.shIt prints a single line, WORKFLOW_OK map=<id> marker_served=1 postgis=<version> redis=ok. Any failure prints BROKEN-<reason> instead and exits with a non-zero status.
You can check the installed versions at any time:
/srv/umap/venv/bin/python -c "import django, importlib.metadata as m; print('Django', django.get_version(), '| uMap', m.version('umap-project'))"Step 10 - List the maps on your instance
List the maps from the command line, with the instance environment already loaded:
sudo /usr/local/sbin/umap-manage shell -c "from umap.models import Map; print([(m.id, m.slug, m.name) for m in Map.objects.all()])"The shipped example map, welcome-to-umap, appears in the list.
Step 11 - Optional: turn on account sign up or OAuth sign in
By default the only way to sign in is the Django admin as the instance administrator, although anonymous visitors can still create maps. To let visitors register their own uMap accounts, or sign in with an external provider such as OpenStreetMap, edit the settings.
To allow local account login, set ENABLE_ACCOUNT_LOGIN in the environment file:
sudo nano /srv/umap/umap.envAdd the following line, then restart uMap:
ENABLE_ACCOUNT_LOGIN=1sudo systemctl restart umapTo use OpenStreetMap or another OAuth provider, add the provider's backend and keys to /etc/umap/umap.conf following the uMap configuration documentation, then restart uMap. Leave both switched off if you need only anonymous map creation and a single administrator.
Step 12 - Add a domain and TLS
For production, put your own certificate in front of uMap. Point a DNS record at the VM's public IP, install a certificate with your preferred tool, and configure nginx to serve it. The vhost lives at /etc/nginx/sites-available/sac-umap.
Once you serve HTTPS, edit the environment file to set uMap's public address, restrict the hostnames it answers on, and switch the session and CSRF cookies to secure-only:
UMAP_SITE_URL=https://umap.example.com UMAP_ALLOWED_HOSTS=umap.example.com UMAP_CSRF_TRUSTED_ORIGINS=https://umap.example.com UMAP_SECURE_COOKIES=trueThen restart the service:
sudo systemctl restart umapLeave UMAP_SECURE_COOKIES at false while you are still on plain HTTP. The browser never returns a secure-only cookie over HTTP, so turning it on too early stops sign-in and map creation from working.
Server Components
Component Version Purpose
uMap 3.7.3 The map creator: maps, data layers, imports, sharing and embedding
Django 5.2 LTS The GeoDjango web framework hosting uMap
Python 3.12 Runtime, in a dedicated virtual environment
gunicorn 26.x WSGI application server, bound to 127.0.0.1:8019
nginx 1.24 Reverse proxy on port 80, serves static files and map data layers
PostgreSQL 16 Map metadata database, bound to 127.0.0.1:5432
PostGIS 3.4 Spatial extension providing the geometry types uMap needs
Redis 7.0 Django cache, bound to 127.0.0.1:6379, password protected
Filesystem Layout
Path Size Purpose
/ 29 GB Root filesystem
/boot 881 MB Operating system kernel files
/boot/efi 105 MB UEFI boot partition (Gen2 Hyper-V)
/mnt 8 GB Azure temporary resource disk (not persistent)
Key directories
Path Purpose
/srv/umap Application root, owned by the umap system user
/srv/umap/venv Python virtual environment holding uMap and its dependencies
/srv/umap/var/static Collected static files, served by nginx
/srv/umap/var/data Map data layers stored as GeoJSON files
/etc/umap/umap.conf The SecureAnyCloud appliance settings
/srv/umap/umap.env Per-VM environment file: secret key, database and Redis passwords, host settings
/var/lib/postgresql/16/main PostgreSQL data directory
/etc/nginx/sites-available/sac-umap The nginx vhost
/root/umap-credentials.txt Per-VM administrator credentials, 0600 root:root
Managing the services
Check the status of the uMap service:
systemctl status umap --no-pager --lines=0Restart any service as needed:
sudo systemctl restart umap
sudo systemctl restart nginx
sudo systemctl restart postgresql
sudo systemctl restart redis-serverFollow the application log:
sudo journalctl -u umap -fRun any uMap or Django management command with the instance environment already loaded:
sudo /usr/local/sbin/umap-manage showmigrations umap | tail -5Scripts and Log Files
Path Purpose
/usr/local/sbin/umap-firstboot.sh First boot: generates the per-VM secrets, creates the administrator account, enables the public site
/usr/local/sbin/umap-manage Runs a uMap or Django management command with the instance environment
/usr/local/sbin/umap-verify-workflow.sh End-to-end workflow check (Step 9)
/usr/local/sbin/umap-secret-leak-check.sh Confirms no per-VM secret reached the journal, auth log, backups or history
/var/lib/sac/data/umap-firstboot.done First boot sentinel; its presence stops first boot re-running
journalctl -u umap Application and gunicorn access log
journalctl -u umap-firstboot First boot log
/var/log/nginx/access.log, /var/log/nginx/error.log nginx logs
On Startup
umap-firstboot.service runs once, on the first boot of each VM, gated on the sentinel above. It does the following in order:
- Resolves the VM's public address.
- Rotates the PostgreSQL password and the Redis password.
- Generates a unique Django secret key.
- Applies any pending database migrations.
- Creates the
umapadminadministrator account with a random password. - Starts gunicorn on loopback.
- Enables the public nginx vhost.
It finishes by checking that the whole map workflow works and that no secret leaked into any log, and then writes the sentinel.
Until that unit completes, nothing listens on port 80. This is deliberate, so a newly launched VM is never reachable with a credential that anybody else could know. On later boots the unit is skipped and the normal service units start uMap.
Backups
Back up two things: the PostgreSQL database (map metadata, permissions, users) and the data directory (the GeoJSON files that hold your map features). Do not copy the environment file into a backup location, because it holds the Django secret key and the database password.
sudo install -d -o root -g root -m 0700 /var/backups/umap
sudo -i bash -c 'set -a; . /srv/umap/umap.env; set +a; umask 077; PGPASSWORD="$DB_PASSWORD" pg_dump -h 127.0.0.1 -U "$DB_USER" -d "$DB_NAME" | gzip > /var/backups/umap/umap-$(date -u +%Y%m%d).sql.gz'
sudo tar czf /var/backups/umap/umap-data-$(date -u +%Y%m%d).tar.gz -C /srv/umap/var data
sudo ls -l /var/backups/umap/Copy both backup files off the VM to your own storage.
Troubleshooting
uMap does not answer on port 80. First boot may still be running. Check its state and outcome:
systemctl show -p ActiveState -p Result -p ExecMainStatus umap-firstboot.serviceActiveState=active with Result=success means first boot finished. Result=exit-code or a non-zero ExecMainStatus means it failed. Read the log:
sudo journalctl -u umap-firstboot --no-pager | tail -40The public vhost is enabled by first boot, so if that unit failed, port 80 stays closed by design.
The site loads, but sign-in or map creation fails in the browser. Check that UMAP_SECURE_COOKIES is not set to true while you are still serving plain HTTP. The browser never sends a secure-only cookie back over HTTP, so the session and the CSRF token are silently dropped.
A page reports a disallowed host. Add your hostname to UMAP_ALLOWED_HOSTS and your scheme plus hostname to UMAP_CSRF_TRUSTED_ORIGINS in /srv/umap/umap.env, then restart umap.
The administrator password is not accepted. Re-read it from /root/umap-credentials.txt. If the account has been lost entirely, create a replacement:
sudo DJANGO_SUPERUSER_PASSWORD='<new-password>' /usr/local/sbin/umap-manage createsuperuser --noinput --username newadmin --email you@example.comTo check for application errors, read the end of the uMap log:
sudo journalctl -u umap --no-pager | tail -60Security Recommendations
- Change the
umapadminpassword after your first sign in. - Anonymous map creation is on by default. If your instance should be private, either restrict
80/tcpand443/tcpto trusted networks in the NSG, or turn anonymous creation off by settingUMAP_ALLOW_ANONYMOUS=0in/etc/umap/umap.confand restarting uMap. - Restrict
22/tcpto your management network in the NSG. - Terminate TLS with your own certificate and domain, then set
UMAP_SITE_URL,UMAP_ALLOWED_HOSTS,UMAP_CSRF_TRUSTED_ORIGINSandUMAP_SECURE_COOKIES=trueas described in Step 12. - Keep
/root/umap-credentials.txtand/srv/umap/umap.envas they are shipped. The environment file holds the Django secret key, and anyone who reads it can forge sessions. - Unattended security upgrades are enabled on the image. Leave them on, and reboot when a kernel update requires it.
- Take regular database and data directory backups as described above, and store them off the VM.
Support
SecureAnyCloud provides 24/7 support for this image. Contact sales@secureanycloud.com with your Azure subscription ID and the VM name.
uMap is open source software distributed under the GNU Affero General Public License version 3. uMap is a project of the OpenStreetMap community, and OpenStreetMap is a trademark of the OpenStreetMap Foundation. SecureAnyCloud is not affiliated with, endorsed by or sponsored by either. The example map shown in this guide is included for illustration.
Deploy on Azure
Launch uMap 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