Skip to main content

Installing PatchMon Server on Ubuntu 24

Native

Installing InstallPatchMon (advanced/non-docker)

RunServer on aUbuntu/Debian clean

Overview

The PatchMon setup script automates the full installation on Ubuntu/Debian serverservers. withIt internetinstalls access:all dependencies, configures services, generates credentials, and starts PatchMon - ready to use in minutes.

Ubuntu:

It supports both fresh installations and updating existing instances.


Requirements

RequirementMinimum
OSUbuntu 20.04+ / Debian 11+
CPU2 vCPU
RAM2 GB
Disk15 GB
AccessRoot (sudo)
NetworkInternet access (to pull packages and clone the repo)

Fresh Installation

1. Prepare the server

apt-get update -y && apt-get upgrade -y
apt install curl jq bc -y

Script

2. Run the setup script

curl -fsSL -o patchmon_server_setup.setup.sh https://raw.githubusercontent.com/9technologygroup/patchmon.net/PatchMon/PatchMon/refs/heads/main/setup.sh \
  && chmod +x patchmon_server_setup.setup.sh \
  && sudo bash patchmon_server_setup.setup.sh

Minimum

3. specsFollow forthe buildinginteractive :

prompts

CPUThe :script 2will vCPUask RAMyou :four 2GB Disk : 15GBthings:

During

