Skip to main content

Installing PatchMon Server on Docker

Installing PatchMon Server on Docker

Overview

PatchMon runs as a containerised application made up of four services:

  • Database - PostgreSQL 17
  • Redis - Redis 7 (used for BullMQ job queues and caching)
  • Backend - Node.js API server
  • Frontend - React application served via NGINX

Container Images

Available Tags

Tag Description
latest Latest stable release
x.y.z Exact version pin (e.g. 1.2.3)
x.y Latest patch in a minor series (e.g. 1.2)
x Latest minor and patch in a major series (e.g. 1)
edge Latest development build in main branch - may be unstable, for testing only

Both backend and frontend images share the same version tags.


Quick Start

1. Download the files

curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/PatchMon/PatchMon/refs/heads/main/docker/docker-compose.yml
curl -fsSL -o env.example https://raw.githubusercontent.com/PatchMon/PatchMon/refs/heads/main/docker/env.example

2. Create your .env file

Copy the example file and generate the three required secrets:

cp env.example .env

# Generate and insert strong secrets
sed -i "s/^POSTGRES_PASSWORD=$/POSTGRES_PASSWORD=$(openssl rand -hex 32)/" .env
sed -i "s/^REDIS_PASSWORD=$/REDIS_PASSWORD=$(openssl rand -hex 32)/" .env
sed -i "s/^JWT_SECRET=$/JWT_SECRET=$(openssl rand -hex 64)/" .env

Then open .env and configure your server access settings:

# Set these to the URL you will use to access PatchMon.
# SERVER_PROTOCOL, SERVER_HOST and SERVER_PORT are used by agents to connect back to PatchMon.
# CORS_ORIGIN should match the full URL you access PatchMon from in your browser.

SERVER_PROTOCOL=http
SERVER_HOST=localhost
SERVER_PORT=3000
CORS_ORIGIN=http://localhost:3000

Tip: If you are deploying PatchMon behind a reverse proxy with a domain name, set SERVER_PROTOCOL=https, SERVER_HOST=patchmon.example.com, SERVER_PORT=443, and CORS_ORIGIN=https://patchmon.example.com.

That's it. The docker-compose.yml uses env_file: .env to pass all your configuration straight into the containers. You do not need to edit the compose file itself.

For a full list of optional environment variables (rate limiting, logging, database pool tuning, session timeouts, etc.), see the Environment Variables page.

3. Start PatchMon

docker compose up -d

Once all containers are healthy, open your browser at http://localhost:3000 (or your configured URL) and complete the first-time setup to create your admin account.


Updating PatchMon

By default the compose file uses the latest tag. To update:

docker compose pull
docker compose up -d

This pulls the latest images, recreates containers, and keeps all your data intact.

Pinning to a specific version

If you prefer to pin versions, update the image tags in docker-compose.yml:

services:
  backend:
    image: ghcr.io/patchmon/patchmon-backend:1.4.0
  frontend:
    image: ghcr.io/patchmon/patchmon-frontend:1.4.0

Then run:

docker compose pull
docker compose up -d

Check the releases page for version-specific changes and migration notes.


Volumes

The compose file creates the following Docker volumes:

Volume Purpose
postgres_data PostgreSQL data directory
redis_data Redis data directory
agent_files PatchMon agent scripts
branding_assets Custom branding files (logos, favicons) - optional, new in 1.4.0

You can bind any of these to a host path instead of a Docker volume by editing the compose file.

Note: The backend container runs as user and group ID 1000. If you rebind the agent_files or branding_assets volumes to a host path, make sure that user/group has write permissions.


Docker Swarm Deployment

This section covers deploying PatchMon to a Docker Swarm cluster. For standard single-host deployments, use the production guide above.

Network Configuration

The default compose file uses an internal bridge network (patchmon-internal) for service-to-service communication. All services connect to this network and discover each other by service name.

If you are using an external reverse proxy network (e.g. Traefik):

  1. Keep all PatchMon services on patchmon-internal for internal communication
  2. Optionally add the frontend service to the reverse proxy network
  3. Make sure service name resolution works within the same network

Example: Traefik integration

services:
  frontend:
    image: ghcr.io/patchmon/patchmon-frontend:latest
    networks:
      - patchmon-internal
    deploy:
      replicas: 1
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.patchmon.rule=Host(`patchmon.example.com`)"

The frontend reaches the backend via patchmon-internal using the hostname backend, while Traefik routes external traffic to the frontend.

Troubleshooting: host not found in upstream "backend"

This usually means the frontend and backend are on different networks, or services haven't fully started. Check:

  • All services are on the same internal network
  • Service health status with docker ps or docker service ps
  • Network connectivity with docker exec <container> ping backend

Development Setup

This section is for developers who want to contribute to PatchMon or run it locally in development mode.

Getting started

git clone https://github.com/PatchMon/PatchMon.git
cd PatchMon
docker compose -f docker/docker-compose.dev.yml up --watch --build

The development compose file:

  • Builds images locally from source
  • Enables hot reload via Docker Compose watch
  • Exposes all service ports for debugging
  • Mounts source code directly into containers

Development ports

Service Port URL
Frontend 3000 http://localhost:3000
Backend API 3001 http://localhost:3001
PostgreSQL 5432 localhost:5432
Redis 6379 localhost:6379

Common commands

# Start with hot reload (attached)
docker compose -f docker/docker-compose.dev.yml up --watch

# Start detached
docker compose -f docker/docker-compose.dev.yml up -d

# Rebuild a specific service
docker compose -f docker/docker-compose.dev.yml up -d --build backend

# View logs
docker compose -f docker/docker-compose.dev.yml logs -f

How hot reload works

  • Frontend/backend source changes are synced automatically in watch mode
  • package.json changes trigger an automatic service rebuild
  • Prisma schema changes cause the backend to restart automatically

Building images locally

# Development images
docker build -f docker/backend.Dockerfile --target development -t patchmon-backend:dev .
docker build -f docker/frontend.Dockerfile --target development -t patchmon-frontend:dev .

# Production images
docker build -f docker/backend.Dockerfile -t patchmon-backend:latest .
docker build -f docker/frontend.Dockerfile -t patchmon-frontend:latest .