Skip to main content

Security Overview

Securing your self-hosted AppFlowy instance is critical to protect your data and ensure compliance with security standards.

Network Security

SSL/TLS encryption and firewall configuration

Authentication

Strong authentication and access controls

Data Protection

Encryption at rest and in transit

Monitoring

Audit logs and security monitoring

SSL/TLS Configuration

Let’s Encrypt provides free SSL certificates with automatic renewal.
1

Install Certbot

sudo apt update
sudo apt install certbot python3-certbot-nginx -y
2

Obtain SSL certificate

sudo certbot --nginx -d appflowy.yourdomain.com
Follow the interactive prompts:
  • Enter your email address
  • Agree to terms of service
  • Choose whether to redirect HTTP to HTTPS (recommended: Yes)
3

Verify certificate installation

sudo certbot certificates
Check the expiry date and renewal status.
4

Test automatic renewal

sudo certbot renew --dry-run
5

Configure auto-renewal

Certbot automatically sets up a systemd timer. Verify it:
sudo systemctl status certbot.timer
Ensure ports 80 and 443 are open in your firewall before obtaining certificates.

Using Custom SSL Certificates

If you have your own SSL certificates:
1

Copy certificates to the server

sudo mkdir -p /etc/ssl/appflowy
sudo cp your-certificate.crt /etc/ssl/appflowy/
sudo cp your-private-key.key /etc/ssl/appflowy/
sudo cp ca-bundle.crt /etc/ssl/appflowy/
2

Set proper permissions

sudo chmod 600 /etc/ssl/appflowy/your-private-key.key
sudo chmod 644 /etc/ssl/appflowy/your-certificate.crt
3

Update Nginx configuration

Edit /etc/nginx/sites-available/appflowy:
server {
    listen 443 ssl http2;
    server_name appflowy.yourdomain.com;
    
    ssl_certificate /etc/ssl/appflowy/your-certificate.crt;
    ssl_certificate_key /etc/ssl/appflowy/your-private-key.key;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
    # ... rest of configuration
}
4

Test and reload Nginx

sudo nginx -t
sudo systemctl reload nginx

SSL Best Practices

Enhanced SSL/TLS configuration for maximum security:
# Strong SSL Configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;

# Enable HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

# Disable SSL session tickets
ssl_session_tickets off;

# Enable OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/appflowy/ca-bundle.crt;

# Configure DH parameters
ssl_dhparam /etc/ssl/dhparam.pem;
Generate DH parameters:
sudo openssl dhparam -out /etc/ssl/dhparam.pem 4096

Authentication Configuration

Strong Password Policies

Enforce strong passwords in GoTrue configuration:
# Minimum password length
GOTRUE_PASSWORD_MIN_LENGTH=12

# Require special characters
GOTRUE_PASSWORD_REQUIRED_CHARACTERS=lower,upper,number,special

Multi-Factor Authentication (MFA)

Enable MFA for enhanced security:
# Enable MFA
GOTRUE_MFA_ENABLED=true

# Supported MFA methods
GOTRUE_MFA_METHODS=totp,sms

# Require MFA for all users
GOTRUE_MFA_REQUIRED=true
MFA significantly reduces the risk of unauthorized access, even if passwords are compromised.

Session Management

Configure secure session handling:
# JWT expiration (1 hour)
GOTRUE_JWT_EXP=3600

# Refresh token expiration (7 days)
GOTRUE_REFRESH_TOKEN_EXP=604800

# Require re-authentication for sensitive operations
GOTRUE_SECURITY_REQUIRE_REAUTH=true

Single Sign-On (SSO)

Integrate with your organization’s SSO:
# SAML Configuration
GOTRUE_SAML_ENABLED=true
GOTRUE_SAML_METADATA_URL=https://sso.company.com/metadata
GOTRUE_SAML_ENTITY_ID=appflowy.company.com
GOTRUE_SAML_SSO_URL=https://sso.company.com/saml/sso
GOTRUE_SAML_CERTIFICATE=/etc/appflowy/saml-cert.pem

Data Encryption

Encryption at Rest

1

Enable PostgreSQL encryption

Use encrypted volumes for database storage:
services:
  postgres:
    volumes:
      - /encrypted/volume/postgres:/var/lib/postgresql/data
Or use PostgreSQL’s built-in encryption:
# Enable data encryption
POSTGRES_INITDB_ARGS="--data-checksums"
2

Encrypt S3 storage

For MinIO:
# Enable server-side encryption
MINIO_SERVER_SIDE_ENCRYPTION=on
MINIO_KMS_SECRET_KEY=your-32-byte-hex-key
For AWS S3:
S3_SERVER_SIDE_ENCRYPTION=AES256
# Or use KMS
S3_SERVER_SIDE_ENCRYPTION=aws:kms
S3_SSE_KMS_KEY_ID=your-kms-key-id
3

Encrypt Redis persistence

# Use encrypted volumes
services:
  redis:
    volumes:
      - /encrypted/volume/redis:/data

Encryption in Transit

All communication should use TLS:
# Enforce HTTPS
ENFORCE_HTTPS=true

# Secure WebSocket connections
WS_REQUIRE_TLS=true

# Database connections
POSTGRES_SSL_MODE=require

# Redis TLS
REDIS_TLS_ENABLED=true
Never transmit credentials or sensitive data over unencrypted connections.

Firewall Configuration

Configure firewall rules to limit access:
1

Install UFW (Ubuntu)

sudo apt install ufw -y
2

Configure default policies

