Security Best Practices
Secure your Mist installation in production.
Server Security
Firewall Configuration
Configure firewall to allow only necessary ports:
# UFW example (Ubuntu/Debian)
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (change 22 if using custom port)
sudo ufw allow 22/tcp
# Allow HTTP and HTTPS (required for web access and SSL challenges)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Allow Mist API (if accessing directly, otherwise only localhost)
sudo ufw allow 8080/tcp
# Optional: Allow Traefik dashboard (restrict to specific IPs in production)
sudo ufw allow 8081/tcp
# Enable firewall
sudo ufw enable
# Verify rules
sudo ufw status numberedProduction Firewall Best Practices:
# Restrict Mist API to localhost only (recommended if using Traefik)
sudo ufw delete allow 8080/tcp
sudo ufw allow from 127.0.0.1 to any port 8080
# Restrict Traefik dashboard to localhost only
sudo ufw delete allow 8081/tcp
sudo ufw allow from 127.0.0.1 to any port 8081
# Or allow only from specific admin IP
sudo ufw allow from YOUR_ADMIN_IP to any port 8081
# Allow SSH only from specific IP (very secure)
sudo ufw delete allow 22/tcp
sudo ufw allow from YOUR_ADMIN_IP to any port 22SSH Hardening
# Disable root login
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# Disable password auth (use SSH keys only)
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
# Restart SSH
sudo systemctl restart sshdKeep System Updated
# Ubuntu/Debian
sudo apt update && sudo apt upgrade -y
# Enable automatic security updates
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgradesMist Security
Strong Passwords
Enforce strong password requirements for all users:
- Minimum length: 12 characters (16+ recommended)
- Complexity: Mix of uppercase, lowercase, numbers, and symbols
- No common passwords: Avoid dictionary words, names, dates
- Use password manager: 1Password, Bitwarden, LastPass
- Unique per account: Never reuse passwords
Owner Account Security:
- The first user account becomes the Owner with full system access
- Use an extremely strong password for the Owner account
- Consider using a hardware security key (coming soon)
JWT Secret
Hardcoded JWT Secret
Currently, the JWT secret is hardcoded in the application (server/api/middleware/auth.go:14). This is a security risk for production deployments.
Workaround: Modify the code before deployment:
cd /opt/mist/server/api/middleware
# Edit auth.go and change line 14 to use a strong random value
# Then rebuild: cd /opt/mist/server && go build -o ../bin/server main.goUpcoming: Configurable JWT secret via environment variable.
Generate a strong JWT secret:
# Generate random 64-character secret
openssl rand -hex 32
# Or use this one-liner
openssl rand -base64 48 | tr -d "=+/" | cut -c1-64Session Security
- Session duration: 31 days (hardcoded)
- Sessions are stored as JWT tokens
- Token expiry: Automatically logged out after 31 days
- No session revocation: Currently, there's no way to force-logout users (coming soon)
GitHub Webhook Secret
GitHub webhook requests are validated using HMAC-SHA256 signatures.
How it works:
- Webhook secret is automatically generated when creating GitHub App
- Stored securely in Mist database
- All incoming webhook requests are validated before processing
- Invalid signatures are rejected
Generate a strong webhook secret if creating manually:
# Generate webhook secret (only needed for manual setup)
openssl rand -hex 32Configure in: Settings → Integrations → GitHub App (automatic during app creation)
Docker Security
Socket Permissions
The Mist backend requires access to the Docker socket to manage containers:
# Verify Docker socket permissions
ls -la /var/run/docker.sock
# Should show: srw-rw---- 1 root docker
# Add your user to docker group (done during installation)
sudo usermod -aG docker $USER
# Log out and back in for group changes to take effectSecurity Consideration
Access to the Docker socket = root-level access to the host system. The user running Mist can:
- Create privileged containers
- Mount host filesystem
- Escape container isolation
Mitigations:
- Run Mist as a non-root user (recommended, default in install script)
- Never expose Mist API publicly without authentication
- Use Docker rootless mode (advanced, requires configuration)
- Monitor Docker events for suspicious activity
Container Isolation
Applications deployed by Mist run in Docker containers with:
- Network isolation: Apps on
traefik-netfor controlled routing - Resource limits: (coming soon - CPU/memory limits)
- Read-only filesystems: (coming soon)
- Non-root users: Depends on Dockerfile used
Best Practices for Application Dockerfiles:
# Use specific versions, not :latest
FROM node:20-alpine
# Run as non-root user
RUN addgroup -g 1001 -S appuser && \
adduser -S appuser -u 1001
USER appuser
# Use multi-stage builds to reduce attack surface
# Copy only necessary files
# Scan images for vulnerabilitiesImage Security
- Official base images: Use official Docker images (node, python, golang, etc.)
- Image scanning: (coming soon - automatic vulnerability scanning)
- Keep images updated: Rebuild periodically with latest base images
- Minimize layers: Combine RUN commands to reduce image size
- No secrets in images: Never
COPYor embed secrets in Dockerfiles
Scan images manually:
# Install Trivy (vulnerability scanner)
sudo apt install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt update
sudo apt install trivy
# Scan an image
trivy image your-app-image:latestNetwork Security
Reverse Proxy
- Always use Traefik as reverse proxy
- Never expose application ports directly
- Configure proper CORS headers
SSL/TLS
Mist provides automatic SSL/TLS certificate provisioning and management.
Current Features:
- ✅ Automatic SSL certificate issuance via Let's Encrypt
- ✅ Automatic certificate renewal (90-day certificates, renewed at 60 days)
- ✅ HTTP to HTTPS redirect enabled by default for domains
- ✅ TLS 1.2+ encryption (configured by Traefik v3.1)
- ✅ Modern cipher suites
- ✅ Perfect Forward Secrecy (PFS)
How it Works:
- User adds domain to application in Mist UI
- Mist updates Traefik configuration with domain routing
- Traefik automatically requests certificate from Let's Encrypt
- Let's Encrypt verifies domain ownership via HTTP-01 challenge (port 80)
- Certificate stored in
/opt/mist/letsencrypt/acme.json - Traefik serves traffic over HTTPS with automatic HTTP redirect
Certificate Storage:
# View certificate file
sudo ls -la /opt/mist/letsencrypt/acme.json
# Should show: -rw------- (600 permissions)
# Backup certificates
sudo cp /opt/mist/letsencrypt/acme.json /var/backups/acme_$(date +%Y%m%d).jsonVerify SSL Configuration:
# Test SSL connection
openssl s_client -connect your-domain.com:443 -servername your-domain.com
# Check certificate expiry
echo | openssl s_client -servername your-domain.com -connect your-domain.com:443 2>/dev/null | openssl x509 -noout -dates
# Use SSL Labs for comprehensive analysis
# https://www.ssllabs.com/ssltest/analyze.html?d=your-domain.comLearn more about SSL automation →
Coming Soon:
- Wildcard SSL certificates (
*.example.com) - Custom certificate upload
- HSTS headers and security policies
- Certificate expiry notifications
- mTLS (mutual TLS) for service-to-service communication
Database Security
SQLite File Permissions
The SQLite database contains ALL Mist data including secrets. Protect it carefully:
# Check current permissions
ls -la /var/lib/mist/mist.db
# Set restrictive permissions (read/write for owner only)
sudo chmod 600 /var/lib/mist/mist.db
# Ensure owned by the user running Mist (not root!)
sudo chown $USER:$USER /var/lib/mist/mist.db
# Verify
ls -la /var/lib/mist/mist.db
# Should show: -rw------- 1 youruser youruserDatabase Encryption
Database Not Encrypted
SQLite database is currently stored in plaintext on disk. This means:
- Anyone with file access can read the database
- All secrets (API keys, tokens, env vars) are visible
- Backups should be encrypted separately
Mitigations:
- Encrypt the entire disk/volume (LUKS, dm-crypt)
- Encrypt backups before uploading to cloud storage
- Restrict server access to trusted administrators only
- Use encrypted backup destinations (encrypted S3 buckets, etc.)
Encrypt backups:
# Using GPG
gpg --symmetric --cipher-algo AES256 /var/backups/mist_backup.db
# Using OpenSSL
openssl enc -aes-256-cbc -salt -in /var/backups/mist_backup.db -out /var/backups/mist_backup.db.enc
# Decrypt when needed
openssl enc -d -aes-256-cbc -in /var/backups/mist_backup.db.enc -out /var/backups/mist_backup.dbBackup Security
# Automated encrypted backup script
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/backups/mist"
DB_FILE="/var/lib/mist/mist.db"
ENCRYPTION_KEY="your-encryption-passphrase" # Store securely!
# Hot backup
sqlite3 $DB_FILE ".backup $BACKUP_DIR/mist_$DATE.db"
# Encrypt backup
openssl enc -aes-256-cbc -salt -pbkdf2 \
-in $BACKUP_DIR/mist_$DATE.db \
-out $BACKUP_DIR/mist_$DATE.db.enc \
-pass pass:"$ENCRYPTION_KEY"
# Remove unencrypted backup
rm $BACKUP_DIR/mist_$DATE.db
# Keep last 30 days
find $BACKUP_DIR -name "mist_*.db.enc" -mtime +30 -deleteSee Backup & Recovery for complete backup procedures.
Application Security
Environment Variables & Secrets
Environment variables can contain sensitive data (API keys, database passwords, etc.):
Security Best Practices:
# Never commit secrets to Git repositories
# Add .env to .gitignore
# Never log secrets
# Avoid console.log() or print() statements with env vars
# Rotate secrets regularly
# Change API keys every 90 days or after team member leaves
# Use strong random values
openssl rand -hex 32How Mist Handles Secrets:
- Environment variables stored in SQLite database (plaintext)
- Passed to containers at deployment time via Docker
-eflag - Also passed as
--build-argduring image builds - Visible in
docker inspectoutput on the host
Secrets Visibility
Environment variables are:
- Stored in plaintext in the database
- Visible to anyone with access to the Mist database or Docker host
- Passed to build process (avoid using secrets during build)
Upcoming: Secret encryption at rest and secret management integration (Vault, AWS Secrets Manager)
Minimize Secret Exposure:
Don't use secrets in Dockerfile ARG: They're stored in image layers
dockerfile# BAD - Secret visible in image history ARG API_KEY RUN curl -H "Authorization: $API_KEY" https://api.example.com/setup # GOOD - Fetch at runtime CMD node app.js # App reads API_KEY from process.env at runtimeUse secret management for databases: Connect to external secret managers at runtime
Limit access: Only give secrets to apps that need them
Audit Logging
Mist tracks important actions in the audit log:
What's Logged:
- User authentication (login/logout)
- Application creation/deletion
- Deployments
- Domain changes
- Environment variable changes
- Project member changes
- System settings changes
Access Audit Logs:
- Navigate to Settings → Audit Logs in the UI
- Or query database:
SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 100
Security Monitoring:
# View recent audit logs via database
sqlite3 /var/lib/mist/mist.db "SELECT user_id, action, resource_type, created_at FROM audit_logs ORDER BY created_at DESC LIMIT 50;"What to Monitor:
- Failed login attempts (possible brute force)
- Unusual deployment times (after hours activity)
- Unexpected user creations
- Permission changes
- Bulk deletions
TIP
Set up alerts for critical actions (coming soon). For now, periodically review audit logs manually.
Monitoring & Incident Response
Log Monitoring
Monitor system and application logs for security events:
# Watch Mist backend logs in real-time
sudo journalctl -u mist -f
# Filter for authentication events
sudo journalctl -u mist | grep -i "login\|auth\|failed"
# Watch Traefik access logs
docker logs -f traefik
# Monitor all Docker container activity
docker events
# Check for unauthorized container creation
docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.CreatedAt}}"System Monitoring
Monitor resource usage for anomalies:
# Monitor disk space (database growth, logs, containers)
df -h
du -sh /var/lib/mist/*
docker system df
# Monitor memory usage
free -h
docker stats --no-stream
# Monitor CPU usage
top -bn1 | head -20
# Check Docker daemon resource usage
ps aux | grep dockerdSecurity Alerts
Set up alerts for critical events (manual for now, automated coming soon):
Monitor for:
- Multiple failed login attempts
- Unusual deployment times
- High resource usage (potential crypto mining)
- New user creations
- Permission escalations
- Database file modifications
- Firewall rule changes
Simple alerting script example:
#!/bin/bash
# /usr/local/bin/mist-security-alert.sh
# Check for failed logins in last hour
FAILED_LOGINS=$(sudo journalctl -u mist --since "1 hour ago" | grep -c "authentication failed")
if [ $FAILED_LOGINS -gt 10 ]; then
echo "WARNING: $FAILED_LOGINS failed login attempts in the last hour" | \
mail -s "Mist Security Alert" admin@example.com
fi
# Check database size growth (possible data exfiltration)
DB_SIZE=$(stat -f%z /var/lib/mist/mist.db 2>/dev/null || stat -c%s /var/lib/mist/mist.db)
if [ $DB_SIZE -gt 1073741824 ]; then # 1GB
echo "WARNING: Database size exceeds 1GB" | \
mail -s "Mist Database Alert" admin@example.com
fiIncident Response
If you suspect a security incident:
Isolate: Stop Mist and Traefik immediately
bashsudo systemctl stop mist docker compose -f /opt/mist/traefik-compose.yml downPreserve Evidence: Backup current state before changes
bashsqlite3 /var/lib/mist/mist.db ".backup /tmp/incident_db_$(date +%Y%m%d_%H%M%S).db" sudo journalctl -u mist > /tmp/incident_logs_$(date +%Y%m%d_%H%M%S).log docker ps -a > /tmp/incident_containers_$(date +%Y%m%d_%H%M%S).txtInvestigate: Check audit logs, system logs, container logs
Remediate: Change passwords, rotate secrets, patch vulnerabilities
Restore: From clean backup if compromised
Report: If vulnerability in Mist itself, report to maintainers
Coming Soon
The following security features are planned for future releases:
Authentication & Authorization:
- Two-Factor Authentication (TOTP/WebAuthn)
- SSO/SAML integration
- OAuth2 provider support
- API key management with scopes
- Session management (force logout, view active sessions)
Secrets Management:
- Environment variable encryption at rest
- Integration with HashiCorp Vault
- AWS Secrets Manager integration
- Secret rotation policies
- Secret scanning in code repositories
Network Security:
- Rate limiting per IP/user
- IP whitelisting for admin access
- Custom security headers (CSP, HSTS, X-Frame-Options)
- Web Application Firewall (WAF) integration
- DDoS protection configuration
Application Security:
- Automated vulnerability scanning for Docker images
- Security policy enforcement (required base images, etc.)
- Container resource limits (CPU, memory, network)
- Read-only container filesystems
- Seccomp profiles and AppArmor
Monitoring & Compliance:
- Security dashboard and metrics
- Automated security alerts (email, Slack, webhook)
- Compliance reporting (SOC 2, ISO 27001)
- Security audit trail export
- Real-time threat detection
Data Protection:
- Database encryption at rest
- Backup encryption by default
- Automated backup integrity verification
- Point-in-time recovery
- Data retention policies
Security Checklist
Use this checklist to ensure your Mist installation is properly secured:
Server Security
- [ ] Firewall configured and enabled (UFW/iptables)
- [ ] Only necessary ports open (22, 80, 443, 8080, 8081)
- [ ] Mist API (8080) and Traefik dashboard (8081) restricted to localhost or specific IPs
- [ ] SSH hardened (key-only auth, no root login)
- [ ] Automatic security updates enabled
- [ ] System packages up to date
- [ ] Disk encryption enabled (optional but recommended for sensitive data)
Mist Security
- [ ] Strong passwords enforced for all users (12+ characters)
- [ ] Owner account uses extremely strong password
- [ ] JWT secret changed from hardcoded value (requires code modification)
- [ ] GitHub webhook secret configured and validated
- [ ] Regular security updates applied to Mist
Docker Security
- [ ] Mist running as non-root user
- [ ] User in docker group (but aware of security implications)
- [ ] Docker socket permissions restricted (660)
- [ ] Containers use official base images only
- [ ] Images periodically scanned for vulnerabilities
- [ ] Unnecessary containers removed regularly
Database Security
- [ ] Database file permissions locked down (600)
- [ ] Database owned by correct user (not root)
- [ ] Automated backups configured
- [ ] Backups stored securely (encrypted and offsite)
- [ ] Backup restoration tested regularly
Network Security
- [ ] SSL/TLS enabled for all public domains
- [ ] Certificates automatically renewing
- [ ] HTTP automatically redirects to HTTPS
- [ ] Traefik dashboard access restricted
- [ ] No application ports exposed directly (all through Traefik)
Application Security
- [ ] No secrets committed to Git repositories
- [ ] Environment variables contain only necessary data
- [ ] Secrets rotated regularly (90 days)
- [ ] Audit logs reviewed periodically
- [ ] Suspicious activity monitored
Monitoring & Response
- [ ] Log monitoring configured
- [ ] Disk space alerts set up
- [ ] Resource usage monitored
- [ ] Incident response plan documented
- [ ] Emergency contacts updated
Compliance (if applicable)
- [ ] Data retention policy defined
- [ ] User data handling documented
- [ ] Privacy policy published
- [ ] Terms of service published
- [ ] GDPR/compliance requirements met
Reporting Security Issues
Found a security vulnerability in Mist?
Please report responsibly:
- DO NOT open a public GitHub issue for security vulnerabilities
- DO report via GitHub Security Advisories
- OR email: security@trymist.com (if available)
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will:
- Acknowledge receipt within 48 hours
- Provide estimated fix timeline
- Credit you in security advisory (if desired)
- Keep you updated on progress
Thank you for helping keep Mist secure!
