Skip to content

Deploying Appwrite

Introduction

Appwrite is a secure, open-source backend-as-a-service platform that simplifies backend development for web, mobile, and Flutter applications. It provides developers with a comprehensive set of APIs and tools to build modern applications faster, including authentication, databases, storage, functions, and real-time subscriptions.

Appwrite is designed to be:

  • Developer-Friendly: Easy-to-use REST and GraphQL APIs with SDKs for multiple platforms
  • Self-Hosted: Full control over your data and infrastructure with complete privacy
  • Secure by Default: Built-in security features including user authentication, authorization, and encryption
  • Scalable: Designed to handle applications of any size from prototypes to production
  • Feature-Rich: Comprehensive backend services including user management, database, file storage, cloud functions, and more
  • Real-Time: WebSocket support for real-time updates and subscriptions

Key features include:

  • Authentication: Multiple auth methods (email/password, OAuth, magic links, phone auth)
  • Database: Flexible NoSQL database with relationships and full-text search
  • Storage: Secure file storage with image manipulation and compression
  • Functions: Serverless functions for custom backend logic
  • Realtime: WebSocket-based real-time events and subscriptions
  • Webhooks: HTTP callbacks for external integrations
  • Teams & Permissions: Fine-grained access control and team collaboration

This comprehensive guide walks you through deploying Appwrite on Klutch.sh using Docker, including detailed installation steps, persistent storage configuration, environment variables setup, and production-ready best practices.

Prerequisites

Before you begin deploying Appwrite to Klutch.sh, ensure you have the following:

  • A Klutch.sh account
  • A GitHub account with a repository for your Appwrite project
  • Docker installed locally for testing (optional but recommended)
  • Basic understanding of Docker, backend services, and API concepts
  • An understanding of your application’s authentication and database requirements

Installation and Setup

Step 1: Create Your Project Directory

First, create a new directory for your Appwrite deployment project:

Terminal window
mkdir appwrite-klutch
cd appwrite-klutch
git init

Step 2: Create the Dockerfile

Create a Dockerfile in your project root directory. This will define your Appwrite container configuration:

# Use the official Appwrite image
FROM appwrite/appwrite:1.5
# Set default environment variables
# These can be overridden in the Klutch.sh dashboard
ENV _APP_ENV=production
ENV _APP_LOCALE=en
ENV _APP_OPTIONS_ABUSE=enabled
ENV _APP_OPTIONS_FORCE_HTTPS=disabled
ENV _APP_OPENSSL_KEY_V1=your-secret-key
# Appwrite listens on port 80 by default
EXPOSE 80
# The Appwrite container starts automatically
# No CMD needed as it's defined in the base image

Important Notes:

  • The _APP_OPENSSL_KEY_V1 should be a long, random string for encryption. Generate one using: openssl rand -base64 32
  • The Appwrite official image comes with all necessary services pre-configured
  • For production, you should set _APP_OPTIONS_FORCE_HTTPS=enabled if using HTTPS

Step 3: Create a .dockerignore File

Create a .dockerignore file to exclude unnecessary files from your Docker build:

.git
.github
.gitignore
README.md
.env
*.log

Step 4: Test Locally (Optional)

Before deploying to Klutch.sh, you can test your Appwrite setup locally using Docker:

Terminal window
# Build the Docker image
docker build -t my-appwrite .
# Run the container locally
docker run -d \
--name appwrite-test \
-p 80:80 \
-e _APP_OPENSSL_KEY_V1="$(openssl rand -base64 32)" \
-e _APP_DOMAIN="localhost" \
-e _APP_DOMAIN_TARGET="localhost" \
my-appwrite
# Check if Appwrite is running
curl http://localhost/v1/health/version
# View logs
docker logs appwrite-test
# Stop and remove the test container when done
docker stop appwrite-test
docker rm appwrite-test

Step 5: Push to GitHub

Commit your Dockerfile and configuration to your GitHub repository:

Terminal window
git add Dockerfile .dockerignore
git commit -m "Add Appwrite Dockerfile configuration"
git remote add origin https://github.com/yourusername/appwrite-klutch.git
git push -u origin main

Deploying to Klutch.sh

Now that your Appwrite project is ready and pushed to GitHub, follow these steps to deploy it on Klutch.sh with persistent storage.

