Running `qgis_process` in a Docker container is an excellent way to run headless spatial analysis, automate geoprocessing models, or scale GIS tasks in the cloud without dealing with a heavy desktop GUI. The **best and most reliable way** to do this is by leveraging the official `qgis/qgis` image as your base and configuring the shell to run headlessly. --- ## 1. The Core Trick: Headless Configuration Even though `qgis_process` runs entirely in the command line, QGIS fundamentally relies on Qt for its processing plugins and library dependencies. If you try to run it inside a vanilla Linux container, it will crash, shouting about a missing X Server/Display (`Could not connect to any X display`). To bypass this without installing a heavy display manager, you must set the environment variable: `QT_QPA_PLATFORM=offscreen` --- ## 2. Setting Up the Dockerfile If you need a reliable, minimal setup that allows you to pass commands directly or pass scripts into the container, use a `Dockerfile` like this: ```dockerfile # Use the official LTS or stable QGIS image FROM qgis/qgis:release-3_34 # Crucial: Instruct Qt to run in headless/offscreen mode ENV QT_QPA_PLATFORM=offscreen # Set a working directory for your GIS data and scripts WORKDIR /workspace # (Optional) If you plan to pass inputs/outputs via JSON # ENV QGIS_PROCESS_JSON=1 # Set the default entrypoint directly to the utility ENTRYPOINT ["qgis_process"] ``` ### Build the Image: ```bash docker build -t headless-qgis . ``` --- ## 3. Best Practices for Running the Container Because `qgis_process` is a standalone CLI tool, you usually want to treat it like a binary executable—spin it up, execute a task, output the results to your host machine, and destroy the container. ### A. List Available Algorithms To see if your container is working correctly, run this to list all available tools (including native, GRASS, and GDAL tools): ```bash docker run --rm headless-qgis list ``` ### B. Run an Algorithm with Mounted Data When running actual geoprocessing tasks, you need to mount a local directory containing your shapefiles, GeoTIFFs, or GeoJSONs using a volume map (`-v`). Here is how you would run a simple `native:buffer` algorithm: ```bash docker run --rm \ -v /path/to/local/data:/workspace \ headless-qgis run native:buffer \ --INPUT=/workspace/input_roads.shp \ --DISTANCE=50 \ --OUTPUT=/workspace/buffered_roads.shp ``` * `--rm`: Automatically deletes the container instance after the process completes to keep your system clean. * `-v`: Maps your host data folder to `/workspace` inside the container. Both inputs and outputs must reference this container path. ### C. The Pro-Tip: Use JSON for Complex Inputs Passing dozens of flags via standard bash syntax can get ugly quickly—especially if you have complex, nested parameter arrays. Modern versions of `qgis_process` allow you to pipe or pass arguments via JSON. Instead of writing endless `--PARAMETER=VALUE` flags, copy the JSON configuration directly from the QGIS Desktop History GUI and use: ```bash docker run --rm -i headless-qgis run native:buffer - < my_params.json ``` *(The `-` tells `qgis_process` to read parameters directly from standard input).* --- ## 4. Alternative: Pre-built Community Images If you don't want to build your own Dockerfile, you can pull highly optimized community images depending on your stack: * **For R Users:** The `ghcr.io/geocompx/docker:qgis` image comes heavily optimized out-of-the-box for pairing `qgis_process` with the `qgisprocess` R package. * **For Python/GDAL workflows:** If you are trying to layer this into a specialized pipeline, you can use `FROM qgis/qgis` as your base and install your external Python dependencies (like `pandas`, `scipy`, or `boto3`) right on top of it.