# GeoNode's Docker start needs a generated .env before compose will build

> GeoNode is a Django based content management system for geospatial data that fronts an existing stack of open source GIS projects rather than replacing them. Getting it running locally takes three steps, and the first of them is a Python script that generates the environment file with your passwords, hostname and SSL mode.

**GeoNode/geonode** — GeoNode is an open source platform that facilitates the creation, sharing, and collaborative use of geospatial data.

- Repository: https://github.com/GeoNode/geonode
- Website: https://geonode.org/
- Stars: 1,735 · Forks: 1,202
- Language: Python
- License: NOASSERTION
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/geonode-geonode

## create-envfile.py is the first command, not an afterthought

The Quick Docker Start section begins with a script rather than a compose command:

```bash
python create-envfile.py
```

That ordering matters, because the compose file reads its environment from a file that must exist first: services declare env_file as ${COMPOSE_ENV_FILES:-.env}, so with no override the stack looks for .env in the project root. Running docker compose before generating it leaves you with a stack that has no configuration.

The script's arguments are the real configuration surface, and the password list is longer than most people expect. There are five separate passwords: --geonodepwd for the GeoNode administrator, --geoserverpwd for the GeoServer administrator, --pgpwd for PostgreSQL, --dbpwd for the GeoNode database role, and --geodbpwd for the GeoNode data database role. Two OAuth2 values are also generated when omitted, --clientid and --clientsecret, described as the client id and secret of GeoServer's GeoNode OAuth2 client.

Every password argument leaves a random value behind if you do not supply it. That is convenient and also a trap: you will not know the administrator password later unless the script prints it somewhere you kept, so passing --geonodepwd and --geoserverpwd explicitly is the safer habit for anything you intend to come back to.

--hostname defaults to localhost and sets the URL that will serve GeoNode.

## env_type decides three different deployments

The --env_type argument collapses three deployment profiles into one flag, and it controls both DEBUG and TLS:

- prod disables DEBUG and requests a valid SSL certificate from Let's Encrypt's ACME server
- test disables DEBUG and generates a test SSL certificate for local testing
- dev enables DEBUG and generates no SSL certificate

TLS is off by default and enabled with the separate --https flag, so env_type alone does not turn it on for dev or test. That separation is deliberate: the flag decides whether a certificate exists, the type decides what kind.

The prod path has a prerequisite the documentation calls out explicitly. A real email address and valid SMTP configuration are required when --env_type is prod, because Let's Encrypt uses the email when issuing the certificate. Set --env_type prod without working mail and certificate issuance fails, and the failure will look like a certificate problem rather than a mail problem.

After the file exists, the two compose commands are unremarkable:

```bash
docker compose build
docker compose up -d
```

For a first look without installing anything, the README also points at a hosted demo at development.demo.geonode.org, where registering lets you upload layers, build maps and edit metadata and styles.

## Six containers, one image, two processes

The compose file shows what GeoNode actually is at runtime: an assembly of separate services rather than one application container.

The django and celery services share a single anchor, x-common-django, so they run the same image, geonode/geonode:latest-ubuntu-26.04, with identical volume mounts and the same depends_on conditions on db and redis being healthy. They differ in three ways. The container name is suffixed, the environment sets IS_CELERY to False or True, and the command differs: django runs uwsgi --ini /usr/src/geonode/uwsgi.ini while celery runs the celery-cmd script that the Dockerfile copies to /usr/bin/celery-cmd. Both use entrypoint.sh as their entrypoint, which is where migrations and waiting logic live alongside wait-for-databases.sh.

Health checks are wired rather than assumed. Django is probed with curl against http://django:8000/ with a 60 second start period, and celery with celery -b ${BROKER_URL} inspect ping on a 30 second cycle. Both depend on db and redis reporting healthy first, so a slow database start is absorbed rather than crashing the stack.

nginx sits in front on its own image, geonode/nginx:1.31.6-latest, serving Django's static and media files and proxying onward, published on ${HTTP_PORT} and ${HTTPS_PORT}. It is given RESOLVER=127.0.0.11, Docker's embedded DNS, so it can resolve the service names.

Volumes are named and persistent: statics, geoserver-data-dir, backup-restore, data and tmp. The bind mount of the current directory into /usr/src/geonode is what makes the development environment convenient, since code edits take effect without a rebuild.

## The dependency list is the honest description of the platform

pyproject.toml pins almost everything exactly, which is the correct choice for a deployment platform and terrible for a library, and it tells you what you are agreeing to run. Django 5.2.18, psycopg2, Pillow and lxml are the core, with a long tail of Django applications: django-allauth for accounts, django-guardian for object level permissions, django-mptt and django-treebeard for the two tree structures GeoNode needs, django-taggit, django-tinymce, django-imagekit, django-polymorphic and django-tastypie for the API layer.

