jngkadocs
Install & configure / Install with Docker Compose

Install with Docker Compose

Jangka ships as one Docker image, iqbalr3000/jangka, and needs Postgres 18. The release compose file runs both on one host. This page explains what's in it and how to run it on a server. To get a trial running quickly, see Quick start.

The compose file

Download it into its own directory:

terminalsh
mkdir jangka && cd jangka
curl -fsSL https://raw.githubusercontent.com/iqbalr3000/jangka/v1.0.0-rc.1/docker/docker-compose.yml -o docker-compose.yml

This is the whole file:

docker-compose.ymlyaml
name: jangka

services:
  postgres:
    image: postgres:18
    environment:
      POSTGRES_USER: jangka
      POSTGRES_PASSWORD: jangka
      POSTGRES_DB: jangka
    volumes:
      # PG18 stores data in /var/lib/postgresql/18/docker; mounting .../data would not persist.
      - pgdata:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U jangka -d jangka"]
      interval: 5s
      timeout: 3s
      retries: 10

  app:
    image: iqbalr3000/jangka:${JANGKA_VERSION:-latest}
    # The setup wizard tells admins to run `docker logs jangka`.
    container_name: jangka
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DATABASE_URL: postgres://jangka:jangka@postgres:5432/jangka
      MASTER_KEY: ${MASTER_KEY:?set MASTER_KEY (openssl rand -base64 32)}
      PUBLIC_URL: ${PUBLIC_URL:-http://localhost:3000}
    ports:
      - "3000:3000"

volumes:
  pgdata:
PartWhat it does
postgresPostgres 18. It isn't published on a host port, so only the app can reach it. That's why a fixed password is acceptable here.
pgdataNamed volume with all database data. It survives docker compose down and image upgrades.
appJangka, at the version set in JANGKA_VERSION. It runs database migrations on start, then serves the web app and API on port 3000.
container_name: jangkaA fixed name, so docker logs jangka works. The setup wizard shows that command.

To use a Postgres server you already run instead of the bundled one, see Use an existing Postgres.

The .env file

Compose reads .env from the same directory and fills in ${MASTER_KEY}, ${PUBLIC_URL} and ${JANGKA_VERSION}. On a server, set all three:

.envsh
MASTER_KEY=generated-with-openssl-rand-base64-32
PUBLIC_URL=https://jangka.example.com
JANGKA_VERSION=1.0.0-rc.1

Pin an exact version. Without JANGKA_VERSION the compose file falls back to latest, which release candidates don't publish, and which would change under you on the next docker compose pull.

Generate the key with openssl rand -base64 32. Without it, docker compose up stops with set MASTER_KEY.

PUBLIC_URL is the address people type into the browser, without a trailing path. Jangka uses it for session cookies, the CSRF origin check and SSO redirect URIs, so it has to match that address exactly.

Other variables, such as LOG_LEVEL or TRUST_PROXY, go under app.environment in the compose file. See the Configuration reference.

Start and check it

terminalsh
docker compose up -d
docker compose ps

The app's image has a health check that calls GET /api/v1/health, which also checks the database. docker compose ps shows the app as healthy once it's serving traffic. The first start takes longer because migrations create the schema.

Change the port

The app listens on port 3000 inside the container. To serve it on another host port, change the left side of the mapping. This keeps it on port 8080, reachable only from the host itself, which suits a reverse proxy on the same machine:

yaml
    ports:
      - "127.0.0.1:8080:3000"

Everyday commands

Run these in the directory that holds docker-compose.yml.

terminalsh
docker compose logs -f app   # follow the app's logs (JSON, one line per event)
docker compose restart app   # restart the app, e.g. after a crash loop is fixed
docker compose up -d         # apply changes to the compose file or .env
docker compose down          # stop and remove the containers; data stays in pgdata