Applications Azure

ZOO-Project 2.1.0 on Ubuntu 24.04 on Azure User Guide

| Product: ZOO-Project 2.1.0 on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and use of ZOO-Project 2.1.0 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. ZOO-Project is the OSGeo OGC Web Processing Service (WPS) and OGC API - Processes server: the ZOO-Kernel C server runs geospatial processing services and exposes them over the open OGC standards so any client can submit a processing request over HTTP and retrieve the result.

The cloudimg image compiles ZOO-Kernel 2.1.0 from a pinned upstream release with FastCGI, Python, and the GDAL / GEOS / PROJ geospatial libraries, and serves it behind nginx on port 80 through an always-on fcgiwrap FastCGI gateway. It ships the safe built-in demonstration services — a Python HelloPy service, the OGR/GEOS vector operations (Buffer, Centroid, ConvexHull, Intersection, Union, Simplify, Distance, GetArea, and more), OGR Ogr2Ogr, and the GDAL raster tools — so the server does real geospatial work the moment it boots. No external database is required for the base WPS.

What is included:

  • ZOO-Project 2.1.0 (ZOO-Kernel, compiled from the pinned upstream rel-2.1.0 source)
  • Both interfaces served on port 80: classic OGC WPS 1.0.0 / 2.0.0 at /cgi-bin/zoo_loader.cgi and OGC API - Processes at /ogc-api/
  • GDAL, GEOS and PROJ geospatial libraries; the OGR/GEOS vector-processing services and GDAL raster services
  • zoo-fcgiwrap.service (FastCGI gateway, runs as www-data) and nginx.service, both auto-starting on boot
  • zoo-project-firstboot.service systemd oneshot that resolves the VM public IP and writes endpoint info on first customer boot
  • Unauthenticated /healthz endpoint for load-balancer probes
  • Ubuntu 24.04 LTS base with the latest security patches applied at build time
  • Azure Linux Agent for seamless cloud integration and SSH key injection
  • 24/7 cloudimg support with a guaranteed 24 hour response SLA

Prerequisites

  • An active Azure subscription
  • A subscription to the ZOO-Project 2.1.0 on Ubuntu 24.04 listing on Azure Marketplace
  • An SSH public key for VM authentication
  • A virtual network and subnet in the target region

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and light processing workloads. Scale up for larger geometries, raster operations, or higher request concurrency.

A note on security: the base ZOO-Project WPS server is a public processing API with no login — this matches upstream, and the cloudimg image never invents a credential. Only the fixed, safe built-in demo services are enabled; the arbitrary process-deployment (Deploy/Replace/Undeploy) endpoints are deliberately excluded. Restrict inbound access to port 80 with a network security group so that only your client networks can reach the processing endpoints.

Step 1: Deploy from the Azure Portal

Navigate to Marketplace in the Azure Portal, search for ZOO-Project, select the cloudimg publisher entry, and click Create.

On the Networking tab attach a network security group that allows inbound TCP 22 from your management IP range and TCP 80 from your client networks (the WPS and OGC API endpoints). Click Review + create, wait for validation, then Create. Deployment takes around two minutes.

Step 2: Deploy from the Azure CLI

az vm create \
  --resource-group my-geo-rg \
  --name zoo-project \
  --image <cloudimg-zoo-project-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

# Open port 80 to your client network:
az vm open-port --resource-group my-geo-rg --name zoo-project --port 80 --priority 900

Step 3: Confirm the service is healthy

SSH in as azureuser and confirm the FastCGI gateway and nginx are both active and the health endpoint responds:

systemctl is-active nginx zoo-fcgiwrap
curl -s -o /dev/null -w 'health: HTTP %{http_code}\n' http://localhost/healthz

Expected output:

active
active
health: HTTP 200

ZOO-Project service health: nginx and the fcgiwrap gateway active, health endpoint returning HTTP 200, GDAL and GEOS versions

