Skip to content

Running with Docker

Docker is the supported deployment path. The image bundles the OpenCV and Pillow system libraries that are tedious to install by hand.

Quick start

bash
git clone https://github.com/fabriziosalmi/brandkit.git
cd brandkit
docker compose up -d --build

BrandKit is now on http://localhost:8000.

bash
docker compose logs -f brandkit   # follow logs
docker compose down               # stop
docker compose down -v            # stop and drop volumes

What the compose file does

yaml
services:
  brandkit:
    build: .
    container_name: brandkit
    ports:
      - "8000:8000"
    volumes:
      - ./static/uploads:/app/static/uploads
    environment:
      - FLASK_ENV=production        # legacy, no longer does anything
    restart: unless-stopped

Three things worth knowing:

  • The bind mount is a bind mount, not a named volume. ./static/uploads on your host is the app's upload directory. Everything anyone generates lands in your working copy. Add it to .gitignore (it already is) and read Privacy.
  • FLASK_ENV=production is now a no-op and can be dropped. It used to gate the cleanup thread; cleanup is controlled by the BRANDKIT_CLEANUP_* variables and runs under gunicorn regardless.
  • The port is fixed at 8000 inside the container. Change the left-hand side only: "127.0.0.1:9000:8000" to bind on a different host port and stop exposing it on every interface.

Running without Compose

bash
docker build -t brandkit .

docker run -d \
  --name brandkit \
  -p 127.0.0.1:8000:8000 \
  -v "$(pwd)/static/uploads:/app/static/uploads" \
  -v "$HOME/.u2net:/root/.u2net" \
  -e BRANDKIT_MAX_UPLOAD_MB=32 \
  --restart unless-stopped \
  brandkit

The second volume caches rembg's ONNX models on the host, so rebuilding the image does not re-download ~180 MB.

The image

Dockerfile starts from python:3.11-slim and installs the native dependencies for rembg and OpenCV (libgl1, libglib2.0-0, libjpeg-dev, zlib1g-dev, libpng-dev, libwebp-dev, and the OpenCV core/imgproc headers). It then installs rembg, onnxruntime, opencv-python-headless and numpy, followed by everything in requirements.txt.

Expect a build of several minutes and a final image around 2 GB. That is the cost of shipping ONNX Runtime and the scientific Python stack.

The entrypoint

CMD ["bash", "entrypoint.sh"]. The script picks a server in this order:

  1. gunicorn, if it is on PATHgunicorn --bind 0.0.0.0:$PORT --worker-tmp-dir /dev/shm app:app
  2. flask run, if the CLI is present and FLASK_APP is set
  3. a Python fallback that imports app.py and calls app.run(host="0.0.0.0")

It also creates static/uploads if it is missing and honours PORT (default 8000).

Set a secret key before adding workers

The entrypoint does not pass --workers, so gunicorn's default of 1 applies. If you raise it, set BRANDKIT_SECRET_KEY first — without it each worker generates its own signing key and CSRF tokens minted by one worker are rejected by the next.

With several workers you probably also want BRANDKIT_CLEANUP_ENABLED=false on all but one, so a single process owns the file sweep.

Updating

bash
cd brandkit
git pull
docker compose up -d --build

Uploads in the bind mount survive. If you changed config.json, your changes survive too — it is copied into the image at build time but you are running a fresh copy from the repo.

Health check

There is no dedicated /healthz endpoint. Use the root page or the format catalogue:

yaml
    healthcheck:
      test: ["CMD", "python", "-c",
             "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/format-info').status==200 else 1)"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 40s

/format-info is a GET, needs no CSRF token, does no image work, and returns JSON — a good liveness probe.

Resource limits

Background removal on a large image can allocate a lot of memory. If you are running on a small VPS, cap it explicitly:

yaml
    deploy:
      resources:
        limits:
          memory: 4G

and lower the upload ceiling with BRANDKIT_MAX_UPLOAD_MB. See Environment variables.