setupyou’llbeasked:

  • Email:
  • only defaultis
    Prompt Description Default
    Domain/IP:IPThe public DNS or local IP (default:users will access PatchMon frompatchmon.internal)
    SSL/HTTPS:HTTPSEnable Let's Encrypt SSL. Use y for public deployments with a public IP,servers, n for internal networks.networks n
    EmailOnly asked if SSL is enabled (- used for Let’Let's Encrypt)Encrypt
  • Gitcertificate Branch:notifications
  • -
    Release / BranchLists the latest 3 release tags plus main. (pressPick Enter)the latest release unless you need a specific versionLatest tag

    After confirming your choices, the script runs fully unattended.


    What the Script Does

    The script will:performs these steps automatically:

      1. InstallChecks prerequisitestimezone - confirms (Node.js,or PostgreSQL,lets nginx)you change) the server timezone
      2. CloneInstalls theprerequisites repo,- installcurl, dependencies,jq, buildgit, thewget, frontend,netcat-openbsd, run migrations
      3. Create a systemd service and nginx site vhost config
      4. Start the service and write a consolidated info file at:
        • /opt/<your-domain>/deployment-info.txtsudo
        • FullInstalls installerNode.js log20.x - via NodeSource
        • Installs PostgreSQL - creates an isolated database and user for this instance
        • Installs Redis - configures ACL-based authentication with a dedicated Redis user and database
        • Installs Nginx - sets up a reverse proxy with security headers
        • Installs Certbot (if SSL enabled) - obtains and configures a Let's Encrypt certificate
        • Creates a dedicated system user - PatchMon runs as a non-login, locked-down user
        • Clones the repository to /opt/<your-domain>/patchmon-install.log
      5. Installs npm dependencies in an isolated environment
  • Creates

    .env files - generates secrets and writes backend/.env and frontend/.env

  • Runs database migrations - with self-healing for failed migrations
  • Creates a systemd service - with NoNewPrivileges, PrivateTmp, and ProtectSystem=strict
  • Configures Nginx - reverse proxy with HTTP/2, WebSocket support, and security headers
  • Populates server settings in the database (server URL, protocol, port)
  • Writes deployment-info.txt - all credentials and commands in one file

  • After installation:

    Installation

      1. Visit http(s)://<your-domain> andin completeyour browser
      2. Complete the first-time admin setup (create your admin account)
      3. SeeAll allcredentials and useful infocommands are saved to:
      /opt/<your-domain>/deployment-info.txt
      

      Directory Structure

      After installation, PatchMon lives at /opt/<your-domain>/:

      /opt/<your-domain>/
        backend/
          .env              # Backend environment variables
          src/
          prisma/
        frontend/
          .env              # Frontend environment variables (baked at build)
          dist/             # Built frontend (served by Nginx)
        deployment-info.txt # Credentials, ports, and diagnostic commands
        patchmon-install.log
      

      Environment Variables

      The setup script generates a backend/.env with sensible defaults. You can customise it after installation.

      File location: /opt/<your-domain>/backend/.env

      Variables set by the script

      VariableWhat the script sets
      DATABASE_URLFull connection string with generated password
      JWT_SECRETAuto-generated 50-character secret
      CORS_ORIGIN<protocol>://<your-domain>
      PORTRandom port between 3001-3999
      REDIS_HOSTlocalhost
      REDIS_PORT6379
      REDIS_USERInstance-specific Redis ACL user
      REDIS_PASSWORDAuto-generated password
      REDIS_DBAuto-detected available Redis database

      Adding optional variables

      To enable OIDC, adjust rate limits, configure TFA, or change other settings, add the relevant variables to backend/.env and restart the service.

      For example, to enable OIDC SSO:

      # Edit the .env file
      sudo nano /opt/<your-domain>/backend/.env
      

      Add at the bottom:

      # OIDC / SSO
      OIDC_ENABLED=true
      OIDC_ISSUER_URL=https://auth.example.com
      OIDC_CLIENT_ID=patchmon
      OIDC_CLIENT_SECRET=your-client-secret
      OIDC_REDIRECT_URI=https://patchmon.example.com/api/v1/auth/oidc/callback
      OIDC_SCOPES=openid email profile groups
      OIDC_AUTO_CREATE_USERS=true
      

      Then restart:

      sudo systemctl restart <your-domain>
      

      Full list of optional variables

      All optional environment variables are documented in the Docker deployment-info.txtenv.example file and on the Environment Variables page. The same variables work for both Docker and native installations. Key categories include:

      • Authentication - JWT_EXPIRES_IN, JWT_REFRESH_EXPIRES_IN, SESSION_INACTIVITY_TIMEOUT_MINUTES
      • Password policy - PASSWORD_MIN_LENGTH, PASSWORD_REQUIRE_UPPERCASE, etc.
      • Account lockout - MAX_LOGIN_ATTEMPTS, LOCKOUT_DURATION_MINUTES
      • Two-factor authentication - MAX_TFA_ATTEMPTS, TFA_REMEMBER_ME_EXPIRES_IN, etc.
      • OIDC / SSO - OIDC_ENABLED, OIDC_ISSUER_URL, OIDC_CLIENT_ID, etc.
      • Rate limiting - RATE_LIMIT_WINDOW_MS, RATE_LIMIT_MAX, AUTH_RATE_LIMIT_*, AGENT_RATE_LIMIT_*
      • Database pool - DB_CONNECTION_LIMIT, DB_POOL_TIMEOUT, DB_IDLE_TIMEOUT, etc.
      • Logging - LOG_LEVEL, ENABLE_LOGGING
      • Network - ENABLE_HSTS, TRUST_PROXY, CORS_ORIGINS
      • Encryption - AI_ENCRYPTION_KEY, SESSION_SECRET
      • Timezone - TZ
      • Body limits - JSON_BODY_LIMIT, AGENT_UPDATE_BODY_LIMIT

      After any .env change, restart the service: sudo systemctl restart <your-domain>


      Updating an Existing Installation

      To update PatchMon to the latest version, re-run the setup script with --update:

      sudo bash setup.sh --update
      

      The update process:

      1. Detects all existing PatchMon installations under /opt/
      2. Lets you select which instance to update
      3. Backs up the current code and database before making changes
      4. Pulls the latest code from the selected branch/tag
      5. Installs updated dependencies and rebuilds the frontend
      6. Runs any new database migrations (with self-healing)
      7. Adds any missing environment variables to backend/.env (preserves your existing values)
      8. Updates the Nginx configuration with latest security improvements
      9. Restarts the service

      If the update fails, the script prints rollback instructions with the exact commands to restore from the backup.


      Managing the Service

      Replace <your-domain> with the domain/IP you used during installation (e.g. patchmon.internal).

      Service commands

      # Check status
      systemctl status <your-domain>
      
      # Restart
      sudo systemctl restart <your-domain>
      
      # Stop
      sudo systemctl stop <your-domain>
      
      # View logs (live)
      journalctl -u <your-domain> -f
      
      # View recent logs
      journalctl -u <your-domain> --since "1 hour ago"
      

      Other useful commands

      # Test Nginx config
      nginx -t && sudo systemctl reload nginx
      
      # Check database connection
      sudo -u <db-user> psql -d <db-name> -c "SELECT 1;"
      
      # Check which port PatchMon is listening on
      netstat -tlnp | grep <backend-port>
      
      # View deployment info (credentials, ports, etc.)
      cat /opt/<your-domain>/deployment-info.txt
      

      Troubleshooting

      IssueSolution
      Script fails with permission errorRun with sudo bash setup.sh
      Service won't startCheck logs: journalctl -u <your-domain> -n 50
      Redis authentication errorVerify REDIS_USER and REDIS_PASSWORD in backend/.env match Redis ACL. Run redis-cli ACL LIST to check
      Database connection refusedCheck PostgreSQL is running: systemctl status postgresql
      SSL certificate issuesRun certbot certificates to check status. Renew with certbot renew
      Nginx 502 Bad GatewayBackend may not be running. Check systemctl status <your-domain> and the backend port
      Migration failuresCheck status: cd /opt/<your-domain>/backend && npx prisma migrate status
      Port already in useThe script picks a random port (3001-3999). Edit PORT in backend/.env and update the Nginx config

      For more help, see the Troubleshooting page or check the installation log:

      cat /opt/<your-domain>/patchmon-install.log
      

      Please note: This script was built to automate the deployment of PatchMon however our preferred method of installation is via Docker. This method is hard to support due to various parameters and changes within the OS such as versions of Nginx causing issues on the installer.

      Anyway, do enjoy and I understand if you're like me ... want to see the files in plain sight that is being served as the app ;)