The per-VM endpoint URLs (resolved to this VM's public IP on first boot) are recorded at /root/zoo-project-info.txt.

Step 4: WPS GetCapabilities

Ask the server which processing services it offers, using the classic OGC WPS 1.0.0 interface:

curl -s "http://localhost/cgi-bin/zoo_loader.cgi?service=WPS&version=1.0.0&request=GetCapabilities" -o /tmp/wps-capabilities.xml
head -8 /tmp/wps-capabilities.xml

The response is a wps:Capabilities XML document. List the advertised process identifiers:

curl -s "http://localhost/cgi-bin/zoo_loader.cgi?service=WPS&version=1.0.0&request=GetCapabilities" \
  | grep -oE '<ows:Identifier>[^<]+' | sed 's/<ows:Identifier>/  - /'

OGC WPS 1.0.0 GetCapabilities returning the capabilities document and the list of advertised processing services

Step 5: Execute a process

HelloPy is the simplest process — a Python service that takes a literal string input and returns a welcome message. It proves the Execute pipeline end to end:

curl -s "http://localhost/cgi-bin/zoo_loader.cgi?service=WPS&version=1.0.0&request=Execute&Identifier=HelloPy&DataInputs=a=cloudimg&RawDataOutput=Result"

Expected output:

Hello cloudimg from Python World !

Buffer is a real geospatial process built on GDAL and GEOS. Give it a GeoJSON polygon and a buffer distance and it returns the buffered geometry as GML. Here a 10×10 square is buffered outward by 1 unit (note the resulting bounding box -1,-1 to 11,11):

curl -s -G "http://localhost/cgi-bin/zoo_loader.cgi" \
  --data-urlencode 'service=WPS' \
  --data-urlencode 'version=1.0.0' \
  --data-urlencode 'request=Execute' \
  --data-urlencode 'Identifier=Buffer' \
  --data-urlencode 'DataInputs=InputPolygon={"type":"Polygon","coordinates":[[[0,0],[0,10],[10,10],[10,0],[0,0]]]}@mimeType=application/json;BufferDistance=1' \
  --data-urlencode 'RawDataOutput=Result' -o /tmp/buffer-result.gml
head -12 /tmp/buffer-result.gml

WPS Execute results: the HelloPy welcome string and the Buffer service returning a buffered GML polygon

Step 6: OGC API - Processes (JSON REST)

ZOO-Project also serves the modern OGC API - Processes interface at /ogc-api/. List the processes collection as JSON:

curl -s http://localhost/ogc-api/processes \
  | python3 -c 'import sys,json; d=json.load(sys.stdin); print("numberTotal:", d["numberTotal"]); [print("  -", p["id"]) for p in d["processes"][:12]]'

Retrieve a single process description:

curl -s http://localhost/ogc-api/processes/Buffer \
  | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d["id"], "-", d["title"])'

OGC API - Processes listing the processes collection as JSON, and a single Buffer process description

The OGC API landing document (http://localhost/ogc-api/) links the conformance, processes and jobs resources, and each process is also available as HTML at /ogc-api/processes/<id>.html.

Step 7: Configuration and customisation

  • Server configuration: /usr/lib/cgi-bin/main.cfg — the ZOO-Kernel main configuration (server metadata, temp paths, GDAL/PROJ environment). On first boot the advertised server host is set to this VM's public IP.
  • Services directory: /usr/lib/cgi-bin/ — each process is a .zcfg descriptor plus its service implementation (.zo shared object for the compiled OGR/GDAL services, .py for Python services). Add your own services here by dropping in a .zcfg and its implementation.
  • FastCGI gateway: zoo-fcgiwrap.service runs fcgiwrap as www-data on unix:/run/zoo-project/fcgiwrap.sock; nginx proxies to it. Restart with sudo systemctl restart zoo-fcgiwrap nginx after changing services.
  • Web server: /etc/nginx/sites-available/zoo-project routes /cgi-bin/, /ogc-api/, /healthz and the static landing page.

Support

cloudimg images come with 24/7 support and a guaranteed 24 hour response SLA. Contact support@cloudimg.co.uk for assistance. For ZOO-Project itself, see the upstream documentation at zoo-project.org.