Deployment Guide

A comprehensive guide to deploying GeoServer in any environment โ€” Docker, Kubernetes, cloud, or on-premise. Get your geospatial infrastructure running in minutes.

๐Ÿ“… Updated: Jan 15, 2025
โฑ๏ธ 15 min read
๐Ÿ“ฆ v3.1.x
โœ๏ธ GeoServer Team
โ„น๏ธ
Choosing a Deployment Method

This guide covers four deployment paths. For most users, we recommend Docker for development and Kubernetes (Helm) for production. Jump to your preferred method using the sidebar or anchors below.

System Requirements

Before deploying GeoServer, ensure your environment meets the minimum requirements. These specs vary based on deployment type and expected workload.

Requirement Minimum Recommended High Load
CPU 2 vCPUs 4 vCPUs 8+ vCPUs
RAM 4 GB 8 GB 16+ GB
Storage 20 GB SSD 100 GB SSD 500+ GB NVMe
OS Linux / Docker Ubuntu 22.04+ Ubuntu 22.04+
Java OpenJDK 17 OpenJDK 17 OpenJDK 21
Disk I/O โ€” IOPS 3,000+ IOPS 10,000+
โš ๏ธ
Java Version

GeoServer v3.1 requires Java 17 minimum. Java 11 and earlier are no longer supported. Ensure your runtime uses the correct JDK.

Docker Deployment

The fastest way to get GeoServer running locally or in a containerized environment. Use the official geoserver/geoserver image from Docker Hub.

1

Pull the Latest Image

Download the latest stable release from Docker Hub:

docker pull geoserver/geoserver:latest

Or pull a specific version for reproducibility:

docker pull geoserver/geoserver:3.1.0
2

Run the Container

Start a basic GeoServer instance with exposed ports and persistent data:

docker run -d \
  --name geoserver \
  -p 8080:8080 \
  -v geoserver-data:/geoserver/data_dir \
  -e GEOSERVER_ADMIN_PASSWORD=ChangeMe! \
  geoserver/geoserver:latest

Access the admin console at http://localhost:8080/geoserver/web

3

Verify the Deployment

Check that the container is running and healthy:

docker ps | grep geoserver
# Expected output:
# CONTAINER ID   IMAGE                        STATUS          PORTS
# abc123def456   geoserver/geoserver:latest   Up 2 minutes    0.0.0.0:8080->8080/tcp

curl -s http://localhost:8080/geoserver/web | grep -o "GeoServer" | head -1
# Expected output: GeoServer
โœ…
Docker Compose Alternative

For multi-container setups (GeoServer + PostGIS + Traefik), use our official Docker Compose template: docker compose -f docker-compose.yml up -d

Kubernetes / Helm Deployment

For production environments, deploy GeoServer on Kubernetes using our official Helm chart. This provides auto-scaling, rolling updates, and high availability.

1

Add the GeoServer Helm Repository

helm repo add geoserver https://charts.geoserver.io
helm repo update
2

Create a Custom Values File

Create a values.yaml with your configuration overrides:

# values.yaml
replicaCount: 3

image:
  repository: geoserver/geoserver
  tag: "3.1.0"
  pullPolicy: IfNotPresent

service:
  type: LoadBalancer
  port: 8080

resources:
  requests:
    cpu: "2"
    memory: "4Gi"
  limits:
    cpu: "4"
    memory: "8Gi"

persistence:
  enabled: true
  size: 100Gi
  storageClass: "gp3"

environment:
  GEOSERVER_ADMIN_PASSWORD: "<secure-password>"
  GEOSERVER_DATA_DIR: "/geoserver/data_dir"
  JAVA_OPTS: "-Xms2g -Xmx4g"

ingress:
  enabled: true
  host: geoserver.example.com
  tls:
    enabled: true
    secretName: geoserver-tls
3

Install the Chart

helm install geoserver geoserver/geoserver \
  -f values.yaml \
  --namespace geoserver \
  --create-namespace \
  --version 2.5.0

Verify the deployment:

kubectl get pods -n geoserver
kubectl get svc -n geoserver
kubectl get ingress -n geoserver
4

Configure Horizontal Pod Autoscaler (HPA)

Enable autoscaling based on CPU and custom metrics:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: geoserver-hpa
  namespace: geoserver
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: geoserver
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

Terraform / Cloud Deployment

Deploy GeoServer infrastructure as code on AWS, GCP, or Azure using our Terraform modules.

1

Initialize Terraform

# Clone the module
git clone https://github.com/geoserver/terraform-aws-geoserver.git
cd terraform-aws-geoserver

# Initialize
terraform init
2

