Self-hosted OpenStreetMap stack and Python client for spatial analysis
Project description
OSMForge
A self-hosted OpenStreetMap stack that downloads regional OSM extracts, ingests them into a local PostGIS database, and serves a GeoJSON API optimised for spatial analysis — particularly radio-frequency propagation modelling.
Public OSM APIs (Overpass, Nominatim) have strict rate limits and aren't suited to bulk or repeated spatial queries. OSMForge gives you unlimited local access to the same data.
Contents
- Architecture
- Prerequisites
- Quick start
- Adding regions
- Makefile reference
- API reference
- Python client
- Data layers
Architecture
Geofabrik ──download──▶ *.osm.pbf
│
osm2pgsql (Lua flex)
│
osm schema (raw)
osm_points / osm_lines / osm_polygons
│
make layers (SQL)
│
app schema (classified)
osm_buildings / osm_roads / osm_water /
osm_vegetation / osm_landuse /
osm_structures / osm_terrain
│
FastAPI :8000
│
osmforge.client
The osm schema holds raw data exactly as loaded by osm2pgsql.
The app schema holds pre-classified, indexed tables ready for querying.
Prerequisites
| Tool | Version | Notes |
|---|---|---|
| Docker + Compose v2 | latest | docker compose version |
| osm2pgsql | ≥ 1.9 | osm2pgsql --version |
| Python | ≥ 3.12 | |
| Poetry | ≥ 1.8 | pip install poetry |
Install Python dependencies:
poetry install
Quick start
1 — Start the database
make up
This starts a PostGIS 17 container on localhost:5432 and the FastAPI container
on localhost:8000. On first run Docker will pull the images.
2 — Download an OSM extract
Extracts come from Geofabrik. Pass the full path from the Geofabrik URL:
make download REGION=europe/united-kingdom/england/isle-of-wight
The file lands in osmforge/data/ and is skipped on subsequent runs unless you
pass FORCE=--force.
3 — Ingest + build layers
make ingest # load every *.osm.pbf in osmforge/data/ into osm.*
make layers # build classified app.* tables
Or in one step:
make rebuild
4 — Query the API
curl "http://localhost:8000/propagation/bbox?min_lon=-1.35&min_lat=50.65&max_lon=-1.1&max_lat=50.78"
Adding regions
Download as many regions as you like before ingesting — make ingest loads
everything in osmforge/data/ in a single pass.
# individual counties
make download REGION=europe/united-kingdom/england/west-midlands
make download REGION=europe/united-kingdom/england/staffordshire
make download REGION=europe/united-kingdom/england/warwickshire
# then ingest them all together
make rebuild
To see what Geofabrik has available, browse:
- England: https://download.geofabrik.de/europe/united-kingdom/england.html
- Full index: https://download.geofabrik.de
Makefile reference
| Command | Description |
|---|---|
make up |
Start PostGIS + API containers |
make down |
Stop containers (data volume preserved) |
make download REGION=<path> |
Download a PBF from Geofabrik |
make ingest |
Load all PBFs in osmforge/data/ via osm2pgsql |
make layers |
Build app.* tables from raw osm.* data |
make rebuild |
ingest + layers in one step |
make rebuild-api |
Rebuild the API Docker image after code changes |
make clean |
Destroy containers and data volume (full reset) |
make interface |
Open a psql shell to the database |
make help |
List all targets |
API reference
The API runs at http://localhost:8000. Interactive docs at
http://localhost:8000/docs.
GET /health
200 {"status": "ok"}
GET /propagation/bbox
Return classified OSM features within a bounding box.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
min_lon |
float | ✓ | West edge (WGS-84) |
min_lat |
float | ✓ | South edge |
max_lon |
float | ✓ | East edge |
max_lat |
float | ✓ | North edge |
layers |
string (repeat) | Subset of layers (default: all) | |
limit |
int | Max features returned |
Example
GET /propagation/bbox?min_lon=-1.35&min_lat=50.65&max_lon=-1.1&max_lat=50.78&layers=buildings&layers=terrain
Response — GeoJSON FeatureCollection. Each feature's properties:
{
"osm_id": 123456,
"name": "St Mary's Church",
"layer": "buildings",
"feature_class": "church",
"height_m": 18.0,
"levels": "3",
"material": "stone"
}
POST /propagation/geometry
Return classified OSM features intersecting an arbitrary polygon or multipolygon. Useful when you already have a coverage or study-area polygon.
Request body
{
"geometry": {
"type": "Polygon",
"coordinates": [[[<lon>, <lat>], ...]]
},
"layers": ["buildings", "vegetation", "terrain"],
"limit": 5000
}
| Field | Type | Required | Description |
|---|---|---|---|
geometry |
GeoJSON geometry | ✓ | Polygon or MultiPolygon, WGS-84 |
layers |
array of strings | Subset of layers (default: all) | |
limit |
int | Max features returned |
GET /features/bbox
Return raw OSM features (all tags) within a bounding box. Useful for
exploration; use /propagation/bbox for modelling workflows.
Query parameters — same bbox params as above, plus optional limit.
Python client
Install the package then import the client:
from osmforge.client import OSMClient
client = OSMClient() # default: http://localhost:8000
# or: OSMClient("http://my-server:8000")
All methods return a geopandas.GeoDataFrame (CRS EPSG:4326).
client.propagation_bbox
gdf = client.propagation_bbox(
min_lon=-1.35,
min_lat=50.65,
max_lon=-1.1,
max_lat=50.78,
)
Filter to specific layers:
gdf = client.propagation_bbox(
min_lon=-1.35, min_lat=50.65,
max_lon=-1.1, max_lat=50.78,
layers=["buildings", "terrain"],
limit=10000,
)
client.propagation_geometry
Accepts a GeoJSON dict or a Shapely geometry:
from shapely.geometry import Polygon
area = Polygon([
(-1.35, 50.65), (-1.1, 50.65),
(-1.1, 50.78), (-1.35, 50.78),
(-1.35, 50.65),
])
gdf = client.propagation_geometry(area)
# with options
gdf = client.propagation_geometry(
area,
layers=["buildings", "vegetation", "terrain"],
limit=50000,
)
client.features_bbox
gdf = client.features_bbox(
min_lon=-1.35,
min_lat=50.65,
max_lon=-1.1,
max_lat=50.78,
)
# gdf.columns → geometry, osm_id, name, source_layer, tags
Data layers
| Layer | Source OSM tags | Key properties |
|---|---|---|
buildings |
building=* |
building_type, height_m, levels, material |
roads |
highway=*, railway=* |
transport_class (major / secondary / local / rail / …) |
water |
natural=water, waterway=*, landuse=reservoir |
water_class |
vegetation |
landuse=forest, natural=wood/scrub/heath/grassland, leisure=park |
vegetation_class |
landuse |
landuse=* |
landuse_class (residential / industrial / agricultural / …) |
structures |
man_made=mast/tower, power=tower/line, bridges, embankments |
structure_class |
terrain |
natural=cliff/ridge/coastline/peak/saddle, barriers, chimneys |
terrain_class, height_m |
Height estimation
height_m on buildings is derived from OSM tags in order of preference:
height=*(metres, if numeric)building:levels=*× 3 m per floorNULLif neither is tagged
Terrain classes
terrain_class |
Geometry | Propagation relevance |
|---|---|---|
cliff |
line | Hard diffraction edge |
ridge |
line | Diffraction / shadowing |
coastline |
line | Land/sea boundary — sea has near-zero attenuation |
barrier_wall |
line | Urban canyon obstruction |
embankment / cutting |
line | Signal blocking |
peak / saddle |
point | Elevation proxy |
chimney / storage_tank |
point | Tall point obstacles |
communications_tower |
point | Co-channel interference sources |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file osmforge-1.1.2.tar.gz.
File metadata
- Download URL: osmforge-1.1.2.tar.gz
- Upload date:
- Size: 8.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.2 CPython/3.12.3 Linux/6.17.0-14-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0c7f06dd68f9dbf8678cb38ea0d77cf7e89edc0b59c4f3d0fa6400c12a8e050
|
|
| MD5 |
fdc02bc2a93bf1187546a6775d732767
|
|
| BLAKE2b-256 |
d07389e559687f51fbcad369e2aed0af02c1081d232668b16c239ebe214edd7f
|
File details
Details for the file osmforge-1.1.2-py3-none-any.whl.
File metadata
- Download URL: osmforge-1.1.2-py3-none-any.whl
- Upload date:
- Size: 9.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.2 CPython/3.12.3 Linux/6.17.0-14-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1db8157c25a1544a6bb650d4e4a136feefeeaae9f6ab9a47c6b39c3ae6b59d24
|
|
| MD5 |
86cf26b3c6716b911eb5e2d9d0854ee4
|
|
| BLAKE2b-256 |
abcef2d81bb787a6c351cd118f06f66720af700517bce779faf049dc8391567f
|