Skip to content

Production Install

This guide covers deploying MJC Job Manager on a Linux host using Docker Compose. The chosen machine is Ubuntu Server 22.04, but the process would be identical for most distributions, or if you were running embedded WSL/Docker Desktop for Windows.

Prerequisites

  • Docker + Docker Compose
  • A Linux host (VM or bare metal) - This guide will be using Ubuntu
  • A domain name (recommended) and the ability to point DNS to your server

Install

  • The simplest way to install mjc-job-manager is with the bootstrap file.
  • This will get the latest version, performa hash verification, and setup and commence the install process.
    curl -fsSL https://raw.githubusercontent.com/michaeljclarkk/mjc-job-manager/main/bootstrap.sh | bash
    cd /opt/mjc/current
    ./install.sh

Install Steps

  • mjc-job-manager comes with several install options

  • It is very possible to have app.YOUR_DOMAIN.com or similar, that requires either port forwarding 80 or 443 & 25, or the usage of a service like Tailscale

  • For this install, the choice will be #2 (this provides a self signed SSL certificate with Caddy, and also allows for no third-party feature limitations):

=============================================================================
  MJC Job Manager - Production Installation
=============================================================================

Checking prerequisites...
 Prerequisites check passed

=== Deployment Mode ===

Choose your deployment mode:

  1) Production with domain (HTTPS via Let's Encrypt)
     - Requires a domain pointing to this server
     - Automatic SSL certificate

  2) Production with self-signed HTTPS (LAN/IP access)
     - Access via IP address or hostname
     - Self-signed SSL certificate (browser warning expected)
     - Required for voice assistant/microphone features

  3) Production without SSL (HTTP only)
     - Access via IP address or hostname
     - No SSL (not recommended - some features won't work)

  4) Cloudflare Proxy (HTTPS via Cloudflare)
     - Cloudflare handles SSL termination
     - Server runs on custom port (avoids router conflicts)
     - Requires Cloudflare DNS with proxy enabled (orange cloud)

  5) Headless (BYO Reverse Proxy)
     - No Caddy - use your own Traefik/nginx/Caddy
     - Exposes frontend and API on configurable ports
     - For integration with existing Docker stacks

Enter choice [1-5]:
  • Next, you'll be asked to enter an IP or hostname, for this case, i'll use my servers internal IP address, but this can be anything you want. For instance, if you wanted to run it at app.mjcit.com.au, youd enter your custom domain here:
Enter IP address or hostname [XXX.XXX.X.X]: 192.168.1.9
  • The script will ask you whether or not you want to download some maps (for the geo-coding and tile server) to choose an installation directory. this can be skipped, however, the software will fallback to using to OSM Tiles and Public Nominatim which is subject to public api rate limiting.

  • In this install, i'll use the Aus geofabrik. Its important to not that anywhere outside of this area, will fallback to the above public API's & the script will fail if given a non-existant GeoFabrik dataset:

=== Map Data Storage ===

The tile server and geocoding services require 50GB+ of storage.
Choose a directory on a drive with sufficient space.

Available storage:
Filesystem                         Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv  455G  108G  329G  25% /
/dev/sda2                          2.0G  198M  1.6G  11% /boot
/dev/sda1                          1.1G  6.2M  1.1G   1% /boot/efi

Enter directory for map data [/opt/mjc/shared/osm-data]:
Creating OSM data directories...
 OSM data directory: /opt/mjc/shared/osm-data
 Available space on /: 329G

=== Map Region Selection ===

Choose the OpenStreetMap region to download:

  1) Australia (~2.5GB download, ~25GB extracted)
  2) New Zealand (~300MB download, ~3GB extracted)
  3) Australia + New Zealand/Oceania (~3GB download, ~30GB extracted)
  4) United Kingdom (~1.5GB download, ~15GB extracted)
  5) United States (~10GB download, ~100GB extracted)
  6) Germany (~4GB download, ~40GB extracted)
  7) Custom (enter Geofabrik path)

Enter choice [1]: 7

