More from MSP Reboot: depl0y · st0r
Deployment Documentation

Deployment & Configuration Guide

ClientSt0r deploys on standard Linux infrastructure. This page covers system requirements, the installation process, and common post-install configuration tasks.

For the authoritative installation steps, see the INSTALL.md file on GitHub. This page provides an overview and reference.

What you need before deploying.

A standard Linux server with Python 3.12+, MariaDB, and Nginx covers the core requirements. The optional Celery/Redis stack is not required for basic operation.

Minimum requirements

Supported Linux environments

  • OS: Ubuntu 22.04 LTS, Debian 12, or comparable Linux distribution
  • CPU: 2 cores
  • RAM: 4 GB (8 GB recommended for active PSA workloads)
  • Disk: 20 GB (more for media storage — screenshots, attachments, floor plans)
  • Python: 3.12+
  • Database: MariaDB 10.6+ or MySQL 8.0+
  • Web server: Nginx 1.18+
  • Network: HTTPS required; a valid domain name is strongly recommended
Recommended production setup

Practical production baseline

  • OS: Ubuntu 22.04 LTS (most tested)
  • CPU: 4+ cores
  • RAM: 8–16 GB depending on org count and concurrent users
  • Disk: 50+ GB SSD (separate volume for media storage if possible)
  • TLS: Let's Encrypt via Certbot (automated renewal)
  • Backups: Daily database dump + media file backup to offsite location
  • Optional: Redis for Celery task queue (background jobs, scheduled scans)

The installation process, step by step.

The full installation steps are in INSTALL.md on GitHub — treat that as the authoritative reference. This overview summarises the process and the key commands at each stage.

01

Prepare the server

  • Fresh Linux install with sudo access
  • Update packages: apt update && apt upgrade -y
  • Install system dependencies: Python 3.12, pip, MariaDB, Nginx, git
  • Create a dedicated service user for running the application
02

Clone and configure

  • Clone repository: git clone https://github.com/agit8or1/clientst0r.git
  • Create Python virtual environment: python3 -m venv venv
  • Install Python dependencies: pip install -r requirements.txt
  • Copy .env.example to .env and edit all configuration values
03

Database setup

  • Create MariaDB database and dedicated application user with minimal privileges
  • Run migrations: python manage.py migrate
  • Create superuser: python manage.py createsuperuser
  • Collect static files: python manage.py collectstatic
04

Configure services

  • Create Gunicorn systemd service file (see reference below)
  • Configure Nginx virtual host with proxy_pass to Gunicorn
  • Obtain TLS certificate — Let's Encrypt via Certbot is recommended
  • Enable and start services: systemctl enable --now clientst0r nginx
05

Post-install

  • Log in with the superuser account and verify the application loads correctly
  • Set up organisations, user accounts, and initial role assignments
  • Configure integrations (RMM, PSA, distributors) from the admin panel
  • Test email delivery — send a test notification to verify SMTP is working
  • Set up database backup schedule and confirm offsite backup destination

Key environment variables.

All sensitive configuration is managed via the .env file at the project root. Copy .env.example to get started — the example file documents every available option. The variables below must be set before the application will start correctly.

SECRET_KEY
Django secret key. Generate with: python -c "import secrets; print(secrets.token_hex(50))"
DEBUG
Set to False in production. Never True on a public-facing server.
ALLOWED_HOSTS
Your domain name(s), comma-separated. Example: clientst0r.example.com
DATABASE_URL
MariaDB connection string: mysql://user:password@localhost/dbname
MEDIA_ROOT
Filesystem path for uploaded files and media. Example: /var/www/clientst0r/media/
EMAIL_HOST
SMTP server hostname for outbound email delivery
EMAIL_PORT
SMTP port. Typically 587 for STARTTLS or 465 for SSL
EMAIL_HOST_USER
SMTP authentication username
EMAIL_HOST_PASSWORD
SMTP authentication password
ENCRYPTION_KEY
Vault encryption key. Generated on first run. Do not change after vault data is stored.
Security note: Never commit your .env file to version control. Never run with DEBUG=True on a public-facing server. The ENCRYPTION_KEY cannot be changed after vault data is stored — back it up securely and treat it as a critical secret.

Representative Nginx server block.

