Skip to main content

Installing PatchMon Server on Docker

Installing PatchMon Server on Docker

Overview

PatchMon isruns as a containerised application thatmade monitors system patches and updates. The application consistsup of four main services:

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

Container Images

Available Tags

  • The latestofPatchMon
  • Full-Usethis for exact version pinning.
  • Minor-Usethisto-Usethis to get the latest minor and patch release in a major version series.
  • The latestdevelopmentpurposes.
    TagDescription
    latest: Latest stable release
    x.y.z: Exact version tagspin (e.g. 1.2.3)
    x.y: Latest versionpatch tagsin a minor series (e.g. 1.2)
    x Latest getminor the latestand patch release in a minormajor version series.
  • x: Major version tagsseries (e.g. 1)
  • edge: Latest development build within themain mostbranch recent features and fixes. This tag- may often be unstable and is intended onlyunstable, for testing andonly

    These tags are available for bothBoth backend and frontend images asshare theythe aresame versionedversion together.tags.


    Quick Start

    Production1. Deployment

    1. Download the Docker Compose file
    2. Set a database password in the file where it says:files
      environment:curl POSTGRES_PASSWORD:-fsSL #-o CREATEdocker-compose.yml A STRONG PASSWORD AND PUT IT HEREhttps://raw.githubusercontent.com/PatchMon/PatchMon/refs/heads/main/docker/docker-compose.yml
      
    3. Update the corresponding DATABASE_URL with your password in the backend service where it says:
      environment:curl DATABASE_URL:-fsSL postgresql:-o env.example https://patchmon_user:REPLACE_YOUR_POSTGRES_PASSWORD_HERE@database:5432/patchmon_dbraw.githubusercontent.com/PatchMon/PatchMon/refs/heads/main/docker/env.example
      
    4. 2.
    5. SetCreate ayour Redis.env passwordfile
    6. in

      Copy the Redisexample servicefile commandand wheregenerate itthe says:three required secrets:

      command:cp redis-serverenv.example --requirepass.env
      
      your-redis-password-here# 
      Note: The Redis service uses a hardcoded password in the command line for better reliabilityGenerate and to avoid environment variable parsing issues.
    7. Update the corresponding REDIS_PASSWORD in the backend service where it says:
      environment:
        REDIS_PASSWORD: your-redis-password-here
      
    8. Generate ainsert strong JWTsecrets secret.sed You-i can do this like so:
      "s/^POSTGRES_PASSWORD=$/POSTGRES_PASSWORD=$(openssl rand -hex 6432)/" .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
      
    9. Then

    10. open .env and configure your server access settings:

      # Set athese JWTto secretthe 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 theyour backendbrowser.
      
      serviceSERVER_PROTOCOL=http
      whereSERVER_HOST=localhost
      itSERVER_PORT=3000
      says:
      
      environment:
        JWT_SECRET: # CREATE A STRONG SECRET AND PUT IT HERECORS_ORIGIN=http://localhost:3000
      
    11. Configure

      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.

    12. 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 Configuration section)

    13. Start the application:Environment Variables page.

      3. Start PatchMon

      docker compose up -d
      
    14. Once

    15. Accessall thecontainers applicationare 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,default the compose file uses the latest tagtag. forTo both backend and frontend images.

    This means you can update PatchMon to the latest version as easily as:update:

    docker compose pull
    docker compose up -d
    --pull
    

    This command will:

    • Pullpulls the latest imagesimages, fromrecreates thecontainers, registry
    • and
    • Recreatekeeps containers with updated images
    • Maintainall your data and configuration
    intact.

    Version-Specific Updates

    If you'd like to pin your Docker deployment of PatchMonPinning to a specific version,version

    If you can do this in the compose file.

    When you do this, updatingprefer to apin newversions, version requires manually updating the image tags in the compose file yourself:

    1. Updateupdate the image tags in docker-compose.yml. For example::

      services:
        backend:
          image: ghcr.io/patchmon/patchmon-backend:1.2.3  # Update version here
         ...4.0
        frontend:
          image: ghcr.io/patchmon/patchmon-frontend:1.2.3  # Update version here
         ...4.0
      
    2. Then run the update command:run:

      docker compose pull
      docker compose up -d
      --pull
      

    [!TIP] Check the releases page for version-specific changes and migration notes.


    ConfigurationVolumes

    Environment

    The Variables

    compose

    Databasefile Service

    creates the following Docker volumes:

    datadataagent
    VariableVolume DescriptionDefaultPurpose
    POSTGRES_DBpostgres_data DatabasePostgreSQL name patchmon_dbdirectory
    POSTGRES_USERredis_data DatabaseRedis user patchmon_userdirectory
    POSTGRES_PASSWORDagent_files DatabasePatchMon password MUST BE SET!

    Redis Service

    VariableDescriptionDefault
    REDIS_PASSWORDRedis passwordMUST BE SET!

    [!NOTE] The Redis service uses a hardcoded password in the command line (redis-server --requirepass your-password) instead of environment variables or configuration files. This approach eliminates parsing issues and provides better reliability. The password must be set in both the Redis command and the backend service environment variables.

    Backend Service

    Database Configuration
    (logos,favicons)-optional,
    VariableDescriptionDefault
    DATABASE_URLPostgreSQL connection stringMUST BE UPDATED WITH YOUR POSTGRES_PASSWORD!scripts
    PM_DB_CONN_MAX_ATTEMPTSbranding_assets MaximumCustom databasebranding connectionfiles attempts 30
    PM_DB_CONN_WAIT_INTERVALWait interval between connection attemptsnew in seconds2
    Redis Configuration
    VariableDescriptionDefault
    REDIS_HOSTRedis server hostnameredis
    REDIS_PORTRedis server port6379
    REDIS_PASSWORDRedis authentication passwordMUST BE UPDATED WITH YOUR REDIS_PASSWORD!
    REDIS_DBRedis database number1.4.0
    Authentication & Security
    VariableDescriptionDefault
    JWT_SECRETJWT signing secret - Generate with openssl rand -hex 64MUST BE SET!
    JWT_EXPIRES_INJWT token expiration time1h
    JWT_REFRESH_EXPIRES_INJWT refresh token expiration time7d
    SESSION_INACTIVITY_TIMEOUT_MINUTESSession inactivity timeout in minutes30
    DEFAULT_USER_ROLEDefault role for new usersuser
    Server & Network Configuration
    VariableDescriptionDefault
    PORTBackend server API port3001
    SERVER_PROTOCOLFrontend Server protocol (http or https)http
    SERVER_HOSTFrontend server hostlocalhost
    SERVER_PORTFrontend server port3000
    CORS_ORIGINThe URL used to access the apphttp://localhost:3000
    ENABLE_HSTSEnable HTTP Strict Transport Securitytrue
    TRUST_PROXYTrust proxy headers - See Express.js docstrue

    SERVER_PROTOCOLYou , SEVER_HOST & SERVER_PORT is used by the agent scripts to communicate to the server which goes via the frontend. Generally this is the same as CORS_ORIGIN but in some cases it's different.

    Rate Limiting
    VariableDescriptionDefault
    RATE_LIMIT_WINDOW_MSRate limiting window in milliseconds900000
    RATE_LIMIT_MAXMaximum requests per window5000
    AUTH_RATE_LIMIT_WINDOW_MSAuthentication rate limiting window in milliseconds600000
    AUTH_RATE_LIMIT_MAXMaximum authentication requests per window500
    AGENT_RATE_LIMIT_WINDOW_MSAgent API rate limiting window in milliseconds60000
    AGENT_RATE_LIMIT_MAXMaximum agent requests per window1000
    Logging
    VariableDescriptionDefault
    LOG_LEVELLogging level (debug, info, warn, error)info
    ENABLE_LOGGINGEnable application loggingtrue

    Frontend Service

    VariableDescriptionDefault
    BACKEND_HOSTBackend service hostnamebackend
    BACKEND_PORTBackend service port3001

    Volumes

    The compose file creates three Docker volumes:

    • postgres_data: PostgreSQL's data directory.
    • redis_data: Redis's data directory.
    • agent_files: PatchMon's agent files.

    If you wish tocan bind eitherany ifof their respective container pathsthese to a host path ratherinstead thanof a Docker volume,volume youby can do so inediting the Docker Composecompose file.

    [!TIP]Note: The backend container runs as user &and group ID 1000. If you planrebind the agent_files or branding_assets volumes to re-binda thehost agentpath, filesmake directory, ensuresure that the same user and/or user/group ID has permission to write to the host path to which it's bound.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.

    Development

    Setup

    Getting

    For development with live reload and source code mounting:

    1. Clone the repository:

      started

    git clone https://github.com/PatchMon/PatchMon.git
    cd patchmon.netPatchMon
    
  • Start development environment:

    docker compose -f docker/docker-compose.dev.yml up --watch --build
    

    See Development Commands for more options.

  • Access the application:

    • Frontend: http://localhost:3000
    • Backend API: http://localhost:3001
    • Database: localhost:5432
    • Redis: localhost:6379
  • Development Docker Compose

    The development compose file (docker/docker-compose.dev.yml):file:

    • Builds images locally from source using development targets
    • Enables hot reload withvia Docker Compose watch functionality
    • Exposes databaseall and backendservice ports for testing and developmentdebugging
    • Mounts source code directly into containers for live development
    • Supports debugging with enhanced logging

    Building

    Development Imagesports

    Locally

    Both

    Dockerfilesusemulti-stagebuildswithseparatedevelopmentandproductiontargets:

    Service Port URL
    Frontend 3000http://localhost:3000
    Backend API3001http://localhost:3001
    PostgreSQL5432localhost:5432
    Redis6379localhost:6379

    Common commands

    # BuildStart developmentwith 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 .
    
    # Build productionProduction images (default target)
    docker build -f docker/backend.Dockerfile -t patchmon-backend:latest .
    docker build -f docker/frontend.Dockerfile -t patchmon-frontend:latest .
    

    Development Commands

    Hot Reload Development

    # Attached, live log output, services stopped on Ctrl+C
    docker compose -f docker/docker-compose.dev.yml up
    
    # Attached with Docker Compose watch for hot reload
    docker compose -f docker/docker-compose.dev.yml up --watch
    
    # Detached
    docker compose -f docker/docker-compose.dev.yml up -d
    
    # Quiet, no log output, with Docker Compose watch for hot reload
    docker compose -f docker/docker-compose.dev.yml watch
    

    Rebuild Services

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

    Development Ports

    The development setup exposes additional ports for debugging:

    • Database: 5432 - Direct PostgreSQL access
    • Redis: 6379 - Direct Redis access
    • Backend: 3001 - API server with development features
    • Frontend: 3000 - React development server with hot reload

    Development Workflow

    1. Initial Setup: Clone repository and start development environment

      git clone https://github.com/PatchMon/PatchMon.git
      cd patchmon.net
      docker compose -f docker/docker-compose.dev.yml up -d --build
      
    2. Hot Reload Development: Use Docker Compose watch for automatic reload

      docker compose -f docker/docker-compose.dev.yml up --watch --build
      
    3. Code Changes:

      • Frontend/Backend Source: Files are synced automatically with watch mode
      • Package.json Changes: Triggers automatic service rebuild
      • Prisma Schema Changes: Backend service restarts automatically
    4. Database Access: Connect database client directly to localhost:5432

    5. Redis Access: Connect Redis client directly to localhost:6379

    6. Debug: If started with docker compose [...] up -d or docker compose [...] watch, check logs manually:

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

      Otherwise logs are shown automatically in attached modes (up, up --watch).

    Features in Development Mode

    • Hot Reload: Automatic code synchronization and service restarts
    • Enhanced Logging: Detailed logs for debugging
    • Direct Access: Exposed ports for database, Redis, and API debugging
    • Health Checks: Built-in health monitoring for services
    • Volume Persistence: Development data persists between restarts