Enter the Geofabrik path (see https://download.geofabrik.de/)
Example: europe/france-latest.osm.pbf
PBF path: australia-oceania/australia/queensland-latest.osm.pbf
 Map region: Custom
  • Once the script is complete, the progress of the download/import progress of the tile-server and nominatim can be checked with:
    # Check tile-server download/import progress
    docker logs mjc-tile-server -f --tail 50

    # Check nominatim download/import progress
    docker logs mjc-nominatim -f --tail 50
  • The installation will continue with its other processes, such as running migrations, generating secrets, config files, and bringing the services up. The frontend is created/built towards the end of this, to where all required containers are confirmed as created:
[+] up 23/23
  Image mjc-job-manager-frontend Built                                                                                                               281.1s
  Volume mjc-caddy-data          Created                                                                                                               0.1s
  Volume mjc-caddy-config        Created                                                                                                               0.1s
  Volume mjc-storage-data        Created                                                                                                               0.1s
  Volume mjc-postfix-spool       Created                                                                                                               0.1s
  Container mjc-nominatim        Created                                                                                                              13.3s
  Container mjc-tile-server      Created                                                                                                              13.9s
  Container mjc-db               Healthy                                                                                                              43.5s
  Container mjc-imgproxy         Created                                                                                                              12.6s
  Container mjc-functions        Created                                                                                                              12.3s
  Container mjc-realtime         Created                                                                                                              11.9s
  Container mjc-migrator         Created                                                                                                              11.3s
  Container mjc-auth             Created                                                                                                              11.4s
  Container mjc-meta             Created                                                                                                              12.8s
  Container mjc-studio           Created                                                                                                              13.6s
  Container mjc-rest             Created                                                                                                              13.1s
  Container mjc-storage          Created                                                                                                               1.9s
  Container mjc-text-extractor   Created                                                                                                               2.1s
  Container mjc-kong             Created                                                                                                               2.1s
  Container mjc-frontend         Created                                                                                                               2.5s
  Container mjc-mailhook         Created                                                                                                               2.1s
  Container mjc-postfix          Created                                                                                                               3.3s
  Container mjc-caddy            Created                                                                                                               2.3s
  • It will then commence the verification process, to ensure all are in a running state.
  • You'll be presented with creating the first user, this should be the main business_admin
=== Creating Initial Admin User ===
Enter admin email address: michaeljclarkk@outlook.com
Enter admin password (8+ chars, must have uppercase, lowercase, digit):
Re-type password to confirm:
Enter admin first name: Michael
Enter admin last name: Clark

Creating admin user: my@email.com
                  id
--------------------------------------
 A BIG USER ID WILL BE SHOWN HERE
(1 row)

If all is successful, you'll be presenteed with the final stage of the install script:

  Installation Complete!
=============================================================================

Your MJC Job Manager instance is now running.

Access URLs:
  Application:     https://192.168.1.9

Note: Using self-signed certificate. Your browser will show a
      security warning - this is expected. Click 'Advanced' and
      'Proceed to 192.168.1.9' to continue.
  Supabase Studio: http://localhost:54323 (localhost only)

Steps:
  1. Open the application URL in your browser
  2. Log in with your admin credentials:
     Email: your@email.com
  3. Configure SMTP in Settings > Business > Email Settings (optional)

Note: Email confirmation is disabled by default.
      You can enable it after configuring SMTP by setting
      MAILER_AUTOCONFIRM=false in .env.production

Important:
  - Your secrets are stored in /opt/mjc/shared/.env.production
  - Back up this file securely!
  - To view logs: docker compose -f docker-compose.prod.yml logs -f
  - To stop: docker compose -f docker-compose.prod.yml down
  - To update: sudo /opt/mjc/shared/update-release.sh --to <version> --repo <owner>/<repo>
-

Next Steps

  • Access the front end at the IP/Hostname added during setup, in this case the hostname is https://192.168.1.9.
  • Login with your admin username and password Login screen first start

Notes

  • Supabase Studio is bound to localhost by default for safety.
  • If you need Studio remotely, prefer an SSH tunnel or VPN.

Switching to a different Hostname or Mode Later on

There may be a need to switch different modes or change hosts - whatever this may be, you can update the related services to support the new host:

#1 Regenerate certificates

cd /opt/mjc/shared/certs
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout server.key -out server.crt \
    -subj "/CN=NEW_IP_OR_HOSTNAME" \
    -addext "subjectAltName=IP:NEW_IP_OR_HOSTNAME"

#2 Update the CaddyFile
sed -i 's/OLD_IP/NEW_IP/g' /opt/mjc/shared/Caddyfile

#3 Update .env.production
sed -i 's/OLD_IP/NEW_IP/g' /opt/mjc/shared/.env.production

#4 Rebuild Containers and Restart 
cd /opt/mjc/current
docker compose --env-file /opt/mjc/shared/.env.production -f docker-compose.prod.yml up -d --build frontend
docker compose --env-file /opt/mjc/shared/.env.production -f docker-compose.prod.yml restart caddy

Uninstallation

  • The simplest way to start over - or remove forever, is to shut everything down, and nuke the install directory. (After you have made appropriate backups of course)
# Stop containers first (if running)
cd /opt/mjc/current 2>/dev/null && \
docker compose --env-file /opt/mjc/shared/.env.production -f docker-compose.prod.yml down -v 2>/dev/null

# Now nuke it
sudo rm -rf /opt/mjc

# Verify it's gone
ls /opt/

Next - Initial Setup