> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/AppFlowy-IO/AppFlowy/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> Secure your self-hosted AppFlowy deployment

## Security Overview

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

<CardGroup cols={2}>
  <Card title="Network Security" icon="network-wired">
    SSL/TLS encryption and firewall configuration
  </Card>

  <Card title="Authentication" icon="key">
    Strong authentication and access controls
  </Card>

  <Card title="Data Protection" icon="shield">
    Encryption at rest and in transit
  </Card>

  <Card title="Monitoring" icon="eye">
    Audit logs and security monitoring
  </Card>
</CardGroup>

## SSL/TLS Configuration

### Using Let's Encrypt (Recommended)

Let's Encrypt provides free SSL certificates with automatic renewal.

<Steps>
  <Step title="Install Certbot">
    ```bash theme={null}
    sudo apt update
    sudo apt install certbot python3-certbot-nginx -y
    ```
  </Step>

  <Step title="Obtain SSL certificate">
    ```bash theme={null}
    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)
  </Step>

  <Step title="Verify certificate installation">
    ```bash theme={null}
    sudo certbot certificates
    ```

    Check the expiry date and renewal status.
  </Step>

  <Step title="Test automatic renewal">
    ```bash theme={null}
    sudo certbot renew --dry-run
    ```
  </Step>

  <Step title="Configure auto-renewal">
    Certbot automatically sets up a systemd timer. Verify it:

    ```bash theme={null}
    sudo systemctl status certbot.timer
    ```
  </Step>
</Steps>

<Warning>
  Ensure ports 80 and 443 are open in your firewall before obtaining certificates.
</Warning>

### Using Custom SSL Certificates

If you have your own SSL certificates:

<Steps>
  <Step title="Copy certificates to the server">
    ```bash theme={null}
    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/
    ```
  </Step>

  <Step title="Set proper permissions">
    ```bash theme={null}
    sudo chmod 600 /etc/ssl/appflowy/your-private-key.key
    sudo chmod 644 /etc/ssl/appflowy/your-certificate.crt
    ```
  </Step>

  <Step title="Update Nginx configuration">
    Edit `/etc/nginx/sites-available/appflowy`:

    ```nginx theme={null}
    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
    }
    ```
  </Step>

  <Step title="Test and reload Nginx">
    ```bash theme={null}
    sudo nginx -t
    sudo systemctl reload nginx
    ```
  </Step>
</Steps>

### SSL Best Practices

Enhanced SSL/TLS configuration for maximum security:

```nginx theme={null}
# 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:

```bash theme={null}
sudo openssl dhparam -out /etc/ssl/dhparam.pem 4096
```

## Authentication Configuration

### Strong Password Policies

Enforce strong passwords in GoTrue configuration:

```bash theme={null}
# 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:

```bash theme={null}
# Enable MFA
GOTRUE_MFA_ENABLED=true

# Supported MFA methods
GOTRUE_MFA_METHODS=totp,sms

# Require MFA for all users
GOTRUE_MFA_REQUIRED=true
```

<Note>
  MFA significantly reduces the risk of unauthorized access, even if passwords are compromised.
</Note>

### Session Management

Configure secure session handling:

```bash theme={null}
# 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:

<Tabs>
  <Tab title="SAML 2.0">
    ```bash theme={null}
    # 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
    ```
  </Tab>

  <Tab title="OAuth 2.0">
    ```bash theme={null}
    # OAuth Configuration (Google)
    GOTRUE_OAUTH_GOOGLE_ENABLED=true
    GOTRUE_OAUTH_GOOGLE_CLIENT_ID=your-client-id
    GOTRUE_OAUTH_GOOGLE_CLIENT_SECRET=your-client-secret
    GOTRUE_OAUTH_GOOGLE_REDIRECT_URI=https://appflowy.yourdomain.com/auth/callback

    # OAuth Configuration (Microsoft)
    GOTRUE_OAUTH_AZURE_ENABLED=true
    GOTRUE_OAUTH_AZURE_CLIENT_ID=your-client-id
    GOTRUE_OAUTH_AZURE_CLIENT_SECRET=your-client-secret
    GOTRUE_OAUTH_AZURE_TENANT_ID=your-tenant-id
    ```
  </Tab>

  <Tab title="LDAP">
    ```bash theme={null}
    # LDAP Configuration
    GOTRUE_LDAP_ENABLED=true
    GOTRUE_LDAP_HOST=ldap.company.com
    GOTRUE_LDAP_PORT=636
    GOTRUE_LDAP_USE_SSL=true
    GOTRUE_LDAP_BASE_DN=dc=company,dc=com
    GOTRUE_LDAP_BIND_DN=cn=appflowy,ou=services,dc=company,dc=com
    GOTRUE_LDAP_BIND_PASSWORD=your-bind-password
    GOTRUE_LDAP_USER_FILTER=(uid=%s)
    ```
  </Tab>
