How we run OrbGIS, from servers to backups
Where your data lives, what happens to it if something breaks, who can reach it, and how we find out when things go wrong. The infrastructure behind OrbGIS.
We say "Swedish hosting, operated by us" a lot. This article is what that means for your data in practice: where it is stored, how it is backed up, who can reach it, and how we notice when something breaks. Everything described below exists, is written down in our runbooks, and in most cases has been exercised in a real restore.
Where your data lives#
Production runs at a Swedish cloud provider, alongside a development environment that every change passes through before it reaches you. Backups go to a second data center in a different location, and a third copy is pulled to hardware we own ourselves, outside the cloud provider entirely. Our systems are spread across several physically separate locations within the EU, so no two copies of your data depend on the same building, the same power feed or the same network.
| Location | Where | What it holds |
|---|---|---|
| Production | EU/Sweden | The platform, your database, your files, your map tiles |
| Backup storage | A second data center, separate location | Every backup, in a different data center from the thing it protects |
| Our own hardware | A third location, outside the cloud provider | A third copy of every backup, plus the monitoring that watches the servers |
Every provider in that chain is European, and none is a US company. Why that matters for jurisdiction is covered in our article on cloud and geodata security for municipalities. This article is about what happens inside that boundary.
What it runs on#
The whole platform is built from proven open source software, and every server runs the complete stack in a set of containers:
- PostgreSQL with PostGIS is the single source of truth. Every layer you upload becomes a spatial table, and every permission rule lives in the database itself.
- Martin serves your feature layers as vector tiles rendered straight from PostGIS, per request and with your permissions applied. There is no separate copy of your data to keep in sync.
- TiTiler serves uploaded raster basemaps, and GDAL does the heavy lifting when you import files, whatever format they arrive in.
- Supabase's open source building blocks provide authentication, the REST API and file storage on top of the same database.
- Caddy sits in front as the reverse proxy and handles TLS, and OpenLayers draws the map in your browser.
Because it is all open source and all in one place, there is nothing proprietary between you and your data: it is a PostGIS database, and it can be exported in open formats whenever you want.
If something breaks: the backups#
A backup has to answer two different questions. "Give me the database as it was last night" is one. "Give me the database as it was at 14:32 today, two minutes before the bad import" is the other. We keep both kinds, and each exists in two places besides the server it protects.
Every night, a full copy of the database and a mirror of your uploaded files are written to versioned storage in the second data center. Continuously, the database's change log is shipped to the same place every two minutes, with a full base backup once a night, so the database can be rewound to any moment inside the retention window. Every hour, hardware we own pulls a copy of all of it. That copy can only be added to, never deleted from, a daily snapshot preserves history against overwrites, and the disk is encrypted with a key that exists only offline.
In numbers:
| Measure | Value |
|---|---|
| Most data you could lose in the worst case | about 7 minutes |
| Data lost while nothing is changing | none |
| Rewind window in backup storage | 14 days, to any point in time |
| Guaranteed history under the service agreement | 90 days |
| Recovery time under the service agreement | within 4 hours |
One design rule sits underneath all of this: no single machine, and no single set of keys, can destroy the archive. The hardware that holds the third copy has a credential that can read the backups and nothing else. We checked by trying: uploads are refused, deletes are refused. The servers, for their part, hold no credential for that hardware at all. A compromise of any one machine leaves the other copies intact.
Retention ages out backup files, never data. Every nightly backup is a full copy, so a layer you uploaded a year ago is in tonight's backup and every one after it. What the window limits is how far back you can rewind, which is really the deadline for noticing a mistake. Deleted items also sit in the in-app recycle bin for 30 days before anything physical is removed.
Backups we have actually restored. The nightly copy has been restored in full, with row counts matched table by table. The point-in-time backup has been restored on production, replayed to a chosen moment, and compared row for row against the live database. And every restore ends with an automatic integrity check that walks every map layer and confirms its data is really there. A backup that has never been restored is a hope, not a backup.
Who can reach your data#
From the internet: a server answers on exactly three ports, for web traffic and key-only SSH. Everything else, including the database, is unreachable from outside. Administrative tools, monitoring dashboards and log search are only reachable through an encrypted VPN tunnel, never from the public internet.
Between customers: isolation is enforced inside the database itself, not in application code. Every table carries row-level security, and the organization a request belongs to comes from the signed session token, so there is no code path that can forget to filter. Map tiles are rendered per request with the requester's permissions applied, which is why we run the tile server without a cache: a tile drawn for one user is never handed to another. Uploaded images and files go through the same authorization layer. Removing someone from your organization takes effect immediately, regardless of any session they still hold.
Our own access: the tooling we use to diagnose production runs under a database role that can only read. That limit is enforced by the database, not by a setting in a tool, so a bug or a manipulated tool cannot write to your data.
Changes to the platform: every change is tested and deployed to the development environment first, and production only ever receives the exact software that has already been running there. Database changes are trial-run and rolled back before they are applied for real, applied as one all-or-nothing step, and preceded by a fresh backup. We added the trial step after a release once left our own environment half-updated. It cannot happen that way again.
How we notice when something goes wrong#
The failure we worry about most is not a loud crash. It is a backup job that quietly stopped three weeks ago. So most of the monitoring is built around silence.
Uptime checks watch the app, the map tiles and the login service for both environments, and the login check talks to the real authentication service rather than the gateway in front of it. Every certificate has an expiry alarm weeks ahead of time. The database and the backup jobs send heartbeats, and an alarm fires when a heartbeat stops arriving, not when something reports an error. The monitoring hardware and the servers watch each other, so an outage on either side is noticed within about fifteen minutes. Backup freshness alarms run on the servers themselves, so they fire even if the monitoring hardware is what went down. Logs from both servers are kept for 30 days and searchable only over the VPN, with alert rules for error bursts and for log streams that simply go quiet. Everything lands in a channel a human reads.
How we keep it patched#
Operating system security updates install automatically on every machine, and kernel updates reboot the servers in a scheduled night-time window. Every software image the platform runs is pinned to an exact version, and a daily scan checks all of them, including the ones we build ourselves, against the vulnerability databases. New serious findings go to a dedicated security channel. Third-party packages are held back for a cooling-off period before they can enter a build, so a malicious package published yesterday cannot ride into OrbGIS today.
What we deliberately do not do#
- No US provider anywhere in the operating chain. Not for hosting, backups, monitoring or AI features.
- No single credential that reaches all copies of your data. The one property we would keep if we had to drop everything else.
Get new articles by email
One email when we publish something new, nothing else.