How the GeoLibre Docker Container Bundles Nginx and the Python Sidecar
The GeoLibre Docker image uses a multi-stage build that combines a static nginx-served frontend with a Python FastAPI sidecar, reverse-proxied behind the same nginx instance at the /sidecar path.
This article explains how the opengeos/GeoLibre repository packages a web-based geospatial application and its optional conversion service into a single production-ready container. The architecture separates build-time asset generation from runtime delivery, enabling efficient caching and minimal final image size.
Multi-Stage Build Architecture
The Dockerfile implements a two-stage build process that isolates Node.js build dependencies from the Python runtime environment.
Stage 1: Node Build Environment
The first stage uses node:22-alpine with platform awareness to compile the frontend assets.
FROM --platform=$BUILDPLATFORM node:22-alpine AS builder
Key build steps in this stage:
- Layer caching optimization — All workspace
package.jsonfiles are copied before the main source tree, allowingnpm cito create a cached dependency layer that only invalidates when packages change. - Full source copy — After dependency installation, the complete source tree is copied into the build context.
- Production build — Running
npm run buildgenerates optimized static assets inapps/geolibre-desktop/dist.
Stage 2: Python Runtime Environment
The runtime stage uses python:3.12-slim-bookworm specifically for glibc compatibility with pre-built Python wheels.
Core runtime dependencies:
nginx— Static file server and reverse proxylibexpat1— XML parsing supportopenssl— Cryptographic operations
Sidecar installation:
The FastAPI sidecar source from backend/geolibre_server is copied to /opt/geolibre_server and installed alongside duckdb and rio-cogeo wheels. Platform-specific handling includes freestiler and whitebox-workflows wheels for amd64 only—they are skipped on arm64 due to unavailable pre-built binaries.
Nginx Configuration and Routing
The nginx setup bridges the frontend and sidecar services under a unified host.
Configuration Template
The file docker/nginx.conf serves as a template copied to /etc/nginx/nginx.conf.template during image build. This template supports runtime variable substitution for:
- Sidecar authentication token — Injected per container launch for security isolation
- Optional Basic Auth — Conditionally enabled via environment variables
Runtime Configuration Generation
The docker/entrypoint.sh script renders the template into /etc/nginx/conf.d/default.conf on container startup. This dynamic generation allows credential injection without rebuilding the image.
Static asset serving:
Built web assets from apps/geolibre-desktop/dist are placed in /usr/share/nginx/html, making the UI available at the container root (/).
Sidecar proxying:
All FastAPI endpoints are reverse-proxied through /sidecar, enabling same-origin access to conversion APIs without CORS configuration.
Environment Configuration
The container accepts several environment variables to configure sidecar behavior:
| Variable | Purpose |
|---|---|
GEOLIBRE_CONVERSION_ROOTS |
Colon-separated paths the sidecar may access for file operations |
GEOLIBRE_CONVERSION_PYTHON |
Python interpreter path for conversion scripts |
GEOLIBRE_AUTH_USER |
Basic Auth username (optional) |
GEOLIBRE_AUTH_PASSWORD |
Basic Auth password hash (optional) |
Health Check and Startup
The image includes a HEALTHCHECK directive that pings /healthz to verify sidecar responsiveness. This endpoint is explicitly exempt from Basic Auth requirements to ensure reliable orchestration health probes.
Container startup executes entrypoint.sh, which:
- Renders the nginx configuration template
- Injects authentication credentials and sidecar token
- Launches nginx as the primary process
- Starts the sidecar via
uvicornas a background service
Building and Running the Container
Build the Image
docker build -t geolibre:latest .
Run with Default Settings
Mount a local data directory to /data for file access:
docker run -d -p 8080:80 \
-v "$(pwd)/data:/data" \
--name geolibre \
geolibre:latest
Enable Basic Authentication
Provide credentials via environment variables at runtime:
docker run -d -p 8080:80 \
-e GEOLIBRE_AUTH_USER=admin \
-e GEOLIBRE_AUTH_PASSWORD=$(openssl passwd -apr1 secret) \
-v "$(pwd)/data:/data" \
--name geolibre \
geolibre:latest
Access the Sidecar API
Use the reverse-proxied path to reach conversion endpoints:
curl http://localhost:8080/sidecar/convert/vector
Key Source Files
Understanding these files provides complete visibility into the bundling approach:
Dockerfile— Multi-stage build orchestrating Node and Python environmentsdocker/nginx.conf— Server template with proxy rules and Content-Security-Policy headersdocker/entrypoint.sh— Runtime configuration generator and process supervisorbackend/geolibre_server/— FastAPI implementation providing vector, raster, and Whitebox geoprocessing APIsapps/geolibre-desktop/dist/— Compiled static assets served by nginx
Summary
- The two-stage build separates Node.js compilation from Python runtime, optimizing layer caching and final image size.
- Nginx serves dual roles as static file server for the frontend and reverse proxy for the sidecar at
/sidecar. - Runtime configuration via
entrypoint.shenables dynamic credential injection without image rebuilds. - Platform-aware builds conditionally include
freestilerandwhitebox-workflowsonly on amd64 where wheels exist. - Health checks verify sidecar availability while remaining accessible to container orchestrators.
Frequently Asked Questions
How does the sidecar communicate with the main application?
The sidecar runs as a separate process within the same container, accessed via nginx's reverse proxy at the /sidecar path. This same-origin routing eliminates CORS requirements and provides unified ingress through port 80.
Can I run the nginx frontend without the Python sidecar?
The entrypoint.sh script starts both services by default. To disable the sidecar, you would need to override the container command or modify the entrypoint, though this is not the intended deployment pattern in the opengeos/GeoLibre source.
Why use python:3.12-slim-bookworm instead of alpine for the runtime stage?
The slim-bookworm variant provides glibc compatibility required for pre-built wheels including duckdb and rio-cogeo. Alpine's musl libc often fails with many scientific Python packages that distribute only manylinux wheels.
How is the sidecar token secured?
A unique token is generated on each container launch by entrypoint.sh and injected into the nginx configuration. This token must be included in sidecar requests, providing request authentication without persistent credential storage in the image.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →