1. Encryption - Generate a random key

    1. Can be done using any method, including just entering random characters - KEEP A BACKUP
    2. Example Nginx Config
    server {
    	listen 80;
    	listen [::]:80;
    	listen 443 ssl http2;
    	listen [::]:443 ssl http2;
    	ssl_certificate /etc/letsencrypt/live/yourwebsite/fullchain.pem;
    	ssl_certificate_key /etc/letsencrypt/live/yourwebsite/privkey.pem;
    
    	include /etc/letsencrypt/options-ssl-nginx.conf;
    
    	root /var/www/OBrians/dist;
    
    	autoindex on;
    	# Add index.php to the list if you are using PHP
    	index index.html index.htm;
    
    	server_name yourwebsite.com www.yourwebsite.com;
    
    	location / {
    		# First attempt to serve request as file, then
    		# as directory, then fall back to displaying a 404.
    		try_files $uri $uri/ /index.html;
    	}
    }
    
    server {
    	listen 80;
    	listen [::]:80;
    	listen 443 ssl http2;
    	listen [::]:443 ssl http2;
    	ssl_certificate /etc/letsencrypt/live/yourwebsite.com/fullchain.pem;
    	ssl_certificate_key /etc/letsencrypt/live/yourwebsite.com/privkey.pem;
    
    	include /etc/letsencrypt/options-ssl-nginx.conf;
    
    	server_name appwrite.yourwebsite.com www.appwrite.yourwebsite.com;
    
    	location / {
    		proxy_set_header Host $host;
    		proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    		proxy_connect_timeout 7d;
        proxy_send_timeout 7d;
        proxy_read_timeout 7d;
    		proxy_pass <https://localhost:6943>;
    	}
    }
    
  2. Limiting Console Access - Limit by Email (configured in docker-compose file)

  3. Scaling: https://dev.to/appwrite/30daysofappwrite-docker-swarm-integration-2io9

  4. Rate Limits - Enabled by default

  5. Emails: https://appwrite.io/docs/email-delivery

  6. Backups: https://dev.to/appwrite/appwrite-in-production-backups-and-restores-4beg

    1. docker compose exec mariadb sh -c 'exec mysqldump --all-databases
    2. docker-compose exec -T mariadb sh -c 'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD"' < dump.sql
    3. Before running these commands is it highly recommended to shutdown your Appwrite instance to ensure you get a complete backup.
    4. mkdir -p backup && docker run --rm --volumes-from "$(docker-compose ps -q appwrite)" -v $PWD/backup:/backup ubuntu bash -c "cd /storage/functions && tar cvf /backup/functions.tar ."
    5. mkdir -p backup && docker run --rm --volumes-from "$(docker-compose ps -q appwrite)" -v $PWD/backup:/backup ubuntu bash -c "cd /storage/uploads && tar cvf /backup/uploads.tar ."

    Restoring

    1. Restoring your Appwrite volumes is fairly simple as well. Move the backup folder you just created to your destination machine next to the docker-compose.yml file and simply run the following commands to restore the backup.
    2. docker run --rm --volumes-from "$(docker-compose ps -q appwrite)" -v $PWD/backup:/restore ubuntu bash -c "cd /storage/functions && tar xvf /restore/functions.tar --strip 1"
    3. docker run --rm --volumes-from "$(docker-compose ps -q appwrite)" -v $PWD/backup:/restore ubuntu bash -c "cd /storage/uploads && tar xvf /restore/uploads.tar --strip 1"
  7. Size of Server: Probably it will be more efficient having multiple instances, however most times vertical scaling will be enough without needing to setup different instances. If you need scaling, then go for vertical scaling rather than having a thousand of different appwrite instances that could make it more difficult to maintain. One of the best approach to horizontal scaling is

  8. Transferring: https://gist.github.com/Meldiron/47b5851663668102a676aff43c6341f7

    1. Backup
    # Make sure to stop Appwrite before this backup,
    # and make sure you have enough space on the machine.
    
    # After backing up, make sure there is a file in 'backups/backup-___.tar.gz'.
    # Also please check size of this file, it should be at least 5kb, even for small instances.
    
    docker run --rm \\
      -v appwrite_appwrite-mariadb:/backup/appwrite-mariadb \\
      -v appwrite_appwrite-redis:/backup/appwrite-redis \\
      -v appwrite_appwrite-cache:/backup/appwrite-cache \\
      -v appwrite_appwrite-uploads:/backup/appwrite-uploads \\
      -v appwrite_appwrite-certificates:/backup/appwrite-certificates \\
      -v appwrite_appwrite-functions:/backup/appwrite-functions \\
      -v appwrite_appwrite-influxdb:/backup/appwrite-influxdb \\
      -v appwrite_appwrite-config:/backup/appwrite-config \\
      -v appwrite_appwrite-builds:/backup/appwrite-builds \\
      -v appwrite_appwrite-executor:/backup/appwrite-executor \\
      -v $(pwd)/.env:/backup/appwrite/.env \\
      -v $(pwd)/docker-compose.yml:/backup/appwrite/docker-compose.yml \\
      -v $(pwd)/backups:/archive \\
      --env BACKUP_FILENAME="backup-%Y-%m-%dT%H-%M-%S.tar.gz" \\
      --entrypoint backup \\
      offen/docker-volume-backup:latest
    

    b. Restore

    # Contributors:
    # - Matej Bačo (Meldiron): <https://github.com/meldiron>
    # - AidsMcGhee: <https://github.com/JakeAi>
    
    # Make sure the Appwrite did NOT run on this server previously,
    # and make sure to stop it before this restore.
    # If appwrite ran here already, make sure to
    # stop Appwrite with 'docker-compose down -v', and ideally
    # also remove appwrite folder.
    
    # Before running, be in any directory,
    # but make sure 'backup.tar.gz' file with your backup is in there.
    # Whichever directory you are in, this script will create 'appwrite'
    # folder in here, with a configuration from backup.
    
    # Backup script puts date in the file name, make sure to
    # rename file to exactly 'backup.tar.gz'.
    
    # After restore, you can enter appwite folder 'cd appwrite'
    # and start Appwrite with 'docker-compose up -d'.
    
    # Untar backup
    tar -C /tmp -xvf backup.tar.gz
    
    # Restore volumes and configuration
    docker run -d --name temp_restore_container \\
      -v appwrite_appwrite-mariadb:/backup_restore/appwrite-mariadb \\
      -v appwrite_appwrite-redis:/backup_restore/appwrite-redis \\
      -v appwrite_appwrite-cache:/backup_restore/appwrite-cache \\
      -v appwrite_appwrite-uploads:/backup_restore/appwrite-uploads \\
      -v appwrite_appwrite-certificates:/backup_restore/appwrite-certificates \\
      -v appwrite_appwrite-functions:/backup_restore/appwrite-functions \\
      -v appwrite_appwrite-influxdb:/backup_restore/appwrite-influxdb \\
      -v appwrite_appwrite-config:/backup_restore/appwrite-config \\
      -v appwrite_appwrite-builds:/backup_restore/appwrite-builds \\
      -v appwrite_appwrite-executor:/backup_restore/appwrite-executor \\
      -v $(pwd)/appwrite:/backup_restore/appwrite \\
      alpine tail -f /dev/null
    
    docker cp /tmp/backup/. temp_restore_container:/backup_restore
    
    docker stop temp_restore_container
    docker rm temp_restore_container
    
    # Remove temporary files
    rm -rf /tmp/backup
    
  9. With respect to security, another good practice in production is adding a WAF too or DDoS protection if you're in an environment that is susceptible to such kind of attacks, like cloudflare (includes both, 25$/month)