Deployment Steps

    1. Log in to Klutch.sh

      Navigate to klutch.sh/app and sign in to your account.

    2. Create a New Project

      Go to Create Project and give your project a meaningful name (e.g., “Appwrite Backend”).

    3. Create a New App

      Navigate to Create App and configure the following settings:

    4. Select Your Repository

      • Choose GitHub as your Git source
      • Select the repository containing your Dockerfile
      • Choose the branch you want to deploy (usually main or master)
    5. Configure Traffic Type

      • Traffic Type: Select HTTP (Appwrite serves HTTP/HTTPS traffic)
      • Internal Port: Set to 80 (the port that Appwrite listens on inside the container)
    6. Set Environment Variables

      Add the following essential environment variables for your Appwrite configuration:

      Required Environment Variables:

      • _APP_ENV: Set to production
      • _APP_OPENSSL_KEY_V1: Your encryption key (generate with openssl rand -base64 32)
      • _APP_DOMAIN: Your Klutch.sh app URL (e.g., example-app.klutch.sh)
      • _APP_DOMAIN_TARGET: Same as _APP_DOMAIN (e.g., example-app.klutch.sh)

      Optional but Recommended:

      • _APP_LOCALE: Default locale (e.g., en)
      • _APP_OPTIONS_ABUSE: Set to enabled for rate limiting
      • _APP_OPTIONS_FORCE_HTTPS: Set to enabled if using HTTPS
      • _APP_REDIS_HOST: Redis host for caching (if using external Redis)
      • _APP_DB_HOST: Database host (if using external database)
      • _APP_STORAGE_LIMIT: Maximum file size in bytes (default: 30MB)

      SMTP Configuration (for email services):

      • _APP_SMTP_HOST: Your SMTP server hostname
      • _APP_SMTP_PORT: SMTP port (typically 587 or 465)
      • _APP_SMTP_SECURE: Set to tls or ssl
      • _APP_SMTP_USERNAME: SMTP username
      • _APP_SMTP_PASSWORD: SMTP password

      Security Note: Never commit sensitive credentials like _APP_OPENSSL_KEY_V1 or SMTP passwords to your repository. Always set them as environment variables in Klutch.sh.

    7. Attach Persistent Volumes

      Appwrite requires persistent storage for databases, cache, and uploaded files. Configure the following volumes:

      Volume 1 - Database Storage:

      • Mount Path: /storage/uploads
      • Size: Choose based on expected file uploads (e.g., 10GB, 20GB, 50GB)

      Volume 2 - Configuration Storage:

      • Mount Path: /storage/cache
      • Size: 5GB (or more based on your caching needs)

      Volume 3 - Functions Storage (if using Appwrite Functions):

      • Mount Path: /storage/functions
      • Size: 5GB (or more if using many cloud functions)

      Important: Persistent volumes are critical for Appwrite. Without them, you’ll lose all data (users, databases, files) when the container restarts.

    8. Configure Additional Settings

      • Region: Select the region closest to your users for optimal latency
      • Compute Resources:
        • Minimum: 1 CPU, 2GB RAM (for light usage)
        • Recommended: 2 CPU, 4GB RAM (for production workloads)
        • High Traffic: 4+ CPU, 8GB+ RAM
      • Instances: Start with 1 instance (Appwrite handles internal scaling)
    9. Deploy Your Application

      Click “Create” to start the deployment. Klutch.sh will:

      • Automatically detect your Dockerfile in the repository root
      • Build the Docker image with Appwrite
      • Attach the persistent volumes to the specified mount paths
      • Start your Appwrite container
      • Assign a URL for accessing your Appwrite instance
    10. Access Your Appwrite Instance

      Once deployment is complete, you’ll receive a URL like example-app.klutch.sh. Your Appwrite instance will be accessible at:

      • Console: https://example-app.klutch.sh/ (web-based admin dashboard)
      • API Endpoint: https://example-app.klutch.sh/v1

      Open the console to complete the initial setup and create your first project.


Getting Started with Appwrite

After deploying Appwrite, here’s how to get started building your application.

Creating Your First Project

  1. Access the Appwrite Console

    Open your Appwrite instance at https://example-app.klutch.sh/ and create an admin account.

  2. Create a New Project

    In the console, click “Create Project” and give it a name (e.g., “My App”).

  3. Get Your API Keys

    • Navigate to your project settings
    • Note your Project ID (you’ll need this in your client code)
    • Create an API key if building a server-side application

Sample Code: Connecting to Appwrite

Here are examples of how to connect to your deployed Appwrite instance from different platforms:

JavaScript/Node.js:

