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
Using Let’s Encrypt (Recommended)
Let’s Encrypt provides free SSL certificates with automatic renewal.
Install Certbot
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
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)
Verify certificate installation
sudo certbot certificates
Check the expiry date and renewal status.Test automatic renewal
sudo certbot renew --dry-run
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:
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/
Set proper permissions
sudo chmod 600 /etc/ssl/appflowy/your-private-key.key
sudo chmod 644 /etc/ssl/appflowy/your-certificate.crt
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
}
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
# 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
# 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)
Data Encryption
Encryption at Rest
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"
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
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:
Configure default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
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
Restrict database access
# Only allow from application server
sudo ufw allow from 10.0.0.0/8 to any port 5432
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
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
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
Schedule with cron
Add daily backup at 2 AM:0 2 * * * /usr/local/bin/backup-appflowy.sh >> /var/log/appflowy-backup.log 2>&1
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
# Sync to remote server
rsync -avz --delete /backup/appflowy/ \
[email protected]:/backups/appflowy/
# 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
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:
Install Fail2ban
sudo apt install fail2ban -y
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
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:
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:
Document procedures
Create an incident response plan including:
- Contact information for security team
- Escalation procedures
- Containment strategies
- Recovery procedures
Regular drills
Practice incident response procedures quarterly.
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