---
title: "Deploy GeoServer | (Just Updated) WMS WFS Map Server with PostGIS, Admin Password Preset, Data Survives Redeploys"
description: "GeoServer WMS/WFS/WMTS map server with a PostGIS spatial database"
category: "Other"
url: https://railway.com/deploy/geoserver-or-just-updated-wms-wfs-map-se
---

# Deploy GeoServer | (Just Updated) WMS WFS Map Server with PostGIS, Admin Password Preset, Data Survives Redeploys

GeoServer WMS/WFS/WMTS map server with a PostGIS spatial database

**[Deploy GeoServer | (Just Updated) WMS WFS Map Server with PostGIS, Admin Password Preset, Data Survives Redeploys on Railway](https://railway.com/template/geoserver-or-just-updated-wms-wfs-map-se)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/geoserver-or-just-updated-wms-wfs-map-se/manifest.json

- **Creator:** SuperSlowSloth
- **Category:** Other

## Template content

### postgis

- **Image:** ghcr.io/bon5co/postgis-railway:18-3.6@sha256:f4ba5d567abbb7b7c7ddd6f1baa34578c86cb09307941e7f08ff6ec0f3a69809

### geoserver

- **Image:** kartoza/geoserver:3.0.2@sha256:7b0dd1685716be9867c96d1cbe82e6ad8697206892cc605d27e3a353aea7dc55
- **Start command:** `/bin/sh -c 'export GEOSERVER_ADMIN_USER=${GEOSERVER_ADMIN_USER:-admin} INITIAL_MEMORY=${INITIAL_MEMORY:-512M} MAXIMUM_MEMORY=${MAXIMUM_MEMORY:-1G} ACTIVATE_PROXY_HEADERS=true PROXY_BASE_URL_HEADER=true; exec /bin/bash /scripts/entrypoint.sh'`
- **Health check:** /geoserver/wms
- **Public domain:** Yes

## Documentation

# Deploy and Host GeoServer on Railway

**Built for an LLM agent to deploy and use.** There is no setup form and nothing to fill in: the admin password is generated at deploy time, a PostGIS database is wired in on the private network, and the contract below lists every address, variable name and one script that proves the REST API, the database link and the WMS service work.

GeoServer is the open source Java server for publishing geospatial data as web services. It serves maps over OGC WMS, WMTS and WCS and vector features over WFS, reads PostGIS, GeoTIFF, shapefiles and GeoPackage, and has a web admin UI and a full REST API for configuration.

## About Hosting GeoServer

This template runs two services. `geoserver` is the `kartoza/geoserver` 3.0.2 image (GeoServer 3.0.2 on Tomcat), pinned by digest, with its data directory on a volume at `/opt/geoserver/data_dir`. `postgis` is PostgreSQL 18 with PostGIS 3.6 on its own volume, reachable only on Railway's private network. Layers, styles, workspaces, stores and the admin password all live in the volume, so they survive redeploys.

The admin user is `admin`. Its password comes from `GEOSERVER_ADMIN_PASSWORD`, generated per deploy; the image applies it on every boot, so changing the variable and redeploying changes the password. Proxy headers are on, so the capabilities documents and the admin UI advertise the `https://` address Railway serves. The JVM heap starts at 512 MB and tops out at 1 GB (`INITIAL_MEMORY` and `MAXIMUM_MEMORY` on the `geoserver` service raise it); the service measured about 750 MB resident when idle, so plan for at least 1 GB of memory.

### Agent contract

- Public URL: `GEOSERVER_PUBLIC_URL` (`https://` plus the service's `RAILWAY_PUBLIC_DOMAIN` plus `/geoserver`). The admin UI is at `/web/` under it.
- Private URL: `http://geoserver.railway.internal:8080/geoserver`, exposed as `GEOSERVER_PRIVATE_URL`.
- Credentials: user `admin`, password in `GEOSERVER_ADMIN_PASSWORD`. The database link uses `POSTGIS_HOST` and `POSTGIS_PASSWORD` (user `postgres`, database `railway`, port 5432, private network only).
- Auth: HTTP basic on `/rest/*`; anonymous REST calls get `401`. OGC services (`/wms`, `/wfs`, `/ows`) are open for published layers.
- Health: `GET /geoserver/wms` returns 200 without credentials.
- API: REST under `/geoserver/rest/` (workspaces, datastores, layers, styles); OGC under `/geoserver/WORKSPACE/wms`, `/wfs`, `/wcs`.

```bash
# run with GEOSERVER_PUBLIC_URL, GEOSERVER_ADMIN_PASSWORD, POSTGIS_HOST and POSTGIS_PASSWORD set
AUTH="admin:$GEOSERVER_ADMIN_PASSWORD"
W="agent$(date +%s)"
curl -s -o /dev/null -w "health: %{http_code}\n" "$GEOSERVER_PUBLIC_URL/wms"
curl -s -o /dev/null -w "anonymous rest: %{http_code}\n" "$GEOSERVER_PUBLIC_URL/rest/workspaces.json"
curl -s -o /dev/null -w "workspace: %{http_code}\n" -u "$AUTH" -H "Content-Type: application/json" \
  -d "{\"workspace\":{\"name\":\"$W\"}}" "$GEOSERVER_PUBLIC_URL/rest/workspaces"
curl -s -o /dev/null -w "postgis store: %{http_code}\n" -u "$AUTH" -H "Content-Type: application/json" \
  -d "{\"dataStore\":{\"name\":\"pg\",\"connectionParameters\":{\"entry\":[{\"@key\":\"dbtype\",\"\$\":\"postgis\"},{\"@key\":\"host\",\"\$\":\"$POSTGIS_HOST\"},{\"@key\":\"port\",\"\$\":\"5432\"},{\"@key\":\"database\",\"\$\":\"railway\"},{\"@key\":\"schema\",\"\$\":\"public\"},{\"@key\":\"user\",\"\$\":\"postgres\"},{\"@key\":\"passwd\",\"\$\":\"$POSTGIS_PASSWORD\"}]}}}" \
  "$GEOSERVER_PUBLIC_URL/rest/workspaces/$W/datastores"
curl -s -o /dev/null -w "postgis reachable: %{http_code}\n" -u "$AUTH" "$GEOSERVER_PUBLIC_URL/rest/workspaces/$W/datastores/pg/featuretypes.json?list=available"
echo "capabilities: $(curl -s -G --data-urlencode service=WMS --data-urlencode version=1.3.0 --data-urlencode request=GetCapabilities "$GEOSERVER_PUBLIC_URL/$W/wms" | grep -m1 -o WMS_Capabilities)"
```

A fresh deploy prints `health: 200`, `anonymous rest: 401`, `workspace: 201`, `postgis store: 201`, `postgis reachable: 200` and `capabilities: WMS_Capabilities`.

## Why Deploy GeoServer on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying GeoServer on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.

- **Agent-ready** - generated admin password, contract block and one working script; no setup form.
- **PostGIS included** - a spatial database next to GeoServer on the private network, not exposed to the internet.
- **State survives redeploys** - the data directory and the database each sit on a volume.
- **Credentials from variables** - the admin password is applied from the environment on every boot.
- **Correct public URLs** - proxy headers are on, so capabilities documents point at your HTTPS domain, not an internal address.

## Common Use Cases

- **Web maps for a front end** - serve WMS or WMTS tiles to Leaflet, OpenLayers or MapLibre.
- **Spatial APIs for agents and apps** - publish PostGIS tables as WFS features and query them over HTTP.
- **A shared map server for a team** - publish shapefiles, GeoTIFFs and GeoPackages with styles managed in the admin UI.

## Dependencies for GeoServer Hosting

- PostgreSQL 18 with PostGIS 3.6 and one Railway volume, created by the template.
- One Railway volume for the GeoServer data directory, created by the template.

### Deployment Dependencies

- [GeoServer](https://geoserver.org/)
- [GeoServer documentation](https://docs.geoserver.org/)
- [Kartoza docker-geoserver](https://github.com/kartoza/docker-geoserver)
- [PostGIS wrapper image](https://github.com/bon5co/postgis-railway)

### Implementation Details

| Variable | Purpose |
| --- | --- |
| `GEOSERVER_ADMIN_PASSWORD` | Password of the `admin` user, generated per deploy. |
| `GEOSERVER_PUBLIC_URL` | HTTPS address for clients outside Railway. |
| `GEOSERVER_PRIVATE_URL` | Address on the private network, for services in the same project. |
| `CSRF_WHITELIST` | Public domain allowed to post to the admin UI behind Railway's proxy. |
| `POSTGIS_HOST` | Private hostname of the `postgis` service. |
| `POSTGIS_PASSWORD` | Password of the `postgres` user in the database, generated per deploy. |

The start command sets the admin user, the heap sizes and the proxy-header switches, then runs the image's own entrypoint. GeoServer is not wired to PostGIS automatically because a store needs a workspace of your choosing; the contract script shows the REST call that creates one.


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/geoserver-or-just-updated-wms-wfs-map-se
