# worklenz: five containers pulled from one personal namespace

> An AGPL project management tool with task, time tracking, analytics, and resource management, deployed as five containers behind nginx. The compose file is where the interesting decisions live, including one that quietly disables Google sign-in by default.

**Worklenz/worklenz** — All in one project management tool for efficient teams

- Repository: https://github.com/Worklenz/worklenz
- Website: https://worklenz.com
- Stars: 3,212 · Forks: 376
- Language: TypeScript
- License: AGPL-3.0
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/worklenz-worklenz

## Compose pulls images rather than building the repository

The deployment story is a compose file with five services, and the first thing to notice is that none of them build from this repository. The frontend, the backend, and a third application called the client portal all reference published images in a single personal container namespace, each on a floating latest tag. Two infrastructure services complete the set: nginx in front of everything, and MinIO as the object store. That matters because the quick start is one command, and that command downloads rather than compiles. Anyone who edits the TypeScript source locally and then runs the same command will see their change ignored. It also means the compose file cannot tell you anything about the current state of the source tree, since the images are built and pushed outside it.

## Google sign-in ships disabled as a literal string

The backend service carries four explicit environment entries that are worth reading closely. Two of them, the client identifier and the client secret, default to the word disabled, and a comment above them explains why: it lets the published image start when Google authentication is not configured. The effect is that the container boots and runs with social sign-in silently off rather than crashing on a missing variable, which is a reasonable trade for a quick start and a bad default for anything real. The fourth entry is the callback URL, which defaults to a localhost path ending in the verification endpoint, so anyone enabling Google authentication has to override it or the provider will refuse the redirect. The other two entries point the application at its database service by name rather than by address.

## The SQL setup order is not the file numbering

The manual installation path asks you to create a database and then run a list of SQL files in what it calls the correct order. That order is not the numeric order of the files. Extensions load first, then tables, then indexes, then functions, then triggers, then views, and finally the data manipulation scripts, which are numbered two and run last. Functions must exist before the triggers that call them, and the data must exist before the views that read it, so the sequence is forced by dependency rather than by version.

```bash
psql -U your_username -d worklenz_db -f database/sql/0_extensions.sql
psql -U your_username -d worklenz_db -f database/sql/1_tables.sql
psql -U your_username -d worklenz_db -f database/sql/indexes.sql
psql -U your_username -d worklenz_db -f database/sql/4_functions.sql
psql -U your_username -d worklenz_db -f database/sql/triggers.sql
psql -U your_username -d worklenz_db -f database/sql/3_views.sql
psql -U your_username -d worklenz_db -f database/sql/2_dml.sql
```

Two smaller warnings apply to anyone following that path. You need Node 18 or newer, PostgreSQL 15 or newer, and an S3-compatible store such as MinIO or Azure Blob Storage, so the manual route is not dependency-free the way the container route is. And the final command in that step is cut off mid-line in the documentation.

## Two deployment modes decided by one variable

The example environment file opens with the decision that shapes everything else. One variable selects the deployment mode, and it has two values. The bundled mode, which is the default and the one recommended for most users, starts everything, including the database, a cache, and the object store. The advanced mode expects you to supply those yourself, naming cloud object storage and an external PostgreSQL as the intended targets. Below that sit the URL variables, and they are not interchangeable. The domain variable is what the application calls itself. One URL variable is what the front end uses to reach the API, another is the socket endpoint for real-time features, and a third is what the back end uses for cross-origin checks and redirects, so all three have to agree. The cross-origin setting ships as a wildcard with a comment telling you to narrow it in production.

## nginx terminates TLS and mounts its configuration read-only

The reverse proxy publishes both HTTP and HTTPS ports and depends on the front end and the back end, so it starts last. Its three mounts are all read-only, which is a small correctness detail: the server configuration file, a directory of additional configuration, and a directory for certificates are mounted with no write permission, so a compromised process inside the container cannot rewrite how traffic is routed. Those certificate files are what the deployment script prepares. To point the stack at a server, you run a script in the repository with the hostname, and pass a second argument to switch the generated configuration from plain HTTP and WebSocket to their secure forms. Then a pull and an up brings the new images in. Two video walkthroughs are linked, one for the local container path and one for the remote path.

## The object store console is documented with default credentials

MinIO is part of the standard stack rather than an add-on, and it is published on two ports: one for the service itself and one for its console. The quick start gives the console address and the default username and password, which are the well-known pair that ships with the product and are therefore not credentials you want exposed. Because nginx sits in front of the stack, the question of which of those ports is reachable from outside is a deployment decision rather than a default, and the documentation is clear about the addresses used for local testing only. The configuration section also notes that storage can point at Azure Blob Storage instead, which is the same setting the advanced deployment mode expects you to have already provisioned.

## Three application directories and four extra documents

The repository holds three application directories rather than two: a back end, a front end, and a client portal, the last of which is the service on port 5174 in the compose file that the quick start's port list never mentions. Around them sit four shell entry points for the same operations in different forms, including batch files for Windows alongside the shell scripts, plus a backup script, a management script, a quick setup script, and the environment update script described earlier. Documentation is unusually distributed: beside the readme there is a design document, a Docker setup guide, a project setup guide, and a deployment verification checklist that reads like a release gate rather than a tutorial. The licence is AGPL 3.0, and the release history shows a major version jump in late August followed by a minor one in late September, with a patch release from February preceding both.

## Conclusion

Worklenz suits a team that wants task management, time tracking, and reporting in one self-hosted place and is comfortable running five containers. Two things to check before you rely on it. The compose file pulls published images rather than building this repository, so a local change to the source has no effect until you build and push, which is a different mental model from most self-hosted projects. And the example configuration ships with a permissive cross-origin setting, which belongs in development rather than on a public deployment.

## FAQ

### What is Worklenz?

An open source project management tool for teams, licensed under AGPL 3.0. It covers project planning, task management with due dates and priorities, file sharing and comments, time tracking for resource allocation and billing, and reporting on project status and team workload.

### How do I run Worklenz locally?

Clone the repository and run docker-compose up -d. The front end is then on port 5000, the back end API on port 3000, and the MinIO console on port 9001 with the default MinIO credentials. There are also start scripts for Windows and for Linux and macOS if you prefer them.

### Does Worklenz build its own Docker images?

No. The compose file pulls published frontend, back end, and client portal images from a single container namespace on floating latest tags, so the quick start downloads rather than compiles. The build path is the manual one, which needs Node 18 or newer, PostgreSQL 15 or newer, and an S3-compatible store.

### How do I configure storage and deployment mode in Worklenz?

One environment variable chooses between a bundled mode that starts the database, cache, and object store, and an advanced mode that expects external services such as cloud object storage and an external PostgreSQL. You then set the domain, the API and socket URLs the front end uses, the front end URL the back end uses for cross-origin checks, and the cross-origin settings themselves.

## Sources

- [Issues](https://github.com/Worklenz/worklenz/issues)
- [Project website](https://worklenz.com)
- [README](https://github.com/Worklenz/worklenz/blob/main/README.md)
- [Releases](https://github.com/Worklenz/worklenz/releases)
- [Worklenz/worklenz on GitHub](https://github.com/Worklenz/worklenz)

---

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