</Tabs>

## Data Encryption

### Encryption at Rest

<Steps>
  <Step title="Enable PostgreSQL encryption">
    Use encrypted volumes for database storage:

    ```yaml theme={null}
    services:
      postgres:
        volumes:
          - /encrypted/volume/postgres:/var/lib/postgresql/data
    ```

    Or use PostgreSQL's built-in encryption:

    ```bash theme={null}
    # Enable data encryption
    POSTGRES_INITDB_ARGS="--data-checksums"
    ```
  </Step>

  <Step title="Encrypt S3 storage">
    For MinIO:

    ```bash theme={null}
    # Enable server-side encryption
    MINIO_SERVER_SIDE_ENCRYPTION=on
    MINIO_KMS_SECRET_KEY=your-32-byte-hex-key
    ```

    For AWS S3:

    ```bash theme={null}
    S3_SERVER_SIDE_ENCRYPTION=AES256
    # Or use KMS
    S3_SERVER_SIDE_ENCRYPTION=aws:kms
    S3_SSE_KMS_KEY_ID=your-kms-key-id
    ```
  </Step>

  <Step title="Encrypt Redis persistence">
    ```bash theme={null}
    # Use encrypted volumes
    services:
      redis:
        volumes:
          - /encrypted/volume/redis:/data
    ```
  </Step>
</Steps>

### Encryption in Transit

All communication should use TLS:

```bash theme={null}
# Enforce HTTPS
ENFORCE_HTTPS=true

# Secure WebSocket connections
WS_REQUIRE_TLS=true

# Database connections
POSTGRES_SSL_MODE=require

# Redis TLS
REDIS_TLS_ENABLED=true
```

<Warning>
  Never transmit credentials or sensitive data over unencrypted connections.
</Warning>

## Firewall Configuration

Configure firewall rules to limit access:

<Steps>
  <Step title="Install UFW (Ubuntu)">
    ```bash theme={null}
    sudo apt install ufw -y
    ```
  </Step>

  <Step title="Configure default policies">
    ```bash theme={null}
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    ```
  </Step>

  <Step title="Allow necessary ports">
    ```bash theme={null}
    # SSH (change 22 if using custom port)
    sudo ufw allow 22/tcp

    # HTTP/HTTPS
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    ```
  </Step>

  <Step title="Restrict database access">
    ```bash theme={null}
    # Only allow from application server
    sudo ufw allow from 10.0.0.0/8 to any port 5432
    ```
  </Step>

  <Step title="Enable firewall">
    ```bash theme={null}
    sudo ufw enable
    sudo ufw status verbose
    ```
  </Step>
</Steps>

### Docker Network Isolation

Isolate services using Docker networks:

```yaml theme={null}
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:

```nginx theme={null}
# 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

