Install WeCare Resolve Community Edition

This article explains how install WeCare Resolve Community Edition on a server with Docker Compose.

Quick start

  1. Create an empty directory and save the two files from Installation files in it: compose.yaml and .env.

  2. Edit .env:

    • DOMAIN_NAME=localhost:8080 and DOMAIN_PROTOCOL=http
    • APP_MASTER_KEY, POSTGRES_PASSWORD, DATABASE_APP_PASSWORD: each the output of openssl rand -hex 32
    • RESOLVE_BOOTSTRAP_ADMIN_EMAIL and RESOLVE_BOOTSTRAP_ADMIN_PASSWORD: your sign-in as the first administrator
    • RESOLVE_BOOTSTRAP_UNIT_NAME: your organisation’s name
  3. Start it:

    docker compose up -d
    
  4. Once curl -s http://localhost:8080/q/health/ready reports "status": "UP", open http://localhost:8080 and sign in with the email and password from .env.

Advanced installation

Requirements

  • A 64-bit Linux server (x86-64 or ARM64) with at least 1 GB of free memory.

  • Docker Engine 24 or newer with the Compose plugin. Check with:

    docker compose version
    
  • Access from the server to containers.wecaredigital.eu, where Docker downloads the WeCare Resolve image from.

  • A host name for WeCare Resolve, for example resolve.example.com, whose DNS record points at the server or at your reverse proxy.

  • A reverse proxy with a TLS certificate for that host name (see Set up a reverse proxy).

  • Outbound SMTP to your mail server.

  • openssl to generate the secrets (installed on most Linux systems).

Prepare the installation directory

Create a directory for the two files WeCare Resolve needs, for example /opt/resolve:

sudo mkdir -p /opt/resolve
cd /opt/resolve

Save the two files from Installation files in it:

  • compose.yaml: unchanged.
  • .env: you fill it in during the next steps.

.env will contain secrets, so only administrators should be able to read it:

chmod 600 .env

Generate the secrets

WeCare Resolve needs three secrets. Generate each one separately with:

openssl rand -hex 32

Put the results into .env:

SettingPurpose
APP_MASTER_KEYencrypts sensitive settings stored by WeCare Resolve, such as mail passwords and integration tokens
POSTGRES_PASSWORDthe database administrator password
DATABASE_APP_PASSWORDthe password of the restricted database account the application uses at runtime

Back up APP_MASTER_KEY now, outside the server, for example in your password manager. A database backup cannot be decrypted without it. If the key is lost, every encrypted setting has to be entered again.

Never change APP_MASTER_KEY on a running installation. If you need to replace it, see Rotating the master key.

First start

Fill in the remaining values in .env:

SettingExampleMeaning
RESOLVE_IMAGEcontainers.wecaredigital.eu/wecare/resolve-ce:2the container image to run
DOMAIN_NAMEresolve.example.comthe host name, without https://
RESOLVE_PORT8080the port on 127.0.0.1 that your reverse proxy forwards to
RESOLVE_BOOTSTRAP_ADMIN_EMAILit@example.comsign-in of the first administrator
RESOLVE_BOOTSTRAP_ADMIN_PASSWORDtheir initial password
RESOLVE_BOOTSTRAP_UNIT_NAMECity of Exampleyour organisation’s name, shown top left in the app
RESOLVE_BOOTSTRAP_LANGUAGEdethe default language (de, en, …)
RESOLVE_BOOTSTRAP_MAP_CENTER52.52,13.405,5000optional: where the map starts, as latitude,longitude[,radius in metres]

The RESOLVE_BOOTSTRAP_* values are only read while WeCare Resolve is being set up for the first time. They cannot change an existing installation.

Start WeCare Resolve:

docker compose up -d

The first start downloads the images and creates the database. Follow it with:

docker compose logs -f resolve

WeCare Resolve is ready when this prints "status": "UP":

curl -s http://127.0.0.1:8080/q/health/ready

If a required value is missing or invalid, WeCare Resolve stops with Installation incomplete in the log and names the value. Docker then restarts it every few seconds. Correct .env and run docker compose up -d again.

Sign in and remove the bootstrap values

Until your reverse proxy is set up, you can reach WeCare Resolve through an SSH tunnel from your workstation:

ssh -L 8080:127.0.0.1:8080 your-server

Open http://localhost:8080 and sign in with the administrator email and password from .env. Change the password under your account settings.

Then remove the bootstrap values, so the password no longer sits in the container’s configuration. Clear these lines in .env:

RESOLVE_BOOTSTRAP_ADMIN_EMAIL=
RESOLVE_BOOTSTRAP_ADMIN_PASSWORD=
RESOLVE_BOOTSTRAP_UNIT_NAME=
RESOLVE_BOOTSTRAP_MAP_CENTER=

and apply the change:

docker compose up -d

Set up a reverse proxy