Configure Variables

# variables.tf example
variable "instance_type" {
  default = "r5.xlarge"
}

variable "vpc_cidr" {
  default = "10.0.0.0/16"
}

variable "enable_postgis" {
  default = true
}

variable "geoserver_version" {
  default = "3.1.0"
}
3

Apply the Infrastructure

# Review the plan
terraform plan -var-file=environments/production.tfvars

# Apply
terraform apply -var-file=environments/production.tfvars

# Outputs
terraform output
# geoserver_endpoint: https://geoserver.prod.example.com
# admin_username: admin
# admin_password: <stored-in-secrets-manager>
โ„น๏ธ
Supported Cloud Providers

We maintain official Terraform modules for AWS (EC2 + EKS + RDS), GCP (GCE + GKE + Cloud SQL), and Azure (VMSS + AKS + Cosmos DB). Each module includes networking, security groups, load balancing, and monitoring out of the box.

On-Premise Deployment

For organizations requiring full control over infrastructure, GeoServer can be deployed directly on bare metal or virtual machines.

1

Install Java and Dependencies

# Ubuntu 22.04 / Debian 12
sudo apt update && sudo apt install -y openjdk-17-jdk \
  nginx git curl wget

# Verify Java
java -version
# openjdk version "17.0.9" 2023-10-17
2

Download and Extract GeoServer

VERSION=3.1.0
cd /opt
wget https://sourceforge.net/projects/geoserver/files/GeoServer/${VERSION}/geoserver-${VERSION}.war
sudo mkdir -p /opt/geoserver
cp geoserver-${VERSION}.war /opt/geoserver/
3

Deploy with Tomcat or Jetty

# Install Tomcat 10
sudo apt install -y tomcat10 tomcat10-admin

# Deploy the WAR file
sudo cp /opt/geoserver/geoserver-${VERSION}.war \
  /var/lib/tomcat10/webapps/

# Configure JVM memory
sudo nano /etc/default/tomcat10
# JAVA_OPTS="-Xms2048m -Xmx4096m -XX:+UseG1GC"

# Start and enable
sudo systemctl enable tomcat10
sudo systemctl start tomcat10
sudo systemctl status tomcat10
# Install Jetty
sudo apt install -y jetty11

# Deploy
sudo cp /opt/geoserver/geoserver-${VERSION}.war \
  /var/lib/jetty/webapps/geoserver.war

# Configure
sudo nano /etc/jetty/start.ini
# Add: -Xmx4096m

# Start
sudo systemctl enable jetty11
sudo systemctl start jetty11
4

Configure Nginx Reverse Proxy