<Steps>
  <Step title="Create backup script">
    Create `/usr/local/bin/backup-appflowy.sh`:

    ```bash theme={null}
    #!/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:

    ```bash theme={null}
    sudo chmod +x /usr/local/bin/backup-appflowy.sh
    ```
  </Step>

  <Step title="Schedule with cron">
    ```bash theme={null}
    sudo crontab -e
    ```

    Add daily backup at 2 AM:

    ```cron theme={null}
    0 2 * * * /usr/local/bin/backup-appflowy.sh >> /var/log/appflowy-backup.log 2>&1
    ```
  </Step>

  <Step title="Test backup restoration">
    ```bash theme={null}
    # Test database restore
    gunzip < backup.sql.gz | docker compose exec -T postgres psql -U appflowy appflowy
    ```
  </Step>
</Steps>

### Off-Site Backup Storage

Store backups remotely for disaster recovery:

<Tabs>
  <Tab title="AWS S3">
    ```bash theme={null}
    # 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
    ```
  </Tab>

  <Tab title="rsync">
    ```bash theme={null}
    # Sync to remote server
    rsync -avz --delete /backup/appflowy/ \
      user@backup-server.com:/backups/appflowy/
    ```
  </Tab>

  <Tab title="Restic">
    ```bash theme={null}
    # Install restic
    sudo apt install restic -y

    # Initialize repository
    restic -r s3:s3.amazonaws.com/backup-bucket init

    # Backup
    restic -r s3:s3.amazonaws.com/backup-bucket backup /backup/appflowy

    # Prune old backups
    restic -r s3:s3.amazonaws.com/backup-bucket forget --keep-daily 7 --keep-weekly 4 --prune
    ```
  </Tab>
</Tabs>

<Warning>
  Encrypt backups before storing off-site. Test your backup restoration process regularly.
</Warning>

## Audit Logging

Enable comprehensive audit logging:

```bash theme={null}
# 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:

```yaml theme={null}
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:

<Steps>
  <Step title="Install Fail2ban">
    ```bash theme={null}
    sudo apt install fail2ban -y
    ```
  </Step>

  <Step title="Configure for Nginx">
    Create `/etc/fail2ban/jail.local`:

    ```ini theme={null}
    [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
    ```
  </Step>

  <Step title="Restart Fail2ban">
    ```bash theme={null}
    sudo systemctl restart fail2ban
    sudo fail2ban-client status
    ```
  </Step>
</Steps>

### Security Scanning

Regularly scan for vulnerabilities:

```bash theme={null}
# Scan Docker images
docker scan appflowy/appflowy:latest

# Update dependencies
docker compose pull
docker compose up -d
```

## Compliance & Standards

<CardGroup cols={2}>
  <Card title="GDPR Compliance" icon="gavel">
    * Enable data export functionality
    * Implement data deletion procedures
    * Maintain audit logs for data access
    * Document data processing activities
  </Card>

  <Card title="SOC 2" icon="certificate">
    * Implement access controls
    * Enable comprehensive logging
    * Regular security assessments
    * Incident response procedures
  </Card>

  <Card title="HIPAA" icon="briefcase-medical">
    * Encrypt all PHI data
    * Implement BAA agreements
    * Audit trail requirements
    * Regular risk assessments
  </Card>

  <Card title="ISO 27001" icon="shield-check">
    * Information security policies
    * Risk management framework
    * Security awareness training
    * Continuous improvement
  </Card>
</CardGroup>

## 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

<CardGroup cols={2}>
  <Card title="Principle of Least Privilege" icon="user-lock">
    Grant users only the minimum permissions necessary for their role.
  </Card>

  <Card title="Regular Updates" icon="rotate">
    Keep all components updated with the latest security patches.
  </Card>

  <Card title="Defense in Depth" icon="layer-group">
    Implement multiple layers of security controls.
  </Card>

  <Card title="Security Monitoring" icon="bell">
    Continuously monitor for security events and anomalies.
  </Card>
</CardGroup>

## Incident Response

Prepare for security incidents:

<Steps>
  <Step title="Document procedures">
    Create an incident response plan including:

    * Contact information for security team
    * Escalation procedures
    * Containment strategies
    * Recovery procedures
  </Step>

  <Step title="Regular drills">
    Practice incident response procedures quarterly.
  </Step>

  <Step title="Post-incident review">
    After any security event, conduct a review and update procedures.
  </Step>
</Steps>

<Warning>
  Security is an ongoing process, not a one-time setup. Regularly review and update your security posture.
</Warning>

## Getting Help

<CardGroup cols={2}>
  <Card title="Report Security Issues" icon="bug" href="mailto:security@appflowy.io">
    Report security vulnerabilities responsibly
  </Card>

  <Card title="Community Support" icon="users" href="https://discord.gg/9Q2xaN37tV">
    Join our Discord for security discussions
  </Card>

  <Card title="Documentation" icon="book" href="/self-hosting/overview">
    Review self-hosting documentation
  </Card>

  <Card title="Professional Services" icon="headset" href="https://appflowy.io/contact">
    Contact us for security consulting
  </Card>
</CardGroup>