import { Client, Account, Databases } from 'appwrite';
// Initialize the Appwrite client
const client = new Client()
.setEndpoint('https://example-app.klutch.sh/v1') // Your Appwrite Endpoint
.setProject('your-project-id'); // Your project ID
// Initialize services
const account = new Account(client);
const databases = new Databases(client);
// Example: Create a new user account
async function createUser(email, password, name) {
try {
const response = await account.create(
'unique()', // user ID
email,
password,
name
);
console.log('User created:', response);
return response;
} catch (error) {
console.error('Error creating user:', error);
}
}
// Example: Login
async function login(email, password) {
try {
const session = await account.createEmailSession(email, password);
console.log('Logged in:', session);
return session;
} catch (error) {
console.error('Login error:', error);
}
}
// Example: Create a document in a database
async function createDocument(databaseId, collectionId, data) {
try {
const response = await databases.createDocument(
databaseId,
collectionId,
'unique()', // document ID
data
);
console.log('Document created:', response);
return response;
} catch (error) {
console.error('Error creating document:', error);
}
}

React Example:

import { Client, Account } from 'appwrite';
import { useState, useEffect } from 'react';
const client = new Client()
.setEndpoint('https://example-app.klutch.sh/v1')
.setProject('your-project-id');
const account = new Account(client);
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
// Check if user is logged in
account.get()
.then(response => setUser(response))
.catch(() => setUser(null));
}, []);
const handleLogin = async (email, password) => {
try {
await account.createEmailSession(email, password);
const userData = await account.get();
setUser(userData);
} catch (error) {
console.error('Login failed:', error);
}
};
const handleLogout = async () => {
try {
await account.deleteSession('current');
setUser(null);
} catch (error) {
console.error('Logout failed:', error);
}
};
return (
<div>
{user ? (
<div>
<h1>Welcome, {user.name}!</h1>
<button onClick={handleLogout}>Logout</button>
</div>
) : (
<div>
<h1>Please log in</h1>
{/* Add your login form here */}
</div>
)}
</div>
);
}
export default App;

Python Example:

from appwrite.client import Client
from appwrite.services.account import Account
from appwrite.services.databases import Databases
# Initialize client
client = Client()
client.set_endpoint('https://example-app.klutch.sh/v1')
client.set_project('your-project-id')
client.set_key('your-api-key') # Only for server-side
# Initialize services
account = Account(client)
databases = Databases(client)
# Create a new user
def create_user(email, password, name):
try:
user = account.create(
user_id='unique()',
email=email,
password=password,
name=name
)
print(f'User created: {user}')
return user
except Exception as e:
print(f'Error creating user: {e}')
# Create a document
def create_document(database_id, collection_id, data):
try:
document = databases.create_document(
database_id=database_id,
collection_id=collection_id,
document_id='unique()',
data=data
)
print(f'Document created: {document}')
return document
except Exception as e:
print(f'Error creating document: {e}')

Flutter Example:

import 'package:appwrite/appwrite.dart';
class AppwriteService {
static final Client client = Client()
.setEndpoint('https://example-app.klutch.sh/v1')
.setProject('your-project-id');
static final Account account = Account(client);
static final Databases databases = Databases(client);
// Create user
static Future<void> createUser(String email, String password, String name) async {
try {
final user = await account.create(
userId: 'unique()',
email: email,
password: password,
name: name,
);
print('User created: $user');
} catch (e) {
print('Error creating user: $e');
}
}
// Login
static Future<void> login(String email, String password) async {
try {
final session = await account.createEmailSession(
email: email,
password: password,
);
print('Logged in: $session');
} catch (e) {
print('Login error: $e');
}
}
// Create document
static Future<void> createDocument(
String databaseId,
String collectionId,
Map<String, dynamic> data,
) async {
try {
final document = await databases.createDocument(
databaseId: databaseId,
collectionId: collectionId,
documentId: 'unique()',
data: data,
);
print('Document created: $document');
} catch (e) {
print('Error creating document: $e');
}
}
}

Common Use Cases

1. User Authentication

// Register a new user
const user = await account.create('unique()', 'user@example.com', 'password123', 'John Doe');
// Login
const session = await account.createEmailSession('user@example.com', 'password123');
// Get current user
const currentUser = await account.get();
// Logout
await account.deleteSession('current');

2. Database Operations

// Create a document
const document = await databases.createDocument(
'databaseId',
'collectionId',
'unique()',
{ title: 'My First Post', content: 'Hello World!' }
);
// List documents
const documents = await databases.listDocuments('databaseId', 'collectionId');
// Update a document
await databases.updateDocument('databaseId', 'collectionId', 'documentId', {
title: 'Updated Title'
});
// Delete a document
await databases.deleteDocument('databaseId', 'collectionId', 'documentId');

3. File Storage

import { Storage } from 'appwrite';
const storage = new Storage(client);
// Upload a file
const file = await storage.createFile(
'bucketId',
'unique()',
document.getElementById('fileInput').files[0]
);
// Get file for download
const fileUrl = storage.getFileDownload('bucketId', 'fileId');
// Delete a file
await storage.deleteFile('bucketId', 'fileId');

