kartoza/docker-geoserver: a packaging recipe for GeoServer with PostGIS
A docker recipe for GeoServer
At a glance
- What is it?
- The kartoza/docker-geoserver repository is a Dockerfile and a set of compose files that turn GeoServer into a configurable container with a PostgreSQL backend. It suits teams that want a repeatable GeoServer deployment, but the repository is a packaging layer, and GeoServer itself remains the product you operate.
- Who is it for?
- Adopt kartoza/docker-geoserver if you want GeoServer and PostGIS to come up from a known compose file with the plugin set already baked in, and do not adopt it if you need custom extensions, upgrade paths, or tuning guidance that the project does not carry. Before anything else, pull the tagged 3.0.1 image, replace the default credentials held in the .env file, and confirm that the plugin lists under build_data match the extensions you actually license and use.
- Can I use it commercially?
- Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A three stage build that fetches plugins before the runtime image exists
The repository lists a Dockerfile, Advanced-Configuration.md, Developer-Guidelines.md, compose, clustering, scenario_tests, build_data, scripts and resources at the top level, which tells you this is a build and packaging project rather than an application. The Dockerfile visible here works in stages. The first stage is based on ghcr.io/osgeo/gdal:ubuntu-full with GDAL_VERSION pinned to 3.8.4, and the Java base is 11.0.23-jdk21-temurin-noble with JAVA_HOME at /opt/java/openjdk. A separate stage uses python:alpine3.20 as the plugin downloader.
That downloader stage exists for a stated networking reason. The build comments say it pulls plugin lists from build_data/{required,stable,community}_plugins.txt and builds a curl configuration file so the downloads reuse a single HTTPS connection rather than opening a new one per URL. The author estimates that per-URL calls cost at least three network round trips before the request is even sent, and the separate stage lets buildx run this work in parallel with the rest of the build. The comment claims caching saves roughly 460 MiB of downloads when the plugin set does not change. Because plugin archives are architecture neutral, the stage runs on $BUILDPLATFORM while the rest of the image is built for the target architecture.
The version knobs are build arguments rather than runtime configuration. GS_VERSION defaults to 3.0.1, GS_VERSION_COMMUNITY can point at a different community build, and the WAR itself is fetched from a SourceForge URL for that same 3.0.1 release. LIMIT_EXT_DOWNLOAD is set to false, which is the switch to look at first when you want a leaner image.
Pulling a tagged image instead of building one locally
Two routes exist: pull the published image from Docker Hub, or build the Dockerfile yourself against the Developer Guidelines. For most teams the pull path is faster, and the getting started notes recommend tagged versions for stability.
This is the whole pull sequence:
VERSION=3.0.1
docker pull kartoza/geoserver:$VERSIONAfter it completes you should have a local image named kartoza/geoserver tagged 3.0.1. Using a tag rather than latest matters here because the release tags in this repository are dated and versioned, for example v3.0.1--2026.10.04--50b1796, so a tag records both the GeoServer release and the packaging revision. The published image name uses the shorter form kartoza/geoserver:$VERSION, which means the date and commit suffix are not part of the tag you pull.
Building locally is the alternative path, and the overview points at Developer-Guidelines.md rather than giving the commands here. Expect that route to matter if you need a different plugin set, a different GDAL base, or an arm64 build, since the build arguments exist for exactly those cases. The repository also carries an upgrade_geoserver_version.sh script and a build_data directory, which is where version bumps are handled.
Starting GeoServer and PostGIS from the compose directory
The compose directory holds a sample docker-compose.yml illustrating a GeoServer plus PostGIS pairing. The documented sequence is short. Move into the directory that holds the compose files:
cd composeThen bring the services up in the background:
docker-compose up -dWhat you should see afterwards is the GeoServer landing page on port 8600, reachable at http://localhost:8600/geoserver. The port mapping matters: the container listens on the standard GeoServer port 8080, and the sample configuration publishes it as 8600 on the host.
The database side is PostGIS, specifically the kartoza/postgis image, and the overview is explicit that you can substitute any other PostgreSQL image as long as you adjust the environment variables to match. That flexibility is real but manual. There is no documented contract listing which variables must exist and what values they need, so swapping the database backend means reading the image's environment handling yourself.
The database credentials and the GeoServer admin credentials live in the .env file, and the same notes warn that the default login credentials stored there should be changed to something more secure before the stack is exposed to anyone. Editing .env is part of the install, not an optional hardening step.
A one command start for a minimum instance
For a quick look, or for a single container without the database layer, the command line section gives a minimum example that sets the admin password and user as environment variables at run time:
GS_VERSION=3.0.1
docker run -d -p 8600:8080 --name geoserver -e GEOSERVER_ADMIN_PASSWORD=myawesomegeoserver -e GEOSERVER_ADMIN_USER=admin kartoza/geoserver:${GS_VERSION}The container runs detached, the host port 8600 maps to 8080, and the container is named geoserver so it can be addressed later by name. The two environment variables are the entire configuration surface for a first run, and the landing page is again at http://localhost:8600/geoserver.
Note that this minimum instance does not attach a PostgreSQL backend, so the default GeoServer data directory configuration applies. If your data lives in PostGIS, the compose route is the one the project intends. Also note the password is passed on the command line, where it is visible to anyone who can read the process list on the host. The compose and .env route exists partly because of that.
Two environment variables are not a full configuration surface. The overview points to Advanced-Configuration.md for larger deployments, which is where the production style settings referenced by the GeoServer running-in-production guidance would be covered.
Where the support boundary sits between this repository and GeoServer upstream
This project draws an explicit line around its own scope. The project states that the repository focuses on the orchestration and packaging of GeoServer, and that issues specifically related to running the Docker image or its configuration belong here. Anything about GeoServer itself is not the maintainers' problem, and the support section points at the GeoServer issue tracker for that, with paid support from the GeoServer developers offered for urgent upstream problems.
That division has practical consequences for anyone adopting the image. Extension behaviour is upstream territory. The support section specifically asks reporters dealing with installed extensions, community or stable, to check upstream reports first, because the maintainers rely on the GeoServer developers and community for support. Before filing anything here, the project asks you to verify whether the problem originates in GeoServer or in this packaging, by testing with newer or older versions.
Contribution follows a develop branch workflow. Pull requests go against develop so they can be reviewed and tested before merging to master, all existing unit tests must pass, and new features or modifications should include accompanying unit tests where applicable. The presence of scenario_tests in the repository layout is consistent with that expectation. A clustered deployment is a separate concern handled under the clustering directory.
Where a packaging layer stops being enough
Several common needs fall outside what this repository takes on. Extension installation at runtime is not documented here; the plugin lists are baked in at build time from build_data, so adding an extension means rebuilding the image or consulting the Advanced Configuration guide. Upgrading GeoServer is handled by upgrade_geoserver_version.sh, but the README gives no rollback procedure and no guidance on how to migrate a data directory between versions.
There is also no performance or sizing guidance. Nothing in the repository states a heap size, a JVM flag set, a connection pool limit or a recommended instance count, so capacity planning has to come from elsewhere. The clustering directory hints at more than one node, but the overview does not explain it, and stating more would be guesswork.
Licence and upgrade cost deserve attention. The repository carries GPL-2.0, which is the licence for the packaging and the scripts here, while GeoServer itself and its extensions sit under their own terms, including the paid and community extension split the support section refers to. Anyone consolidating licence obligations for a commercial deployment needs to treat those as separate items. On maintenance, the project is not archived, and the last push was on 2026-10-06, with three tagged releases in the preceding two months: v3.0.1--2026.10.04--50b1796, v3.0.1--2026.09.04--9f7f424 and v3.0.1--2026.08.30--43a530a. Each release tag records the packaging revision, so a rollback target is identifiable.
Two ways to run GeoServer, and why the recipe matters
The obvious alternative is running GeoServer from its own distribution and installing it against a database yourself. The difference in approach is that this project pre-resolves the parts that are tedious to get right repeatedly: the plugin archive set, the GDAL base layer, the Java runtime, the PostGIS pairing and the port mapping, all captured in a Dockerfile and a compose file that can be committed next to your own code.
The overview also names its own ancestor: a simple container that runs GeoServer influenced by the docker recipe published by Eliot Jordan, and the build extends that with the multi stage plugin downloader described earlier. Build locally instead of pulling if you need a different plugin set, and the same recipe becomes the base for your own image rather than a black box dependency.
The trade-off sits in the other direction. A recipe this opinionated is a maintained artefact. The release cadence visible in the tags means you take versions from someone else's schedule, and when the upstream GeoServer release changes, the matching plugin and WAR URLs have to be updated by this repository's maintainers before you get a working image. If your requirement is to track upstream GeoServer closely, this project adds a layer of waiting that a direct install does not.
Editorial conclusion
Adopt kartoza/docker-geoserver if you want GeoServer and PostGIS to come up from a known compose file with the plugin set already baked in, and do not adopt it if you need custom extensions, upgrade paths, or tuning guidance that the project does not carry. Before anything else, pull the tagged 3.0.1 image, replace the default credentials held in the .env file, and confirm that the plugin lists under build_data match the extensions you actually license and use.
Frequently asked questions
How do I install kartoza/docker-geoserver and start it for the first time?
Pull the tagged image with docker pull kartoza/geoserver:3.0.1, or bring up the sample stack from the compose directory with docker-compose up -d after editing the .env file. The GeoServer landing page is then at http://localhost:8600/geoserver.
Does the kartoza/docker-geoserver image include a PostGIS database?
The compose sample pairs GeoServer with the kartoza/postgis image as the backend. The overview says you can use any other PostgreSQL image if you adjust the environment variables accordingly.
How are extensions added to the kartoza/docker-geoserver image?
Plugin lists are read from build_data during the build, with separate required, stable and community lists, so the extension set is fixed when the image is built. The project does not document a runtime extension install path, and points to Advanced-Configuration.md for advanced setup.
What are the default GeoServer login credentials for the kartoza/docker-geoserver image?
The default login credentials are stored in the .env file in the compose setup, and the notes say they should be updated to something more secure. When running with docker run directly, the admin user and password are supplied through GEOSERVER_ADMIN_USER and GEOSERVER_ADMIN_PASSWORD.
How do I report a problem with the kartoza/docker-geoserver image?
The repository handles orchestration and packaging issues, while GeoServer itself is covered by the upstream GeoServer issue tracker. For extension related problems the project asks you to check upstream reports first and to test with newer or older versions before filing an issue here.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kartoza-docker-geoserver)Was this useful?