sudo tee /etc/nginx/sites-available/geoserver <<'EOF'
server {
    listen 80;
    server_name geoserver.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name geoserver.example.com;

    ssl_certificate     /etc/letsencrypt/live/geoserver.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/geoserver.example.com/privkey.pem;

    client_max_body_size 500M;

    location /geoserver {
        proxy_pass http://127.0.0.1:8080/geoserver;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 300;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/geoserver /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Environment Variables

GeoServer supports extensive configuration via environment variables. Here are the most important ones:

GEOSERVER_ADMIN_PASSWORD Admin user password "admin" (default)
GEOSERVER_DATA_DIR Path to the GeoServer data directory "/geoserver/data_dir"
JAVA_OPTS JVM arguments (heap size, GC, etc.) "-Xms512m -Xmx1024m"
GEOSERVER_MAX_MEMORY Max JVM heap in MB "1024"
GEOSERVER_PROXY_BASE_URL Base URL when behind a reverse proxy null
LOG_LEVEL Logging level (DEBUG, INFO, WARN, ERROR) "INFO"
GEOSERVER_CSRF_DISABLED Disable CSRF protection (not recommended in prod) "false"
POSTGRES_HOST PostgreSQL database host for data directory storage null
POSTGRES_DB Database name for GeoServer config storage "geoserver"
GEOSERVER_CACHING_ENABLED Enable map tile caching "true"

Storage & Database

GeoServer's data directory stores all configurations, styles, layers, and cached tiles. For production, we recommend storing it on persistent volume or in a PostgreSQL database.

Option A: Persistent Volume (Docker/K8s)

# Docker volume
docker volume create geoserver-data

# Verify
docker volume inspect geoserver-data

Option B: PostgreSQL Data Directory

Store your data directory in a PostgreSQL database for easier backups and replication:

# 1. Create the database
createdb -U postgres geoserver

# 2. Run the migration script
docker exec geoserver \
  /geoserver/bin/pgsql-migrate.sh \
  --host=db.example.com \
  --database=geoserver \
  --user=geoserver_admin \
  --password=secret

# 3. Set environment variable
export GEOSERVER_DB_TYPE=postgresql
โš ๏ธ
Backup Before Migrating

Always back up your file-based data directory before migrating to a database. The migration is one-way and should be tested in a staging environment first.

Networking

GeoServer exposes several ports. Ensure your firewall and security group rules allow the necessary traffic:

Port Protocol Purpose Direction
8080 TCP GeoServer HTTP (WMS, WFS, WCS, REST API) Inbound
443 TCP GeoServer HTTPS (recommended) Inbound
5432 TCP PostgreSQL (for data directory DB) Outbound
6379 TCP Redis (for distributed caching) Outbound

Security

Security is critical for geospatial infrastructure. Follow these best practices:

Enable OAuth2 Authentication

# In your values.yaml or environment
GEOSERVER_SECURITY_AUTH_MODULE=oauth2
OAUTH2_ISSUER_URI=https://auth.example.com
OAUTH2_CLIENT_ID=geoserver-client
OAUTH2_CLIENT_SECRET=secret_value_here
OAUTH2_SCOPES=openid profile

Monitoring

GeoServer ships with built-in metrics endpoints compatible with Prometheus and Grafana.

Prometheus Configuration

# prometheus.yml
scrape_configs:
  - job_name: 'geoserver'
    metrics_path: '/geoserver/rest/metrics'
    scrape_interval: 15s
    static_configs:
      - targets: ['geoserver:8080']

Key Metrics to Monitor

Metric Description Alert Threshold
geoserver_requests_total Total WMS/WFS/WCS requests โ€”
geoserver_request_duration_ms Request latency p95 > 5000ms
geoserver_errors_total Error count by type Rate > 10/min
geoserver_layers_count Active layer count โ€”
geoserver_cache_hit_ratio Tile cache effectiveness < 70%
java_heap_usage_percent JVM heap utilization > 85%

Scaling

GeoServer supports both horizontal and vertical scaling:

Horizontal Scaling

Vertical Scaling

Backup & Restore

Backup (File-Based)

# Docker
docker exec geoserver \
  tar czf /tmp/geoserver-backup-$(date +%F).tar.gz \
  /geoserver/data_dir/

docker cp geoserver:/tmp/geoserver-backup-$(date +%F).tar.gz ./

# Kubernetes
kubectl exec -n geoserver geoserver-pod \
  -- tar czf /tmp/backup.tar.gz /geoserver/data_dir/

Restore

# Stop GeoServer
docker stop geoserver

# Copy backup back
docker cp ./geoserver-backup-2025-01-15.tar.gz \
  geoserver:/tmp/

# Extract
docker exec geoserver \
  tar xzf /tmp/geoserver-backup-2025-01-15.tar.gz \
  -C /

# Restart
docker start geoserver
๐Ÿšจ
Test Your Backups Regularly

A backup is only useful if it can be restored. Run restore drills quarterly in a staging environment. Verify layer counts, style integrity, and configuration settings after each restore.

Troubleshooting

Common Issues

GeoServer Fails to Start

# Check container logs
docker logs geoserver --tail 50

# Common causes:
# 1. Port 8080 already in use โ†’ change with -p 9090:8080
# 2. Insufficient memory โ†’ increase JVM heap
# 3. Permission denied on data_dir โ†’ fix ownership
# 4. Java version mismatch โ†’ use OpenJDK 17+

Layers Not Rendering

High Memory Usage

# Check JVM memory
docker exec geoserver jcmd 1 VM.gc_heap_info

# Tune GC settings
JAVA_OPTS="-Xms4g -Xmx8g \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=/geoserver/logs/"

Slow Map Rendering

โ„น๏ธ
Need More Help?

Visit our Community Forum, open an issue on GitHub, or contact our Enterprise Support team for priority assistance.

Upgrades

When upgrading GeoServer, follow these steps to ensure a smooth transition:

  1. Back up your data directory and database
  2. Read the release notes for breaking changes
  3. Test in staging before upgrading production
  4. Update the image/container to the new version
  5. Verify all layers, styles, and services work correctly
# Docker upgrade
docker pull geoserver/geoserver:3.1.0
docker stop geoserver && docker rm geoserver
docker run -d \
  --name geoserver \
  -p 8080:8080 \
  -v geoserver-data:/geoserver/data_dir \
  geoserver/geoserver:3.1.0

# Helm upgrade
helm upgrade geoserver geoserver/geoserver \
  -f values.yaml \
  --set image.tag="3.1.0" \
  --namespace geoserver