sudo ufw default deny incoming
sudo ufw default allow outgoing
3

Allow necessary ports

# SSH (change 22 if using custom port)
sudo ufw allow 22/tcp

# HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
4

Restrict database access

# Only allow from application server
sudo ufw allow from 10.0.0.0/8 to any port 5432
5

Enable firewall

sudo ufw enable
sudo ufw status verbose

Docker Network Isolation

Isolate services using Docker networks:
services:
  appflowy-server:
    networks:
      - frontend
      - backend
      
  postgres:
    networks:
      - backend
    # Not exposed to frontend network
    
  redis:
    networks:
      - backend
      
  nginx:
    networks:
      - frontend
    ports:
      - "80:80"
      - "443:443"

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No external access

Security Headers

Add security headers in Nginx:
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

# Remove server version
server_tokens off;

Backup Recommendations

Automated Database Backups

1

Create backup script

Create /usr/local/bin/backup-appflowy.sh:
#!/bin/bash
BACKUP_DIR="/backup/appflowy"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Backup PostgreSQL
docker compose exec -T postgres pg_dump -U appflowy appflowy | \
  gzip > "$BACKUP_DIR/postgres_$TIMESTAMP.sql.gz"

# Backup MinIO data
docker compose exec -T minio mc mirror local/appflowy-storage \
  "$BACKUP_DIR/storage_$TIMESTAMP/"

# Backup configuration
cp .env "$BACKUP_DIR/env_$TIMESTAMP.backup"

# Remove backups older than 30 days
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete

echo "Backup completed: $TIMESTAMP"
Make it executable:
sudo chmod +x /usr/local/bin/backup-appflowy.sh
2

Schedule with cron

sudo crontab -e
Add daily backup at 2 AM:
0 2 * * * /usr/local/bin/backup-appflowy.sh >> /var/log/appflowy-backup.log 2>&1
3

Test backup restoration

# Test database restore
gunzip < backup.sql.gz | docker compose exec -T postgres psql -U appflowy appflowy

Off-Site Backup Storage

Store backups remotely for disaster recovery:
# Install AWS CLI
sudo apt install awscli -y

# Configure credentials
aws configure

# Sync backups to S3
aws s3 sync /backup/appflowy s3://your-backup-bucket/appflowy/ --delete
Encrypt backups before storing off-site. Test your backup restoration process regularly.

Audit Logging

Enable comprehensive audit logging:
# Enable audit logs
ENABLE_AUDIT_LOG=true
AUDIT_LOG_LEVEL=info
AUDIT_LOG_FILE=/var/log/appflowy/audit.log

# Log authentication events
LOG_AUTH_EVENTS=true

# Log data access
LOG_DATA_ACCESS=true

# Log administrative actions
LOG_ADMIN_ACTIONS=true

Centralized Logging

Forward logs to a centralized system:
services:
  appflowy-server:
    logging:
      driver: syslog
      options:
        syslog-address: "tcp://log-server.company.com:514"
        tag: "appflowy"

Security Monitoring

Intrusion Detection

Install and configure Fail2ban:
1

Install Fail2ban

sudo apt install fail2ban -y
2

Configure for Nginx

Create /etc/fail2ban/jail.local:
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log

[nginx-noscript]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log

[nginx-badbots]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
3

Restart Fail2ban

sudo systemctl restart fail2ban
sudo fail2ban-client status

Security Scanning

Regularly scan for vulnerabilities:
# Scan Docker images
docker scan appflowy/appflowy:latest

# Update dependencies
docker compose pull
docker compose up -d

Compliance & Standards

GDPR Compliance

  • Enable data export functionality
  • Implement data deletion procedures
  • Maintain audit logs for data access
  • Document data processing activities

SOC 2

  • Implement access controls
  • Enable comprehensive logging
  • Regular security assessments
  • Incident response procedures

HIPAA

  • Encrypt all PHI data
  • Implement BAA agreements
  • Audit trail requirements
  • Regular risk assessments

ISO 27001

  • Information security policies
  • Risk management framework
  • Security awareness training
  • Continuous improvement

Security Checklist

Use this checklist to verify your security configuration:
  • SSL/TLS certificates installed and auto-renewal configured
  • Firewall rules configured to restrict access
  • Strong passwords enforced (12+ characters)
  • Multi-factor authentication enabled
  • Database encryption at rest enabled
  • Regular automated backups configured
  • Off-site backup storage configured
  • Audit logging enabled
  • Security headers configured
  • Docker network isolation implemented
  • Fail2ban or similar IDS installed
  • Regular security updates scheduled
  • Incident response plan documented
  • Regular security assessments scheduled

Security Best Practices

Principle of Least Privilege

Grant users only the minimum permissions necessary for their role.

Regular Updates

Keep all components updated with the latest security patches.

Defense in Depth

Implement multiple layers of security controls.

Security Monitoring

Continuously monitor for security events and anomalies.

Incident Response

Prepare for security incidents:
1

Document procedures

Create an incident response plan including:
  • Contact information for security team
  • Escalation procedures
  • Containment strategies
  • Recovery procedures
2

Regular drills

Practice incident response procedures quarterly.
3

Post-incident review

After any security event, conduct a review and update procedures.
Security is an ongoing process, not a one-time setup. Regularly review and update your security posture.

Getting Help

Report Security Issues

Report security vulnerabilities responsibly

Community Support

Join our Discord for security discussions

Documentation

Review self-hosting documentation

Professional Services

Contact us for security consulting

Build docs developers (and LLMs) love