A reverse proxy has to:

  • serve DOMAIN_NAME over HTTPS with a valid certificate;
  • forward to http://127.0.0.1:8080 (or your RESOLVE_PORT);
  • pass WebSocket connections on /api/graphql, which carry live updates;
  • pass the original Host header and set X-Forwarded-Proto;
  • accept request bodies of up to 250 MB, for attachments;
  • allow long-lived connections (one hour or more) for the WebSocket.

WeCare Resolve ignores X-Tenant-Id, X-Tenant-Slug and X-Tenant-Proxy-Secret headers unless it is set up for several tenants, so a single-organisation installation needs no special handling for them.

nginx

# In the http block, once:
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 443 ssl;
    server_name resolve.example.com;
    ssl_certificate     /etc/ssl/resolve.example.com/fullchain.pem;
    ssl_certificate_key /etc/ssl/resolve.example.com/privkey.pem;

    client_max_body_size 250m;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 1h;
    }
}

Caddy

Caddy obtains the certificate itself and handles WebSockets and the forwarding headers on its own:

resolve.example.com {
    request_body {
        max_size 250MB
    }
    reverse_proxy 127.0.0.1:8080
}

Check the proxy

Open https://resolve.example.com and sign in. Open an issue in two browser windows and change its status in one: the other window updates within a few seconds if WebSockets pass through the proxy.

Finish the setup in the app

Sign in as the administrator and open Settings:

  • Email: WeCare Resolve sends no email until you enter your SMTP server here and turn email on. Invitations and notifications depend on it.
  • User Management: invite your colleagues. There is no public sign-up.
  • Map: OpenStreetMap is used by default. Here you can change the map provider and where the map starts.
  • Domain: shows the host name from DOMAIN_NAME. Leave it unchanged: a host name saved on this page takes precedence over .env from then on.

Updates

Before updating, read the release notes and back up all data (see Backup and restore).

The image tag :2 follows every 2.x release. To update to the latest one, run in the installation directory:

docker compose pull
docker compose up -d

A new major version gets a new tag, for example :3. To move to it, change RESOLVE_IMAGE in .env and run the same commands.

The application may be unavailable for a minute or two while it migrates the database. To see the progress, run docker compose logs -f resolve.

Backup and restore

A complete backup consists of:

  1. .env, which contains APP_MASTER_KEY;
  2. a database dump;
  3. the resolve-data volume.

Back up

Run these commands in the installation directory:

docker compose exec -T db pg_dumpall -U postgres | gzip > resolve-db-$(date +%F).sql.gz
docker compose run --rm --no-deps --user root -v "$PWD:/backup" --entrypoint tar resolve \
  czf /backup/resolve-data-$(date +%F).tar.gz -C /deployments data

Copy both files and .env to a safe place outside the server. Use pg_dumpall, not pg_dump: the dump must include the database accounts WeCare Resolve uses.

Restore

Restore into an installation directory with the same compose.yaml and the same .env:

docker compose down -v
docker compose up -d db
gunzip -c resolve-db-2026-10-07.sql.gz | docker compose exec -T db psql -U postgres -d postgres
docker compose run --rm --no-deps --user root -v "$PWD:/backup" --entrypoint tar resolve \
  xzf /backup/resolve-data-2026-10-07.tar.gz -C /deployments
docker compose up -d

docker compose down -v deletes the current data. During the restore, role "postgres" already exists and database "resolve" already exists are expected.

Troubleshooting

To see the application log, run:

docker compose logs --tail 200 resolve
SymptomCause and fix
WeCare Resolve restarts every few seconds; the log says Installation incompleteA bootstrap value is missing or invalid on the first start. The log names it. Fix .env, then docker compose up -d.
docker compose up reports set APP_MASTER_KEY in .env (or another name)That value is empty in .env.
The log says Unable to connect to the database and WeCare Resolve never becomes readyCheck docker compose ps db and docker compose logs db. POSTGRES_PASSWORD must not change after the first start: the database keeps the password it was created with.
502 Bad Gateway from the proxyWeCare Resolve is not ready yet or RESOLVE_PORT differs from the proxy’s target. Check with curl -s http://127.0.0.1:8080/q/health/ready.
Uploads fail with 413 Request Entity Too LargeRaise the proxy’s body limit to 250 MB (client_max_body_size in nginx).
Pages do not update until reloadedThe proxy does not pass WebSockets on /api/graphql.
Encrypted settings (mail password, integrations) stopped working after a restoreAPP_MASTER_KEY differs from the one the backup was made with.

Uninstalling

docker compose down -v

This removes the containers and all data. Without -v, the volumes and your data stay in place.

Reference: settings in .env

