PostgreSQL Setup
PostgreSQL Setup
Section titled “PostgreSQL Setup”Configure PostgreSQL for Mantis deployment.
Requirements
Section titled “Requirements”| Requirement | Minimum | Recommended |
|---|---|---|
| PostgreSQL | 16 | 16+ |
| Storage | 10 GB | 50+ GB SSD |
| Memory | 1 GB | 4+ GB |
Installation
Section titled “Installation”Ubuntu/Debian
Section titled “Ubuntu/Debian”# Add PostgreSQL repositorysudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# Install PostgreSQL 16sudo apt updatesudo apt install postgresql-16 postgresql-contrib-16RHEL/Rocky/Alma
Section titled “RHEL/Rocky/Alma”# Install repositorysudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# Disable built-in PostgreSQL modulesudo dnf -qy module disable postgresql
# Install PostgreSQL 16sudo dnf install -y postgresql16-server postgresql16-contrib
# Initialize databasesudo /usr/pgsql-16/bin/postgresql-16-setup initdbDocker
Section titled “Docker”services: postgres: image: postgres:16-alpine environment: POSTGRES_USER: mantis POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: mantis volumes: - postgres_data:/var/lib/postgresql/data ports: - '5432:5432'Database Creation
Section titled “Database Creation”Create User and Database
Section titled “Create User and Database”# Switch to postgres usersudo -u postgres psql
# Create the app role. CREATEROLE is REQUIRED: the audit-hardening migration# creates the mantis_audit_reader / mantis_audit_writer roles and grants them to# this role, which aborts without it (see note below).CREATE USER mantis WITH PASSWORD 'your-secure-password' CREATEROLE;
# Create databaseCREATE DATABASE mantis OWNER mantis;
# Grant permissionsGRANT ALL PRIVILEGES ON DATABASE mantis TO mantis;
# Connect to database and grant schema permissions\c mantisGRANT ALL ON SCHEMA public TO mantis;:::caution Audit roles are required to migrate
The audit-hardening migration creates three roles used for row-level security on
audit_log_entries — mantis_audit_reader, mantis_audit_writer (both
NOLOGIN), and a pre-existing mantis_audit_retention — and grants them to the
app role. If the app role lacks CREATEROLE, diesel migration run aborts on
the very first setup with Cannot grant the audit roles to mantis.
Grant CREATEROLE as above, or pre-create and grant the roles yourself before
migrating:
CREATE ROLE mantis_audit_reader NOLOGIN NOSUPERUSER NOBYPASSRLS;CREATE ROLE mantis_audit_writer NOLOGIN NOSUPERUSER NOBYPASSRLS;CREATE ROLE mantis_audit_retention NOLOGIN NOSUPERUSER NOBYPASSRLS;GRANT mantis_audit_reader, mantis_audit_writer, mantis_audit_retention TO mantis WITH ADMIN OPTION;These same roles are also needed for backup/restore of the audit table. :::
Verify Connection
Section titled “Verify Connection”# Test connectionpsql -h localhost -U mantis -d mantis -c "SELECT version();"Configuration
Section titled “Configuration”postgresql.conf
Section titled “postgresql.conf”Key settings for Mantis workloads:
# Connection Settingslisten_addresses = 'localhost' # Or '*' for remote accessport = 5432max_connections = 200
# Memory Settingsshared_buffers = 1GB # 25% of RAMeffective_cache_size = 3GB # 75% of RAMwork_mem = 16MBmaintenance_work_mem = 256MB
# Write-Ahead Logwal_level = replica # For replicationmax_wal_size = 2GBmin_wal_size = 512MB
# Query Plannerrandom_page_cost = 1.1 # For SSD storageeffective_io_concurrency = 200 # For SSD storage
# Logginglog_destination = 'stderr'logging_collector = onlog_directory = 'log'log_filename = 'postgresql-%Y-%m-%d.log'log_statement = 'ddl' # Log schema changeslog_min_duration_statement = 1000 # Log queries > 1s
# Autovacuumautovacuum = onautovacuum_max_workers = 3autovacuum_naptime = 60pg_hba.conf
Section titled “pg_hba.conf”Configure client authentication:
# Local connectionslocal all postgres peerlocal all mantis scram-sha-256
# IPv4 local connectionshost all all 127.0.0.1/32 scram-sha-256
# IPv4 remote connections (for Mantis components)host mantis mantis 10.0.0.0/8 scram-sha-256
# SSL connections (recommended for production)hostssl mantis mantis 0.0.0.0/0 scram-sha-256Apply Configuration
Section titled “Apply Configuration”# Reload configurationsudo systemctl reload postgresql
# Or restart for settings that require itsudo systemctl restart postgresqlSSL/TLS Configuration
Section titled “SSL/TLS Configuration”Generate Certificates
Section titled “Generate Certificates”# Create directorysudo mkdir -p /etc/postgresql/16/main/certscd /etc/postgresql/16/main/certs
# Generate server key and certificateopenssl req -new -x509 -days 365 -nodes \ -keyout server.key \ -out server.crt \ -subj "/CN=postgres.example.com"
# Set permissionschmod 600 server.keychown postgres:postgres server.key server.crtEnable SSL
Section titled “Enable SSL”In postgresql.conf:
ssl = onssl_cert_file = '/etc/postgresql/16/main/certs/server.crt'ssl_key_file = '/etc/postgresql/16/main/certs/server.key'ssl_min_protocol_version = 'TLSv1.2'Connection URL with SSL
Section titled “Connection URL with SSL”postgres://mantis:password@db.example.com:5432/mantis?sslmode=verify-full&sslrootcert=/path/to/ca.crt| SSL Mode | Description |
|---|---|
disable | No SSL |
allow | Try SSL, fallback to non-SSL |
prefer | Try SSL first (default) |
require | Require SSL, no certificate verification |
verify-ca | Verify server certificate |
verify-full | Verify certificate and hostname |
High Availability
Section titled “High Availability”Streaming Replication
Section titled “Streaming Replication”Primary Server
Section titled “Primary Server”In postgresql.conf:
wal_level = replicamax_wal_senders = 5wal_keep_size = 1GBhot_standby = onIn pg_hba.conf:
host replication replicator 10.0.0.0/8 scram-sha-256Create replication user:
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'secure-password';Replica Server
Section titled “Replica Server”# Stop PostgreSQLsudo systemctl stop postgresql
# Remove data directorysudo rm -rf /var/lib/postgresql/16/main/*
# Create base backup from primarysudo -u postgres pg_basebackup \ -h primary.example.com \ -U replicator \ -D /var/lib/postgresql/16/main \ -P -R -X stream
# Start PostgreSQLsudo systemctl start postgresqlUsing PgBouncer
Section titled “Using PgBouncer”For connection pooling at scale:
[databases]mantis = host=localhost port=5432 dbname=mantis
[pgbouncer]listen_addr = 0.0.0.0listen_port = 6432auth_type = scram-sha-256auth_file = /etc/pgbouncer/userlist.txtpool_mode = transactionmax_client_conn = 1000default_pool_size = 50Mantis Configuration
Section titled “Mantis Configuration”Mandible Database Settings
Section titled “Mandible Database Settings”[database]url = "postgres://mantis:password@localhost:5432/mantis?sslmode=require"max_connections = 10min_idle = 2connection_timeout_secs = 10Environment Variables
Section titled “Environment Variables”Mandible reads the DATABASE_URL variable (it also accepts the layered
MANDIBLE__DATABASE__URL override):
export DATABASE_URL="postgres://mantis:password@localhost:5432/mantis"Initial Schema
Section titled “Initial Schema”Run Migrations
Section titled “Run Migrations”# Install Diesel CLIcargo install diesel_cli --no-default-features --features postgres
# Run migrations from the instinct directory. The app role must have CREATEROLE# (or the mantis_audit_* roles must be pre-granted WITH ADMIN OPTION) — see# "Create User and Database" above — or this aborts on the audit-hardening step.cd /path/to/mantis/instinctdiesel migration runVerify Schema
Section titled “Verify Schema”# Connect to databasepsql -U mantis -d mantis
# List tables\dt
# Check schema versionSELECT * FROM __diesel_schema_migrations ORDER BY run_on DESC LIMIT 5;Backup Configuration
Section titled “Backup Configuration”Automated Backups
Section titled “Automated Backups”Create backup script:
#!/bin/bashBACKUP_DIR="/var/backups/mantis"DATE=$(date +%Y%m%d_%H%M%S)RETENTION_DAYS=7
# Create backup directorymkdir -p "$BACKUP_DIR"
# Perform backuppg_dump -h localhost -U mantis -Fc mantis > "$BACKUP_DIR/mantis_$DATE.dump"
# Remove old backupsfind "$BACKUP_DIR" -name "mantis_*.dump" -mtime +$RETENTION_DAYS -deleteSchedule with cron:
# Daily at 2 AM0 2 * * * /opt/mantis/scripts/backup-db.shPoint-in-Time Recovery
Section titled “Point-in-Time Recovery”Enable WAL archiving:
# postgresql.confarchive_mode = onarchive_command = 'cp %p /var/lib/postgresql/archive/%f'Monitoring
Section titled “Monitoring”Key Metrics
Section titled “Key Metrics”-- Connection countSELECT count(*) FROM pg_stat_activity;
-- Database sizeSELECT pg_size_pretty(pg_database_size('mantis'));
-- Table sizesSELECT relname, pg_size_pretty(pg_total_relation_size(relid))FROM pg_catalog.pg_statio_user_tablesORDER BY pg_total_relation_size(relid) DESCLIMIT 10;
-- Long running queriesSELECT pid, now() - pg_stat_activity.query_start AS duration, queryFROM pg_stat_activityWHERE state != 'idle'ORDER BY duration DESC;Health Check
Section titled “Health Check”# Simple health checkpg_isready -h localhost -U mantis -d mantisTroubleshooting
Section titled “Troubleshooting”Connection Refused
Section titled “Connection Refused”- Check PostgreSQL is running:
systemctl status postgresql - Verify listen_addresses in postgresql.conf
- Check pg_hba.conf allows connection
Authentication Failed
Section titled “Authentication Failed”- Verify password is correct
- Check auth method in pg_hba.conf
- Ensure user exists:
\duin psql
Performance Issues
Section titled “Performance Issues”- Check for long-running queries
- Run
ANALYZEon affected tables - Review query plans with
EXPLAIN ANALYZE
Next Steps
Section titled “Next Steps”- Migrations - Database schema management
- Connection Pooling - Optimize connections
- Maintenance - Ongoing maintenance
