Deployment Guide
A comprehensive guide to deploying GeoServer in any environment โ Docker, Kubernetes, cloud, or on-premise. Get your geospatial infrastructure running in minutes.
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+ |
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.
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
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
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
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.
Add the GeoServer Helm Repository
helm repo add geoserver https://charts.geoserver.io
helm repo update
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
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
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.
Initialize Terraform
# Clone the module
git clone https://github.com/geoserver/terraform-aws-geoserver.git
cd terraform-aws-geoserver
# Initialize
terraform init
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"
}
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>
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.
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
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/
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
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:
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
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:
- Always use HTTPS โ configure SSL/TLS via your reverse proxy or ingress controller.
- Change default credentials โ never ship with
admin/geoserverin production. - Enable authentication โ GeoServer supports LDAP, Active Directory, OAuth2, and JWT.
- Set resource quotas โ limit WFS feature counts, WMS bounding box sizes, and request timeouts.
- Disable unused services โ turn off WFS-T, REST config API, or other endpoints not in use.
- Apply security headers โ use your reverse proxy to inject CSP, HSTS, and X-Frame-Options headers.
- Network segmentation โ place GeoServer in a private subnet with only required ports exposed.
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
- Deploy multiple GeoServer instances behind a load balancer
- Use a shared data directory (PostgreSQL or NFS)
- Enable sticky sessions for long-running WFS-T transactions
- Configure Redis for distributed tile caching
Vertical Scaling
- Increase JVM heap:
JAVA_OPTS="-Xms4g -Xmx8g" - Use G1GC for large heaps:
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 - Enable map tile caching to reduce rendering load
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
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
- Check the
logs/geoserver.logfile for CRS errors - Verify the data store connection is working
- Ensure the layer's bounding box is correctly set
- Check if the style (SLD) references valid attributes
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
- Enable tile caching (GeoWebCache is bundled)
- Optimize SLD styles โ avoid complex filters
- Use vector tiles instead of WMS for large datasets
- Check database query performance for feature stores
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:
- Back up your data directory and database
- Read the release notes for breaking changes
- Test in staging before upgrading production
- Update the image/container to the new version
- 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