Manual Installation
Manual Installation
Section titled “Manual Installation”Install Mantis components directly on servers without containers.
Prerequisites
Section titled “Prerequisites”Build Requirements
Section titled “Build Requirements”| Software | Version | Purpose |
|---|---|---|
| Rust | Latest stable (build images pin 1.93.x) | Building components |
| Node.js | 20+ | Building Lens UI |
| npm | 10+ | Node package manager |
| PostgreSQL | 16+ | Database |
| RabbitMQ | 3.12+ | Message queue |
| Redis | 7.0+ | Cache and coordination |
System Requirements
Section titled “System Requirements”| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 4 cores | 8+ cores |
| RAM | 8 GB | 16+ GB |
| Storage | 50 GB SSD | 100+ GB SSD |
Building from Source
Section titled “Building from Source”Clone Repository
Section titled “Clone Repository”git clone https://github.com/MantisPlatform/mantis.gitcd mantisBuild Rust Components
Section titled “Build Rust Components”# Install Rust if neededcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shsource ~/.cargo/env
# Build all components in release modejust build-release
# Or build individuallycd mandible && cargo build --releasecd ../thorax && cargo build --releasecd ../tarsus && cargo build --releaseBuild Lens
Section titled “Build Lens”Lens is a Rust binary that embeds its web UI. Build the UI first (Node is a build-time-only dependency), then compile the binary with the UI embedded:
# Build the SPA (produces lens/ui/build)npm --prefix lens/ui cinpm --prefix lens/ui run build
# Compile the binary with the UI embeddedcargo build --release -p lens --features lens/embed-uiInstall Binaries
Section titled “Install Binaries”# Create directoriessudo mkdir -p /usr/local/binsudo mkdir -p /etc/mantissudo mkdir -p /var/lib/mantissudo mkdir -p /var/log/mantis
# Install binariessudo cp target/release/mandible /usr/local/bin/sudo cp target/release/thorax /usr/local/bin/sudo cp target/release/tarsus /usr/local/bin/
# Set permissionssudo chmod 755 /usr/local/bin/mandiblesudo chmod 755 /usr/local/bin/thoraxsudo chmod 755 /usr/local/bin/tarsusDatabase Setup
Section titled “Database Setup”Install PostgreSQL
Section titled “Install PostgreSQL”# Ubuntu/Debiansudo apt updatesudo apt install postgresql-16 postgresql-contrib
# RHEL/Rocky/Almasudo dnf install postgresql16-server postgresql16sudo /usr/pgsql-16/bin/postgresql-16-setup initdbConfigure PostgreSQL
Section titled “Configure PostgreSQL”# Start servicesudo systemctl enable postgresqlsudo systemctl start postgresql
# Create database and usersudo -u postgres psql <<EOFCREATE USER mantis WITH PASSWORD 'your-secure-password';CREATE DATABASE mantis OWNER mantis;GRANT ALL PRIVILEGES ON DATABASE mantis TO mantis;EOFRun Migrations
Section titled “Run Migrations”# Install diesel CLIcargo install diesel_cli --no-default-features --features postgres
# Run migrations from the instinct directorycd /path/to/mantis/instinctexport DATABASE_URL="postgres://mantis:your-secure-password@localhost/mantis"diesel migration runRabbitMQ Setup
Section titled “RabbitMQ Setup”Install RabbitMQ
Section titled “Install RabbitMQ”# Ubuntu/Debian (using official repository)curl -1sLf 'https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey' | sudo gpg --dearmor -o /usr/share/keyrings/rabbitmq.gpgecho "deb [signed-by=/usr/share/keyrings/rabbitmq.gpg] https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu/ jammy main" | sudo tee /etc/apt/sources.list.d/rabbitmq.listsudo apt updatesudo apt install rabbitmq-server
# RHEL/Rocky/Almasudo dnf install rabbitmq-serverConfigure RabbitMQ
Section titled “Configure RabbitMQ”# Enable and startsudo systemctl enable rabbitmq-serversudo systemctl start rabbitmq-server
# Enable management pluginsudo rabbitmq-plugins enable rabbitmq_management
# Create usersudo rabbitmqctl add_user mantis your-secure-passwordsudo rabbitmqctl set_permissions -p / mantis ".*" ".*" ".*"sudo rabbitmqctl set_user_tags mantis administratorEnable TLS
Section titled “Enable TLS”Create /etc/rabbitmq/rabbitmq.conf:
listeners.ssl.default = 5671ssl_options.cacertfile = /etc/rabbitmq/certs/ca.crtssl_options.certfile = /etc/rabbitmq/certs/server.crtssl_options.keyfile = /etc/rabbitmq/certs/server.keyssl_options.verify = verify_peerssl_options.fail_if_no_peer_cert = falseRedis Setup
Section titled “Redis Setup”Install Redis
Section titled “Install Redis”# Ubuntu/Debiansudo apt install redis-server
# RHEL/Rocky/Almasudo dnf install redisConfigure Redis
Section titled “Configure Redis”Edit /etc/redis/redis.conf:
bind 127.0.0.1port 6379requirepass your-secure-passwordmaxmemory 1gbmaxmemory-policy allkeys-lruStart Redis
Section titled “Start Redis”sudo systemctl enable redissudo systemctl start redisComponent Configuration
Section titled “Component Configuration”Mandible Configuration
Section titled “Mandible Configuration”Create /etc/mantis/mandible.toml:
[server]host = "0.0.0.0"port = 3000
[server.tls]cert_path = "/etc/mantis/certs/mandible.crt"key_path = "/etc/mantis/certs/mandible.key"
[database]url = "postgres://mantis:password@localhost/mantis"max_connections = 10
[jwt]algorithm = "HS256"# secret = "" # Set via MANDIBLE__JWT__SECRET env var (min 32 chars)# Generate with: openssl rand -base64 32
# For RS256 (asymmetric, optional):# algorithm = "RS256"# private_key_path = "/etc/mantis/jwt/private.pem"# public_key_path = "/etc/mantis/jwt/public.pem"
[grpc]orchestration_url = "https://localhost:50051"tls_ca_cert_path = "/etc/mantis/certs/ca.crt"Thorax Configuration
Section titled “Thorax Configuration”Create /etc/mantis/thorax.toml:
[tls]auth_mode = "thumbprint"cert_path = "/etc/mantis/certs/thorax.crt"key_path = "/etc/mantis/certs/thorax.key"ca_cert_path = "/etc/mantis/certs/ca.crt"
[grpc]address = "0.0.0.0"port = 50051
# Thorax has NO database — all persistence is owned by Mandible, reached over# gRPC. Set THORAX__MANDIBLE__ENDPOINT to Mandible's internal gRPC (host:50052).[mandible]endpoint = "localhost:50052"
[queue]enabled = truehost = "localhost"port = 5671username = "mantis"password = "password"
[cluster]enabled = trueredis_url = "redis://:password@localhost:6379"Tarsus Configuration
Section titled “Tarsus Configuration”Create /etc/tarsus/tarsus.toml:
name = "server-name"mode = "listen"
# Tarsus registers with Mandible (internal gRPC port 50052), not Thorax.# Mandible assigns the appropriate Thorax instance during registration.[mandible]endpoint = "mandible.example.com:50052"
[tls]cert_path = "/etc/tarsus/cert.pem"key_path = "/etc/tarsus/key.pem"ca_cert_path = "/etc/tarsus/ca.crt"
[registration]heartbeat_interval_secs = 30Systemd Services
Section titled “Systemd Services”Mandible Service
Section titled “Mandible Service”Create /etc/systemd/system/mandible.service:
[Unit]Description=Mantis Mandible API ServerAfter=network.target postgresql.service
[Service]Type=simpleUser=mantisGroup=mantisEnvironment="MANDIBLE_CONFIG=/etc/mantis/mandible.toml"Environment="RUST_LOG=info"EnvironmentFile=-/etc/mantis/mandible.envExecStart=/usr/local/bin/mandibleRestart=alwaysRestartSec=5
# Security hardeningNoNewPrivileges=yesProtectSystem=strictProtectHome=yesReadWritePaths=/var/lib/mantis /var/log/mantisPrivateTmp=yes
[Install]WantedBy=multi-user.targetThorax Service
Section titled “Thorax Service”Create /etc/systemd/system/thorax.service:
[Unit]Description=Mantis Thorax Orchestration ServerAfter=network.target rabbitmq-server.service redis.service
[Service]Type=simpleUser=mantisGroup=mantisEnvironment="THORAX_CONFIG=/etc/mantis/thorax.toml"Environment="RUST_LOG=info"EnvironmentFile=-/etc/mantis/thorax.envExecStart=/usr/local/bin/thoraxRestart=alwaysRestartSec=5
# Security hardeningNoNewPrivileges=yesProtectSystem=strictProtectHome=yesReadWritePaths=/var/lib/mantis /var/log/mantisPrivateTmp=yes
[Install]WantedBy=multi-user.targetTarsus Service
Section titled “Tarsus Service”Create /etc/systemd/system/tarsus.service:
[Unit]Description=Mantis Tarsus AgentAfter=network.target
[Service]Type=simpleUser=rootEnvironment="TARSUS_CONFIG=/etc/tarsus/tarsus.toml"Environment="RUST_LOG=info"EnvironmentFile=-/etc/tarsus/tarsus.envExecStart=/usr/local/bin/tarsusRestart=alwaysRestartSec=5
[Install]WantedBy=multi-user.targetEnable Services
Section titled “Enable Services”# Create mantis usersudo useradd -r -s /sbin/nologin mantis
# Set ownershipsudo chown -R mantis:mantis /etc/mantissudo chown -R mantis:mantis /var/lib/mantissudo chown -R mantis:mantis /var/log/mantis
# Reload systemdsudo systemctl daemon-reload
# Enable and start servicessudo systemctl enable mandible thoraxsudo systemctl start mandible thorax
# On target serverssudo systemctl enable tarsussudo systemctl start tarsusLens Deployment
Section titled “Lens Deployment”Lens is a self-contained binary (lens) — no Node.js runtime. The same release
tarball that carries mandible/thorax/tarsus/mantisctl also carries lens;
it embeds the web UI and reads its Mandible origin at runtime (MANTIS_API_URL),
so one binary serves any environment.
Install the binary + systemd unit
Section titled “Install the binary + systemd unit”# `lens` is already in /usr/local/bin if you installed the release tarball above.# Otherwise copy it there:sudo install -m 0755 lens /usr/local/bin/lens
# Runtime config (EnvironmentFile). MANTIS_API_URL is injected into the served# shell + CSP at runtime; LENS_REQUIRE_TLS=1 fails fast if the certs are missing.sudo tee /etc/mantis/lens.env >/dev/null <<'EOF'PORT=8443HOST=0.0.0.0MANTIS_API_URL=https://mantis.example.comTLS_CERT_PATH=/etc/mantis/certs/lens-cert.pemTLS_KEY_PATH=/etc/mantis/certs/lens-key.pemLENS_REQUIRE_TLS=1EOFCreate /etc/systemd/system/lens.service:
[Unit]Description=Mantis Lens — management UIAfter=network-online.targetWants=network-online.target
[Service]Type=simpleUser=mantisGroup=mantisEnvironmentFile=/etc/mantis/lens.envExecStart=/usr/local/bin/lensRestart=alwaysRestartSec=5ProtectSystem=strictProtectHome=yesNoNewPrivileges=yes
[Install]WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reloadsudo systemctl enable --now lensSame-origin reverse proxy (required)
Section titled “Same-origin reverse proxy (required)”Lens and Mandible must share an origin so the HTTP-only refresh-token cookie
is visible to both. Front them with a single nginx server that serves Lens and
proxies /api to Mandible on the same origin:
server { listen 443 ssl http2; server_name mantis.example.com;
ssl_certificate /etc/nginx/certs/mantis.crt; ssl_certificate_key /etc/nginx/certs/mantis.key;
# Lens — the binary serves the UI + its own CSP/security headers over TLS. location / { proxy_pass https://127.0.0.1:8443; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; }
# Mandible REST — same origin as Lens (shared refresh cookie). location /api { proxy_pass https://localhost:3000; 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; }}Enable the site:
sudo ln -s /etc/nginx/sites-available/lens /etc/nginx/sites-enabled/sudo nginx -tsudo systemctl reload nginxCertificate Setup
Section titled “Certificate Setup”Generate CA
Section titled “Generate CA”# Create CA private keyopenssl genrsa -out /etc/mantis/certs/ca.key 4096
# Create CA certificateopenssl req -x509 -new -nodes \ -key /etc/mantis/certs/ca.key \ -sha256 -days 3650 \ -out /etc/mantis/certs/ca.crt \ -subj "/CN=Mantis CA/O=Your Organization"Generate Server Certificates
Section titled “Generate Server Certificates”# Mandibleopenssl req -new -nodes \ -keyout /etc/mantis/certs/mandible.key \ -out /etc/mantis/certs/mandible.csr \ -subj "/CN=mandible.example.com"
openssl x509 -req \ -in /etc/mantis/certs/mandible.csr \ -CA /etc/mantis/certs/ca.crt \ -CAkey /etc/mantis/certs/ca.key \ -CAcreateserial \ -out /etc/mantis/certs/mandible.crt \ -days 365 -sha256
# Thoraxopenssl req -new -nodes \ -keyout /etc/mantis/certs/thorax.key \ -out /etc/mantis/certs/thorax.csr \ -subj "/CN=thorax.example.com"
openssl x509 -req \ -in /etc/mantis/certs/thorax.csr \ -CA /etc/mantis/certs/ca.crt \ -CAkey /etc/mantis/certs/ca.key \ -CAcreateserial \ -out /etc/mantis/certs/thorax.crt \ -days 365 -sha256Set Permissions
Section titled “Set Permissions”chmod 600 /etc/mantis/certs/*.keychmod 644 /etc/mantis/certs/*.crtchown -R mantis:mantis /etc/mantis/certsVerification
Section titled “Verification”Check Services
Section titled “Check Services”# Service statussudo systemctl status mandiblesudo systemctl status thorax
# Health endpointscurl -k https://localhost:3000/api/v1/health
# gRPC healthgrpcurl -insecure localhost:50051 grpc.health.v1.Health/CheckCheck Logs
Section titled “Check Logs”# Mandible logsjournalctl -u mandible -f
# Thorax logsjournalctl -u thorax -f
# Tarsus logs (on target)journalctl -u tarsus -fTest Connectivity
Section titled “Test Connectivity”# Databasepsql -h localhost -U mantis -d mantis -c "SELECT 1"
# RabbitMQrabbitmqctl status
# Redisredis-cli -a password pingFirewall Configuration
Section titled “Firewall Configuration”Using firewalld
Section titled “Using firewalld”# Mandible APIsudo firewall-cmd --permanent --add-port=3000/tcp
# Thorax gRPCsudo firewall-cmd --permanent --add-port=50051/tcp
# Reloadsudo firewall-cmd --reloadUsing iptables
Section titled “Using iptables”# Mandible APIiptables -A INPUT -p tcp --dport 3000 -j ACCEPT
# Thorax gRPCiptables -A INPUT -p tcp --dport 50051 -j ACCEPTTroubleshooting
Section titled “Troubleshooting”Service Won’t Start
Section titled “Service Won’t Start”- Check configuration syntax
- Verify file permissions
- Check logs:
journalctl -u <service> -xe
Database Connection Failed
Section titled “Database Connection Failed”- Verify PostgreSQL is running
- Check connection URL
- Test manual connection
Certificate Errors
Section titled “Certificate Errors”- Verify certificate paths
- Check certificate validity
- Ensure CA certificate is correct
Next Steps
Section titled “Next Steps”- Upgrades - Upgrade procedures
- Security Overview - Security configuration
- Production Checklist - Production readiness