The block below covers the standard single-server setup: HTTP to HTTPS redirect, TLS termination, static and media file serving, proxy to Gunicorn, and security headers. Adjust paths and domain name to match your environment.

Nginx virtual host — /etc/nginx/sites-available/clientst0r
server {
    listen 80;
    server_name clientst0r.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name clientst0r.example.com;

    ssl_certificate     /etc/letsencrypt/live/clientst0r.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/clientst0r.example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    client_max_body_size 50m;

    # Security headers
    add_header X-Frame-Options           "SAMEORIGIN"            always;
    add_header X-Content-Type-Options    "nosniff"               always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Referrer-Policy           "strict-origin-when-cross-origin" always;

    # Static files — served directly by Nginx
    location /static/ {
        alias /var/www/clientst0r/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Media files — user uploads, screenshots, attachments
    location /media/ {
        alias /var/www/clientst0r/media/;
        expires 7d;
    }

    # Application — proxy to Gunicorn
    location / {
        proxy_pass         http://127.0.0.1:8000;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_redirect     off;
        proxy_read_timeout 60s;
    }
}

Systemd service file for Gunicorn.

Create this file at /etc/systemd/system/clientst0r.service. Adjust the paths to match your installation directory. Worker count recommendation: (2 × CPU cores) + 1.

/etc/systemd/system/clientst0r.service
[Unit]
Description=ClientSt0r Gunicorn application server
After=network.target mariadb.service

[Service]
User=clientst0r
Group=www-data
WorkingDirectory=/opt/clientst0r
Environment="PATH=/opt/clientst0r/venv/bin"
EnvironmentFile=/opt/clientst0r/.env
ExecStart=/opt/clientst0r/venv/bin/gunicorn \
    --workers 5 \
    --bind 127.0.0.1:8000 \
    --timeout 90 \
    --access-logfile /var/log/clientst0r/access.log \
    --error-logfile /var/log/clientst0r/error.log \
    clientst0r.wsgi:application
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

After saving the file, run systemctl daemon-reload and then systemctl enable --now clientst0r to start the service and enable it on boot.

Keeping ClientSt0r up to date.

Always back up the database and .env file before running updates. Review the changelog on GitHub for breaking changes before updating a production instance.

Web-based updates (recommended)

ClientSt0r includes a web-based update mechanism accessible from the admin panel. Updates pull the latest release, run database migrations, collect static files, and restart services automatically.

Review the changelog before triggering an update. The update UI shows the current and target versions before applying changes.

Manual update process (fallback)

  • git pull origin main
  • pip install -r requirements.txt
  • python manage.py migrate
  • python manage.py collectstatic --noinput
  • systemctl restart clientst0r
Always back up the database and mysqldump clientst0r > backup-$(date +%Y%m%d).sql before running updates. A failed migration on a large database is easier to recover from with a fresh backup than without one.

Post-install configuration reference.

Common tasks after a fresh installation. Most configuration is done from the admin panel UI rather than config files.

SMTP email setup

Required for ticket notifications, user invites, password resets, and the customer portal. Set EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER, and EMAIL_HOST_PASSWORD in your .env file. Test delivery from the admin panel after saving.

RMM integrations

Configure RMM connections from the Integrations section in the admin panel. Each integration stores its API credentials encrypted at rest. Integration depth varies by RMM platform — refer to the in-app integration guide for each provider.

Feature flags

Platform modules can be individually enabled or disabled from the admin panel feature flags settings. Disable modules your team does not use to reduce UI surface area. Changes take effect immediately without a service restart.

Let's Encrypt TLS

Install Certbot and obtain a certificate with two commands:

apt install certbot python3-certbot-nginx

certbot --nginx -d clientst0r.example.com

Certbot configures automatic renewal via a systemd timer or cron job.

Database backup cron

Add a daily MariaDB dump to your crontab. Example for 2 AM daily:

0 2 * * * mysqldump -u clientst0r -p clientst0r | gzip > /backups/db-$(date +\%Y\%m\%d).sql.gz

Rotate and sync to an offsite location using your preferred backup tool.

Organisations & users

Create client organisations from the Organisations module, then add user accounts and assign roles. The 42-level RBAC system lets you scope each user to specific orgs with appropriate permissions. Admin accounts have platform-wide access regardless of org role.

Related documentation:

Architecture overview → API reference → INSTALL.md on GitHub →