SettingRequiredDefaultMeaning
RESOLVE_IMAGEyescontainer image to run
DOMAIN_NAMEyespublic host name
DOMAIN_PROTOCOLnohttpshttp only if browsers reach WeCare Resolve without TLS; session cookies then lose the Secure flag
RESOLVE_PORTno8080loopback port for the reverse proxy
APP_MASTER_KEYyesencryption key for sensitive settings
POSTGRES_PASSWORDyesdatabase administrator password
DATABASE_APP_PASSWORDyesruntime database account password
RESOLVE_BOOTSTRAP_ADMIN_EMAILfirst startfirst administrator
RESOLVE_BOOTSTRAP_ADMIN_PASSWORDfirst startfirst administrator’s password
RESOLVE_BOOTSTRAP_UNIT_NAMEfirst startorganisation name
RESOLVE_BOOTSTRAP_LANGUAGEnoendefault language
RESOLVE_BOOTSTRAP_MAP_CENTERnoinitial map view; the radius defaults to 10000 m

Rotating the master key

Replacing the master key means re-encrypting the stored values, so back up first (see Backup and restore). WeCare Resolve then runs with a keyring instead of a single key. Add both settings to compose.yaml under environment:

  • APP_KEYS: a JSON object with every key, for example {"v1":"<current APP_MASTER_KEY>","v2":"<new key>"}. It takes precedence over APP_MASTER_KEY.
  • ACTIVE_KEY_VERSION: the key used for new values, for example v2.

WeCare Resolve still reads values written with any key in the keyring. Keep every key in your backup.

Installation files

compose.yaml

# WeCare Resolve Community Edition. Settings come from .env next to this file.

services:

  resolve:
    image: ${RESOLVE_IMAGE:?set RESOLVE_IMAGE in .env}
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    # Plain HTTP on the loopback only: your HTTPS reverse proxy forwards to it.
    ports:
      - "127.0.0.1:${RESOLVE_PORT:-8080}:8080"
    volumes:
      - resolve-data:/deployments/data
    environment:
      APP_MASTER_KEY: ${APP_MASTER_KEY:?set APP_MASTER_KEY in .env}
      DOMAIN_NAME: ${DOMAIN_NAME:?set DOMAIN_NAME in .env}
      DOMAIN_PROTOCOL: ${DOMAIN_PROTOCOL:-https}
      DATABASE_TYPE: PostgreSQL
      DATABASE_HOST: db
      DATABASE_NAME: resolve
      DATABASE_USER: postgres
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
      DATABASE_APP_PASSWORD: ${DATABASE_APP_PASSWORD:?set DATABASE_APP_PASSWORD in .env}
      # Read on the first start only; clear them in .env afterwards.
      RESOLVE_BOOTSTRAP_ADMIN_EMAIL: ${RESOLVE_BOOTSTRAP_ADMIN_EMAIL:-}
      RESOLVE_BOOTSTRAP_ADMIN_PASSWORD: ${RESOLVE_BOOTSTRAP_ADMIN_PASSWORD:-}
      RESOLVE_BOOTSTRAP_UNIT_NAME: ${RESOLVE_BOOTSTRAP_UNIT_NAME:-}
      RESOLVE_BOOTSTRAP_LANGUAGE: ${RESOLVE_BOOTSTRAP_LANGUAGE:-en}
      RESOLVE_BOOTSTRAP_MAP_CENTER: ${RESOLVE_BOOTSTRAP_MAP_CENTER:-}

  db:
    image: postgres:18-alpine
    restart: unless-stopped
    volumes:
      - db-data:/var/lib/postgresql
    environment:
      POSTGRES_DB: resolve
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres", "-d", "resolve"]
      interval: 5s
      retries: 12

volumes:
  resolve-data:
  db-data:

.env

# Save as .env next to compose.yaml and fill in every value.

# The container image to run. The tag :2 follows every 2.x release.
RESOLVE_IMAGE=containers.wecaredigital.eu/wecare/resolve-ce:2

# Public host name, without https://. Your reverse proxy serves it over HTTPS.
DOMAIN_NAME=resolve.example.com
# https behind a reverse proxy; http only for a trial on localhost (DOMAIN_NAME=localhost:8080).
DOMAIN_PROTOCOL=https

# Port on 127.0.0.1 that your reverse proxy forwards to.
RESOLVE_PORT=8080

# Generate each secret with: openssl rand -hex 32
# APP_MASTER_KEY encrypts sensitive data. Back it up; without it that data is lost.
APP_MASTER_KEY=
POSTGRES_PASSWORD=
DATABASE_APP_PASSWORD=

# First start only: the first administrator and the name of your organisation.
RESOLVE_BOOTSTRAP_ADMIN_EMAIL=admin@example.com
RESOLVE_BOOTSTRAP_ADMIN_PASSWORD=
RESOLVE_BOOTSTRAP_UNIT_NAME=
RESOLVE_BOOTSTRAP_LANGUAGE=en
# Optional initial map view: latitude,longitude[,radius in metres], e.g. 52.52,13.405,5000
RESOLVE_BOOTSTRAP_MAP_CENTER=

Contact WeCare

We welcome bug reports and feature requests. Contact us through our website at wecaredigital.eu.