So here are my experiences in installing Panoramax instance OSM-HR. I’ve made this from notes taken at a time, so hopefully I did not miss too much. Let me know if I did.
There are several ways to install, and I’ve decided to go with docker compose, and with regular OSM Oauth2 login.
We bumped into few issues during the deployment, but we reported them at appropriate repos, and they were fixed so nobody should be bothered by them anymore. Please do the same if you bump into some of your own!
So mostly I followed official instructions here: https://docs.panoramax.fr/backend/install/tutorials/running_docker_osm_auth/
with some preparation first as outlined in: https://forum.geocommuns.fr/t/deploying-a-panoramax-instance-the-pre-flight-check-list/1892
and info about storage needs: https://forum.geocommuns.fr/t/storage-needs-for-a-panoramax-instance/3205
Hardware
First actual hard step was getting the appropriate hardware and place to host it; see that pre-flight check list for other things like checking the law etc.
http://openit.hr/ kindly donated the hardware, and https://carnet.hr/ the place and Internet to host it. Much thanks to them!
We got quite a beast: 4U Super-Micro cse-847 server with 2 * Xeon E5-2680v2 (40 CPU threads @ 2.80GHz), 256 GB DDR3 RAM, 2x1TB SATA SSD, and 34x3TB SAS HDD (54 TB of usable HDD space after RAID6 partitioning), Nvidia Tesla P4
You can get with (much) lower specs, depending on your needs. But we have a good-hearted sponsor so yay!
Creating Oauth2 app
So firstly, I went to osm.org/, logged in, clicked on menu / “My account” / “Oauth 2 Applications” / “Register new application” and created Oauth2 application as described on: https://docs.panoramax.fr/backend/install/tutorials/running_docker_osm_auth/#creating-our-osm-oauth2-client
“Name” was set to Panoramax HR and “Redirect URIs” to https://panoramax.osm-hr.org/api/auth/redirect
Make sure to write down “Client ID” and “Client Secret”, as you’ll need them later and this is only time you’ll be able to see them.
Preparing the host OS
We use Debian. Originally at a time we tried going with Debian Bookworm GNU/Linux, but that had complained about Docker Compose configs, so we upgraded to Trixie. As it is Debian Stable at this moment, that is what I’d recommend anyway nowadays.
We also decided to use multiple HW RAID6 pools, LVM and EXT4, due to familiarity and stability and experience in recovering them (hopefully this won’t jinx it). Some people go with XFS instead of EXT4, and others swear by ZFS and replace both LVM and EXT4 with it – but I’ve never got too familiar with it (due to the way back in bad old days there were licensing issues with it. Never checked if that was resolved. Ha). And we decided on Docker Compose in order to hopefully have easy upgrades and keep host OS to pure Debian “main” packages.
So, we installed prerequisite packages, created a logical volume and formatted it.
apt install docker.io docker-compose docker-cli curl nginx certbot python3-certbot-nginx
lvcreate --name panoramax-pics --size 40T shrikehdd
mkfs.ext4 -T largefile /dev/shrikehdd/panoramax-pics
mkdir /osm/panoramax/storage
echo "/dev/shrikehdd/panoramax-pics /osm/panoramax/storage ext4 defaults 0 3" >> /etc/fstab
mount /osm/panoramax/storage
mkdir /osm/panoramax/storage/pics
chmod 1777 /osm/panoramax/storage/pics
Note that our Debian root directory (and thus, where docker SQL database will live) is on SSD.
Getting and configuring Panoramax
We fetch it from git and copied template config file:
git clone https://gitlab.com/panoramax/server/api.git panoramax-api
# git checkout develop # only if you like to live on the edge -- we had to at a time, as we were finding some bugs on the way
cd panoramax-api/docker/full-osm-auth/
cp -ai env.example .env
and then we edited that .env to configure for our instance:
INSTANCE_NAME=OSM-HR
FLASK_SESSION_COOKIE_DOMAIN=panoramax.osm-hr.org
PICTURES_DIR=/osm/panoramax/storage/pics/
INFRA_NB_PROXIES=2
- we also set the long (different) passwords for
FLASK_SECRET_KEYandPG_PASSWORD. You can use output ofpython3 -c 'import secrets; print(secrets.token_hex())to generate appropriately long passwords. - and we set
OAUTH_CLIENT_IDandOAUTH_CLIENT_SECRETto those values we’ve written down when when we created Oauth2 app in previous steps.
Also, we needed to edit docker-compose.yml from that panoramax-api/docker/full-osm-auth/ directory and update API_SUMMARY according to docs at https://panoramax.ign.fr/api/configuration
We did this:
API_SUMMARY: >-
{
"color": "#ff0000",
"description": {"en": "OpenStreetMap Croatia", "hr": "OpenStreetMap Hrvatska"},
"logo": "https://wiki.openstreetmap.org/w/images/6/6d/Logo_Croatia.svg",
"email": "panoramax@osm-hr.org",
"name": {"en": "${INSTANCE_NAME:-A Panoramax instance}", "hr": "${INSTANCE_NAME:-Panoramax instanca}"},
"geo_coverage": {"en": "Croatia and ex-YU region", "hr": "Hrvatska i regija"}
}
Starting up Panoramax
We went to panoramax-api/docker/full-osm-auth/ directory and started Docker Compose with docker compose --project-name panoramax-hr up --pull=always -d
That should pull up everything newest and start Panoramax in background.
You should verify here if it works by calling curl --fail http://localhost:8080/api - it should return some JSON.
Publishing it to the world
We’ve picked nginx. Since panoramax.osm-hr.org was setup in DNS to point to our server, we created /etc/nginx/sites-available/panoramax with following content:
server {
listen 80;
listen [::]:80;
server_name panoramax.osm-hr.org;
# Limit the files that can be sent to 100M
client_max_body_size 100M;
# buffer size when receiving big files. 6M should be enough for most pictures, but feel free to tune this value depending of your needs.
client_body_buffer_size 6M;
client_body_timeout 120s;
send_timeout 60s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
And then enabled it and started it:
ln -s /etc/nginx/sites-available/panoramax /etc/nginx/sites-enabled/
service nginx reload
(note we don’t use systemd as I deem it a horrible idea; but service(8) on Debian should run regardless if you’re using SysVinit or Systemd)
Then we fetch free Let’s Encrypt TLS certificates by running certbot --nginx and choosing out panoramax.osm-hr.org server from the list.
That makes people able to open https://panoramax.osm-hr.org/ and login and look and upload there!
Geo-limiting the uploads
While the hardware we got was very powerful, we knew it wasn’t nowhere near infinite, so we couldn’t host the whole world. And cameras get better (and more Mpx) with time, and disk usage only rises.
Still, it felt a shame to limit it only to Croatia (where the server and sponsors are from), so we decided to allow all countries from ex-Yugoslavia to use it. (not only we have great mapper friends there, but laws and language are similar, so there is also that).
To restrict what areas are allowed, we first had to get .geojson of the area (see https://docs.panoramax.fr/backend/install/deep_dive/excluded_areas for the info) and save it as exyu.geojson
Then we used docker compose -p panoramax-hr exec api /home/geovisio/.local/bin/panoramax_backend default-account-tokens get to get a Bearer token (looong string of letters and numbers and few dots)
And then we uploaded that config:
curl -X PUT "https://panoramax.osm-hr.org/api/configuration/excluded_areas?invert=true"\
-H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.the.rest.ofthe.bearer.token.xxxxxxxx" \
-H "Content-Type: application/geo+json" --data-binary "@exyu.geojson"
(of course you replace bearer token with that string you got earlier)
Testing
Then there was testing. Obviously, easiest was to use our new web at https://panoramax.osm-hr.org/ to try to upload pictures from both allowed and disallowed regions, to see if geo-limiting was working.
Then we tried some sequences uploading from CLI (sudo apt install pipx; pipx install panormax_cli), using the mobile apps (Vespucci custom server) etc.
We first had test instance on different hardware that we nuked later and setup production, but that is not needed. (If you do something similar, make sure to nuke your panoramax-cli config cache, or it will behave strangely).
Announcing to the world
Well, when you’re happy that everything is working great, you want to make your instance usable by others too!
-
Firstly you need to make it a part of federation so it will be visible in meta-catalog on https://api.panoramax.xyz/ You just need to open a simple issue like this: https://gitlab.com/panoramax/server/meta-catalog/-/work_items/56
-
While web and panoramax_cli will work automatically for uploads by just specifying the new instance, and Vespucci will pick instance from meta-catalog above automatically; we also quite like Baba mobile app for uploads - but they have a hard-coded list of servers. Opening issue might’ve been enough, but we’ve created a full PR to make it easier and quicker for Baba developer: https://gitlab.com/ravenfeld/baba/-/merge_requests/390
-
and of course publicize - on OSM blog, on Fediverse, on SotM-HR 2026 (see https://c.osm.org/t/konferencija-state-of-the-map-croatia-2026/143248/2 ), etc.
Appendix A: managing the Docker Compose
I’m not much of a docker guy, but here are some commands which seem to work for me and might come handy to you:
# startup in the future with fetching new versions if needed:
docker compose -p panoramax-hr up --pull=always -d
# shutdown with:
docker compose -p panoramax-hr down
# check logs:
docker compose -p panoramax-hr logs -f --tail 1000
# process list:
docker compose -p panoramax-hr ps
# DESTROY everything docker-related -- in case you mucked it up completely and want to start from scratch:
docker compose -p panoramax-hr down --volumes --rmi all --remove-orphans
docker system prune -a --volumes
# database access
docker compose -p panoramax-hr exec -it db psql postgres://gvs:thatlongPostgresqlPassword@db/geovisio
TODO
- try to setup our own blurring server (it was in initial plan, but there were issues with that blurring docker container, and we had deadlines to mean - SotM-HR 2026; where I presented Panoramax)
- backups (Database. And pictures. And hardware to store ‘em, uhhhh)
- move Croatian (and other ex-YU) pictures off the OSM-FR server to our OSM-HR, to help reduce their overload (see https://c.osm.org/t/osm-fr-panoramax-server-only-for-testing-if-outside-of-france/143428/2) once stable UUIDs are implemented
- encourage more users to setup their Panoramax instances – this can only work for whole world if there are a lot of us!
- admin user over the web (not just CLI Bearer - see https://docs.panoramax.fr/backend/install/cli/#set-the-role-of-an-account )
- figuring out how to check out blur / unblur requests and other moderation / flow checking
- look into few warnings / errors in the logs (and file some more issues)
Discussion