Best Practices#

Guidelines for using GeoServer CLI effectively and safely.

Configuration Management#

Use Environment-Specific Configs#

Create separate configurations for each environment:

1
2
3
4
5
configs/
├── default.config.toml    # Template
├── dev.config.toml         # Development
├── staging.config.toml     # Staging
└── prod.config.toml        # Production

Switch between them easily:

1
export GEOSRVCLI_CONFIG=prod

Never Commit Passwords#

Keep sensitive data out of version control:

1
2
3
4
# .gitignore
configs/*.config.toml
!configs/default.config.toml  # Template only
.envrc

Use environment variables for passwords:

1
2
# .envrc (gitignored)
export GEOSRVCLI_PASSWORD=$(vault read -field=password secret/geoserver)

Use direnv for Local Development#

Install direnv and create .envrc:

1
2
3
4
5
# .envrc
export GEOSRVCLI_CONFIG=dev
export GEOSRVCLI_DEFAULT_WORKSPACE=dev_workspace
export GEOSRVCLI_PASSWORD=dev_password
PATH_add ./bin

Then:

1
direnv allow

Validate Before Deploy#

Always validate configuration before production use:

1
2
3
4
5
6
7
8
# Validate config file
./geoserver-cli config validate --config prod

# Show resolved configuration
./geoserver-cli config show --config prod --redact

# Test connection
./geoserver-cli workspace list --config prod

Publishing Workflows#

Use Dry Run First#

Preview changes before executing:

1
2
3
4
5
# See what would be published
./geoserver-cli publish postgis --all -w prod --dry-run

# Review output, then execute
./geoserver-cli publish postgis --all -w prod

Publish in Stages#

For production, break publishing into stages:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash
# Stage 1: Create workspace
./geoserver-cli workspace create production

# Stage 2: Publish core layers
./geoserver-cli publish postgis --layers roads,buildings -w production

# Stage 3: Apply styles
./geoserver-cli style create road_style --sld @styles/road.sld
./geoserver-cli layer update roads --default-style road_style

# Stage 4: Enable and advertise
./geoserver-cli layer update roads --enabled true --advertised true

Use Filters for Bulk Publishing#

Instead of publishing everything, use filters:

1
2
3
4
# Publish only production tables
./geoserver-cli publish postgis --all -w prod \
  --include "^prod_" \
  --exclude "_staging$"

Leverage Concurrency Wisely#

Use concurrency but don’t overwhelm the server:

1
2
3
4
5
# Good: Moderate concurrency
./geoserver-cli publish postgis --all -w prod --concurrency 4

# Bad: Too much concurrency may overwhelm server
./geoserver-cli publish postgis --all -w prod --concurrency 32

Handle Failures Gracefully#

Use idempotent commands and error handling:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash
set -e

# Idempotent: Skip existing layers
./geoserver-cli publish postgis --all -w prod || {
  echo "Publishing failed. Check logs."
  exit 1
}

# Continue even if some operations fail
./geoserver-cli layer update roads --enabled true || echo "Failed to update roads"

Workspace Organization#

Use Meaningful Workspace Names#

Choose descriptive, environment-specific names:

1
2
3
4
5
6
7
8
# Good
./geoserver-cli workspace create production
./geoserver-cli workspace create staging_v2
./geoserver-cli workspace create dev_john

# Bad
./geoserver-cli workspace create ws1
./geoserver-cli workspace create test

Set Default Workspace#

Set a default to avoid repetition:

1
2
3
4
5
6
# In .envrc or environment
export GEOSRVCLI_DEFAULT_WORKSPACE=production

# Now all commands use this workspace
./geoserver-cli store list
./geoserver-cli publish postgis --all

Keep Workspaces Focused#

Group related layers in the same workspace:

1
2
3
4
5
6
7
# By dataset
./geoserver-cli workspace create osm_data
./geoserver-cli workspace create census_data

# By environment
./geoserver-cli workspace create prod_layers
./geoserver-cli workspace create test_layers

Style Management#

Version Control Your SLD Files#

Keep styles in version control:

1
2
3
4
styles/
├── roads.sld
├── buildings.sld
└── water.sld

Deploy them consistently:

1
2
3
4
5
for style in styles/*.sld; do
  name=$(basename "$style" .sld)
  ./geoserver-cli style create "$name" --sld "@$style" || \
    ./geoserver-cli style update "$name" --sld "@$style"
done

Use Descriptive Style Names#

Choose clear, meaningful names:

1
2
3
4
5
6
7
# Good
./geoserver-cli style create road_primary --sld @road_primary.sld
./geoserver-cli style create building_residential --sld @building_residential.sld

# Bad
./geoserver-cli style create style1 --sld @s1.sld
./geoserver-cli style create temp --sld @temp.sld

Separate Concerns#

Create focused styles for specific purposes:

1
2
3
4
5
6
# Base styles
./geoserver-cli style create road_base --sld @road_base.sld

# Themed styles
./geoserver-cli style create road_winter --sld @road_winter.sld
./geoserver-cli style create road_summer --sld @road_summer.sld

Security#

Use Read-Only Credentials#

For read-only operations, use limited credentials:

1
2
3
4
# config for monitoring/reporting
[geoserver]
username = "readonly_user"
password = "readonly_password"

Restrict Config File Permissions#

Protect configuration files:

1
2
3
4
5
6
# Make config readable only by owner
chmod 600 configs/prod.config.toml

# Verify
ls -la configs/prod.config.toml
# Should show: -rw------- (600)

Never Log Passwords#

When debugging, redact sensitive information:

1
2
3
4
5
# Good: Redacted output
./geoserver-cli config show --redact

# Bad: Shows passwords
./geoserver-cli config show

Use HTTPS in Production#

Always use HTTPS for production:

1
2
[geoserver]
base_url = "https://geoserver.example.com/rest"  # HTTPS

Performance#

Optimize Bulk Operations#

Use appropriate concurrency:

1
2
3
4
5
6
# CPU-bound: Use CPU core count
CORES=$(nproc)
./geoserver-cli publish postgis --all -w prod --concurrency $CORES

# Network-bound: Use higher concurrency
./geoserver-cli publish postgis --all -w prod --concurrency 16

Adjust Timeouts#

Set appropriate timeouts for your operations:

1
2
3
4
5
# Quick operations: Short timeout
./geoserver-cli workspace list --timeout 10s

# Bulk publishing: Long timeout
./geoserver-cli publish postgis --all -w prod --timeout 300s

Monitor GeoServer#

Keep an eye on GeoServer resources:

1
2
3
4
5
# Check GeoServer status
curl http://localhost:8080/geoserver/rest/about/status.json

# Watch during bulk operations
watch -n 5 'curl -s http://localhost:8080/geoserver/rest/about/status.json | jq .metrics.memory'

Automation and CI/CD#

Use Declarative Configs#

Store desired state in code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# geoserver-config.yaml
workspaces:
  - production
  - staging

datastores:
  production:
    - name: postgis
      type: postgis
      connection: ${POSTGIS_PROD_URL}

layers:
  production:
    - roads
    - buildings
    - water

Implement Health Checks#

Verify deployments:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash
# health-check.sh

# Check workspace exists
./geoserver-cli workspace get production || exit 1

# Check critical layers
for layer in roads buildings water; do
  # Verify layer is enabled and advertised
  ./geoserver-cli layer update "$layer" | grep -q "Enabled: true" || exit 1
done

echo "Health check passed"

Use Rollback Strategies#

Plan for rollback:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#!/bin/bash
# deploy-with-rollback.sh

# Backup current state
BACKUP_DIR="backups/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"

# Store workspace list
./geoserver-cli workspace list > "$BACKUP_DIR/workspaces.txt"

# Deploy
if ! ./geoserver-cli publish postgis --all -w prod; then
  echo "Deployment failed. Rollback instructions:"
  echo "1. Check $BACKUP_DIR for previous state"
  echo "2. Manually restore via GeoServer UI"
  exit 1
fi

Log Everything#

Maintain audit logs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
# publish-with-logging.sh

LOG_FILE="logs/publish-$(date +%Y%m%d_%H%M%S).log"
mkdir -p logs

{
  echo "=== Publish started at $(date) ==="
  echo "User: $(whoami)"
  echo "Config: $GEOSRVCLI_CONFIG"
  echo ""
  
  ./geoserver-cli publish postgis --all -w prod 2>&1
  
  EXIT_CODE=$?
  echo ""
  echo "=== Publish finished at $(date) with exit code $EXIT_CODE ==="
} | tee "$LOG_FILE"

exit $EXIT_CODE

Testing#

Test in Lower Environments First#

Never test in production:

1
2
3
4
5
6
7
8
# 1. Test in dev
./geoserver-cli publish postgis --all -w dev --config dev

# 2. Test in staging
./geoserver-cli publish postgis --all -w staging --config staging

# 3. Deploy to production
./geoserver-cli publish postgis --all -w prod --config prod

Use Dry Run for Testing#

Preview operations without changes:

1
2
3
4
5
# Test publish without actually publishing
./geoserver-cli publish postgis --all -w prod --dry-run

# Verify configuration
./geoserver-cli config show --config prod --redact

Automate Testing#

Include CLI in your test suite:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash
# test-integration.sh

# Start test GeoServer (docker)
docker-compose up -d geoserver-test

# Wait for startup
sleep 30

# Run integration tests
./geoserver-cli workspace create test --config test
./geoserver-cli publish postgis --layer test_table -w test --config test

# Cleanup
docker-compose down

Maintenance#

Regular Configuration Audits#

Periodically review configurations:

1
2
3
4
5
# Check all configs
for config in configs/*.config.toml; do
  echo "Validating $config"
  ./geoserver-cli config validate --config "$(basename $config .config.toml)"
done

Keep CLI Updated#

Update the CLI regularly:

1
2
3
4
5
6
7
8
# Pull latest
git pull

# Rebuild
go build -o geoserver-cli ./cmd/geoserver-cli

# Verify
./geoserver-cli version

Document Your Workflows#

Keep README files for custom workflows:

1
2
3
4
5
6
# Production Deployment

1. Validate config: `./geoserver-cli config validate --config prod`
2. Dry run: `./geoserver-cli publish postgis --all -w prod --dry-run`
3. Deploy: `./scripts/deploy-prod.sh`
4. Verify: `./scripts/health-check.sh`

Summary#

Key Takeaways:

  • ✅ Use environment-specific configs
  • ✅ Never commit passwords
  • ✅ Always dry-run in production
  • ✅ Use appropriate concurrency
  • ✅ Test in lower environments first
  • ✅ Log and audit all operations
  • ✅ Keep styles in version control
  • ✅ Implement health checks
  • ✅ Plan for rollback
  • ✅ Document your workflows