Skip to main content

GeoServer Proxy Server (Python)

Browser-based map libraries (Leaflet, OpenLayers, Mapbox GL) cannot set custom HTTP headers on WMS tile or WFS feature requests — it is a browser security restriction. This means you cannot pass your Authorization header directly from client-side JavaScript.

The solution is a backend proxy: a small server that sits between your frontend and Qarta. Your browser sends unauthenticated requests to the proxy; the proxy adds the API key server-side and forwards the request to Qarta.

Browser  →  /wms/GetMap?...  →  Proxy (adds Authorization header)  →  Qarta

The proxy in this guide is a minimal Python/Flask application. It only attaches the API key — it does not modify, inspect, or cache requests.

Download

Download geoserver-proxy.zip

The zip contains proxy.py, pyproject.toml, and a full test suite.

Running the Proxy

Install dependencies:

unzip geoserver-proxy.zip
cd geoserver-proxy
pip install -e ".[dev]"

Start the server:

export QARTA_API_KEY=your_api_key_here
python proxy.py
# Listening on http://0.0.0.0:8080

Optional environment variables:

VariableDefaultDescription
QARTA_API_KEY(required)Your Qarta API key
QARTA_BASE_URLhttps://graph.quarticle.roUpstream Qarta base URL
PROXY_TIMEOUT30Upstream request timeout in seconds

Connecting Your Web Map

Point your Leaflet WMS layer at the proxy instead of directly at Qarta:

import L from 'leaflet';

const map = L.map('map').setView([40.7128, -74.0060], 10);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);

// Point at the proxy — no API key in client-side code
const wmsLayer = L.tileLayer.wms('http://localhost:8080/wms/GetMap', {
layers: 'GRAPHRASTER:light_pollution',
styles: '',
format: 'image/png',
transparent: true,
srs: 'EPSG:3857',
version: '1.3.0',
}).addTo(map);

Other WMS operations (GetCapabilities, GetFeatureInfo, GetLegendGraphic, DescribeLayer) and WFS operations (GetFeature) are proxied in the same way — just change the path:

http://localhost:8080/wms/GetCapabilities
http://localhost:8080/wms/GetFeatureInfo
http://localhost:8080/wms/GetLegendGraphic
http://localhost:8080/wfs/GetFeature

Proxy Source Code

examples/geoserver-proxy/proxy.py
import os

import requests
from flask import Flask, Response, request

QARTA_BASE_URL = os.getenv("QARTA_BASE_URL", "https://graph.quarticle.ro")
QARTA_API_KEY = os.getenv("QARTA_API_KEY")
PROXY_TIMEOUT = int(os.getenv("PROXY_TIMEOUT", "30"))

app = Flask(__name__)


def _forward(service: str, operation: str) -> Response:
"""Forward a WMS or WFS request to Qarta, injecting the API key."""
upstream_url = f"{QARTA_BASE_URL}/graph/layers/{service}/{operation}"
resp = requests.get(
upstream_url,
params=request.args,
headers={"Authorization": QARTA_API_KEY},
timeout=PROXY_TIMEOUT,
stream=True,
)
return Response(
resp.iter_content(chunk_size=8192),
status=resp.status_code,
content_type=resp.headers.get("Content-Type", "application/octet-stream"),
)


@app.get("/wms/<operation>")
def wms_proxy(operation: str) -> Response:
return _forward("wms", operation)


@app.get("/wfs/<operation>")
def wfs_proxy(operation: str) -> Response:
return _forward("wfs", operation)


if __name__ == "__main__":
if not QARTA_API_KEY:
raise RuntimeError("QARTA_API_KEY environment variable is required")
app.run(host="0.0.0.0", port=8080)

Running the Tests

cd geoserver-proxy
pytest tests/ -v

The tests use responses to mock all upstream Qarta calls — no real network requests are made.

Next Steps