Production Best Practices

Security Recommendations

  • Strong Encryption Keys: Always use cryptographically secure random keys for _APP_OPENSSL_KEY_V1. Never use default or weak keys in production.
  • Environment Variables: Store all sensitive credentials (API keys, database passwords, SMTP credentials) as environment variables in Klutch.sh, never in your code or Dockerfile.
  • HTTPS Only: Enable _APP_OPTIONS_FORCE_HTTPS=enabled to ensure all connections use HTTPS.
  • Rate Limiting: Keep _APP_OPTIONS_ABUSE=enabled to protect against abuse and DDoS attacks.
  • CORS Configuration: Properly configure allowed origins in the Appwrite console to prevent unauthorized access.
  • API Key Scoping: Create API keys with minimal required permissions for each service.
  • Regular Updates: Keep your Appwrite image updated to the latest stable version for security patches.

Performance Optimization

  • Resource Allocation: Monitor your application and adjust CPU/memory based on actual usage patterns.
  • Caching: Appwrite includes built-in Redis caching. Ensure the cache volume has adequate space.
  • Database Indexing: Create appropriate indexes in your collections for frequently queried fields.
  • File Compression: Enable file compression in storage buckets to reduce storage costs and improve transfer speeds.
  • CDN Integration: Consider using a CDN for serving static files and images.
  • Connection Pooling: For high-traffic applications, monitor database connection usage.

Backup and Recovery

  • Regular Backups: Implement a backup strategy for your persistent volumes, especially /storage/uploads which contains user data and databases.
  • Database Exports: Periodically export your database collections using Appwrite’s export functionality.
  • Configuration Backups: Keep backups of your environment variables and configuration settings.
  • Disaster Recovery Plan: Document your recovery procedures and test them regularly.
  • Version Control: Keep your Dockerfile and configuration in version control (Git) for easy rollback.

Monitoring and Logging

Monitor your Appwrite instance for:

  • API Response Times: Track endpoint performance and identify slow queries
  • Error Rates: Monitor failed requests and authentication attempts
  • Resource Usage: CPU, memory, and disk I/O patterns
  • Storage Growth: Track database and file storage usage over time
  • User Activity: Monitor active sessions and API usage patterns
  • Security Events: Failed login attempts and suspicious activity

Scaling Considerations

  • Vertical Scaling: Increase CPU and memory for your Klutch.sh instance as traffic grows
  • Volume Expansion: Monitor storage usage and expand volumes before reaching capacity
  • Database Optimization: Regularly review and optimize database queries and indexes
  • Caching Strategy: Implement application-level caching for frequently accessed data
  • Function Optimization: Optimize cloud functions for performance and cold start times

Troubleshooting

Cannot Access Appwrite Console

  • Verify your app is deployed and running in the Klutch.sh dashboard
  • Check that the internal port is set to 80
  • Ensure HTTP traffic type is selected (not TCP)
  • Review deployment logs for any startup errors
  • Verify environment variables are correctly set

Database or Files Not Persisting

  • Verify persistent volumes are correctly attached at the specified mount paths
  • Check volume mount paths: /storage/uploads, /storage/cache, /storage/functions
  • Ensure volumes have sufficient space allocated
  • Review logs for permission or write errors

CORS Errors

  • Add your application’s domain to allowed origins in the Appwrite console
  • Ensure _APP_DOMAIN and _APP_DOMAIN_TARGET are correctly set
  • Check that your client is using the correct endpoint URL

Authentication Issues

  • Verify _APP_OPENSSL_KEY_V1 is set and matches across all instances
  • Check that SMTP settings are correct if using email verification
  • Ensure OAuth redirect URLs are properly configured
  • Review authentication logs in the Appwrite console

Email Delivery Problems

  • Verify SMTP environment variables are correctly set
  • Test SMTP credentials with your email provider
  • Check spam folders for verification emails
  • Review Appwrite logs for email sending errors
  • Consider using a dedicated email service like SendGrid or Mailgun

Performance Issues

  • Monitor resource usage in the Klutch.sh dashboard
  • Check database query performance in Appwrite logs
  • Review and optimize frequently used queries
  • Consider increasing compute resources
  • Ensure proper indexing on database collections
  • Monitor and optimize cloud function execution times

Additional Resources


Conclusion

Deploying Appwrite to Klutch.sh provides a powerful, scalable backend-as-a-service platform for your applications. With Docker-based deployment, persistent storage, and comprehensive configuration options, you can build production-ready applications with authentication, databases, storage, and more. By following this guide, you’ve set up a secure, high-performance Appwrite instance ready to power your web, mobile, and Flutter applications with reliable backend services.