Then the non Django parts: celery 5.6.3 and redis 8.1.0 for asynchronous work, oauthlib and pyjwt for token handling, rdflib for RDF metadata, PyMuPDF for PDF processing, defusedxml and zipstream-ng for XML and streaming archives. A further section of pyproject.toml covers geopython dependencies, which is where the GIS specific stack including PostGIS access is pinned.

Python 3.10 or newer is the floor, and the classifier reads Development Status :: 5 - Production/Stable with Framework :: Django and Topic :: Scientific/Engineering :: GIS.

Licensing is where to look carefully. pyproject declares license GPL and setup.py carries the standard GPL header, but the repository is marked as a custom licence rather than an OSI identifier, and the README's licensing paragraph ends after crediting OSGeo, the Open Source Geospatial Foundation. Read LICENSE before deploying.

## Extend through a project template, not by editing core files

The README's advice on customisation is unambiguous: if you plan to customise a GeoNode instance or extend its functionality, it is not advisable to change core files in any case. The recommended mechanism is a GeoNode Project Template from the GeoNode/geonode-project repository.

That is not squeamishness about diffs. The upgrade path matters more. Releases 5.0.2, 5.0.3 and 5.1.0 all landed within months, and a platform that moves frequently punishes local edits at every upgrade. A template keeps your changes in your own repository while GeoNode's core stays replaceable.

The extension story has two layers. Python developers extend it the Django way, and the README notes other open source projects extend GeoNode by tapping into the reusability of Django applications, with a gallery at geonode.org/gallery showing how the community does it. That reuse of Django apps is the actual integration surface: if your data lives in a Django application you already have, GeoNode can adopt it rather than the reverse.

Planning happens through GeoNode Improvement Projects, called GNIPS, documented on the wiki and discussed on the developer mailing list. They are framed as large undertakings adding many features, which is an honest signal about the cost of any single change landing upstream.

## Where GeoNode is the wrong choice

Three cases. If you only need tiles, a WMS, or a spatial query API, GeoNode is enormous: you would be running Django, uwsgi, Celery, Redis, PostgreSQL and GeoServer to serve something a single service does. If your team has no GIS vocabulary, the README says so itself, listing familiarity with web development and general GIS concepts as prerequisites for developing against it. And if you need something outside the catalogue model, the constraint is the data model rather than the code, since datasets, permissions and metadata are tightly integrated.

The alternative is to assemble the parts yourself: PostGIS and GeoServer directly, or GeoServer with a thin application layer for metadata and permissions. You keep the same underlying open source projects the README credits, lose the integrated catalogue, search, commenting and rating, and gain a deployment with a fraction of the moving parts.

The other honest alternative is a hosted instance. For an organisation that needs to publish maps but not operate a platform, a managed or community deployment avoids the whole compose stack, at the cost of control over versions and data residency.

Security reporting is handled by direct contact with a GeoNode Core Developer rather than the public issue tracker, and SECURITY.md sits at the repository root alongside CHANGELOG.md, CONTRIBUTING.md and CLA_INDIVIDUAL.md. The last push was on 2026-10-16, with 5.1.0 released on 2026-08-18.

## Conclusion

Adopt GeoNode when you need to publish and describe geospatial layers with metadata, permissions and a web map editor, because the catalogue, search and permissions machinery is what you would otherwise build around PostGIS and GeoServer. Do not adopt it as a lighter GIS stack when you only need a tile service or a data API, since it brings Django, uwsgi, Celery, Redis and GeoServer with it. Verify first that create-envfile.py has written every password you need, since leaving any of the password arguments empty produces a random value you will not know later.

## FAQ

### How do I start GeoNode with Docker?

Run python create-envfile.py to generate the .env file, then docker compose build and docker compose up -d. The services read configuration from ${COMPOSE_ENV_FILES:-.env}, so the file has to exist first.

### What do the passwords in create-envfile.py do?

There are five separate ones: --geonodepwd for the GeoNode administrator, --geoserverpwd for GeoServer, --pgpwd for PostgreSQL, --dbpwd for the GeoNode database role and --geodbpwd for the GeoNode data database role. Any left empty gets a random value.

### What is the difference between the prod, test and dev env types?

prod disables DEBUG and requests a real certificate from Let's Encrypt, test disables DEBUG and generates a test certificate, and dev enables DEBUG with no certificate. SSL itself is off unless you also pass --https.

### How should I customise a GeoNode instance?

Through a GeoNode Project Template from the GeoNode/geonode-project repository. The README advises against changing core files in any case, so that upgrades stay replaceable.

### Can I try GeoNode before installing it?

Yes. The README points to the official demo at development.demo.geonode.org, where registering gives access to layer uploads, map creation and metadata and style editing.

## Sources

- [GeoNode/geonode on GitHub](https://github.com/GeoNode/geonode)
- [Issues](https://github.com/GeoNode/geonode/issues)
- [Project website](https://geonode.org/)
- [README](https://github.com/GeoNode/geonode/blob/master/README.md)
- [Releases](https://github.com/GeoNode/geonode/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/geonode-geonode
