Appwrite Backend-as-a-Service Installation

Appwrite is a self-hosted Backend-as-a-Service platform that provides authentication, databases, storage, serverless functions, and real-time APIs in a single Docker deployment. Running Appwrite on your own Linux server gives you full control over your backend infrastructure without vendor lock-in or cloud service fees.

Prerequisites

  • Linux VPS with at least 2 CPU cores and 4 GB RAM
  • Ubuntu 20.04+ or Debian 11+
  • Docker 20.10+ and Docker Compose v2+
  • A domain name with DNS pointing to your server
  • Ports 80 and 443 open in your firewall

Installing Appwrite with Docker

Appwrite provides a one-command installation using Docker:

# Install using the official script
docker run -it --rm \
    --volume /var/run/docker.sock:/var/run/docker.sock \
    --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
    --entrypoint="install" \
    appwrite/appwrite:1.5.7

# The installer will prompt for:
# - HTTP port (default: 80)
# - HTTPS port (default: 443)
# - Hostname (your domain or server IP)
# - Encryption key (auto-generated or custom)

Manual Docker Compose Installation

For more control, create the Docker Compose file manually:

# Create project directory
mkdir -p /opt/appwrite && cd /opt/appwrite

# Download the official docker-compose.yml
curl -fsSL https://appwrite.io/install/compose -o docker-compose.yml
curl -fsSL https://appwrite.io/install/env -o .env

# Edit .env with your configuration
nano .env

Key environment variables to set:

# .env key settings
_APP_ENV=production
_APP_OPENSSL_KEY_V1=your-32-char-secret-key
_APP_DOMAIN=appwrite.yourdomain.com
_APP_DOMAIN_TARGET=appwrite.yourdomain.com
_APP_DB_HOST=mariadb
_APP_DB_PORT=3306
_APP_DB_SCHEMA=appwrite
_APP_DB_USER=appwrite
_APP_DB_PASS=your-db-password
_APP_REDIS_HOST=redis
_APP_REDIS_PORT=6379

# SMTP for email delivery
_APP_SMTP_HOST=smtp.sendgrid.net
_APP_SMTP_PORT=587
_APP_SMTP_SECURE=tls
_APP_SMTP_USERNAME=apikey
_APP_SMTP_PASSWORD=your-sendgrid-key
[email protected]
# Start Appwrite
docker compose up -d

# Check all services are running
docker compose ps

# View logs
docker compose logs appwrite --tail 50 -f

Access the console at http://your-server-ip or https://appwrite.yourdomain.com.

Authentication Configuration

Appwrite supports multiple authentication methods. Configure them in the console or via API:

Email/Password Auth

# Create the first account via API
curl -X POST "https://appwrite.yourdomain.com/v1/account" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "unique()",
    "email": "[email protected]",
    "password": "SecurePassword123!",
    "name": "Admin User"
  }'

OAuth Providers

Configure OAuth in Console → Auth → Settings → OAuth2 Providers:

# Enable Google OAuth via API
curl -X PATCH "https://appwrite.yourdomain.com/v1/projects/your-project-id/oauth2" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "X-Appwrite-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "google",
    "appId": "your-google-client-id",
    "secret": "your-google-client-secret",
    "enabled": true
  }'

Session Management

# Configure session limits and duration in Console:
# Auth → Security:
# - Session Duration: 365 days
# - Max Sessions Per User: 10
# - Password History: 5
# - Password Dictionary: enabled

Database and Collections

Appwrite uses MariaDB internally but exposes a document-style API:

Creating Databases and Collections

# Create a database
curl -X POST "https://appwrite.yourdomain.com/v1/databases" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "X-Appwrite-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"databaseId": "main", "name": "Main Database"}'

# Create a collection
curl -X POST "https://appwrite.yourdomain.com/v1/databases/main/collections" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "X-Appwrite-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "collectionId": "posts",
    "name": "Posts",
    "permissions": ["read(\"any\")"]
  }'

# Add attributes to the collection
curl -X POST "https://appwrite.yourdomain.com/v1/databases/main/collections/posts/attributes/string" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "X-Appwrite-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"key": "title", "size": 255, "required": true}'

Document Permissions

# Create a document with permissions
curl -X POST "https://appwrite.yourdomain.com/v1/databases/main/collections/posts/documents" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "X-Appwrite-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "documentId": "unique()",
    "data": {
      "title": "My First Post",
      "content": "Hello World"
    },
    "permissions": [
      "read(\"any\")",
      "update(\"user:user123\")",
      "delete(\"user:user123\")"
    ]
  }'

Storage Buckets

# Create a storage bucket
curl -X POST "https://appwrite.yourdomain.com/v1/storage/buckets" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "X-Appwrite-Key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "bucketId": "avatars",
    "name": "Avatars",
    "permissions": ["read(\"any\")"],
    "maximumFileSize": 5242880,
    "allowedFileExtensions": ["jpg", "jpeg", "png", "webp"],
    "compression": "gzip",
    "encryption": true,
    "antivirus": false
  }'

# Upload a file
curl -X POST "https://appwrite.yourdomain.com/v1/storage/buckets/avatars/files" \
  -H "X-Appwrite-Project: your-project-id" \
  -H "X-Appwrite-Key: your-api-key" \
  -F "fileId=unique()" \
  -F "file=@/path/to/avatar.jpg"

Serverless Functions

Appwrite Functions supports Node.js, Python, PHP, Ruby, Dart, and more:

# Install Appwrite CLI
npm install -g appwrite-cli

# Login to your instance
appwrite client --endpoint https://appwrite.yourdomain.com
appwrite login

# Initialize a function project
appwrite init function
# Choose: Node.js 18.0
# Name: send-welcome-email
// functions/send-welcome-email/src/index.js
const sdk = require('node-appwrite');

module.exports = async ({ req, res, log, error }) => {
  const client = new sdk.Client()
    .setEndpoint(process.env.APPWRITE_FUNCTION_API_ENDPOINT)
    .setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
    .setKey(req.headers['x-appwrite-key']);

  const payload = req.body ? JSON.parse(req.body) : {};
  log(`Processing for user: ${payload.userId}`);

  // Send welcome email logic here
  return res.json({ success: true, userId: payload.userId });
};
# Deploy the function
appwrite deploy function

# Create a trigger (on user registration event)
# Console → Functions → your-function → Settings → Events:
# Add event: users.*.create

SDK Integration

JavaScript/TypeScript

npm install appwrite
import { Client, Account, Databases, Storage } from 'appwrite';

const client = new Client()
    .setEndpoint('https://appwrite.yourdomain.com/v1')
    .setProject('your-project-id');

const account = new Account(client);
const databases = new Databases(client);

// Create session
const session = await account.createEmailPasswordSession(
    '[email protected]',
    'password123'
);

// Query documents
const posts = await databases.listDocuments('main', 'posts', [
    Query.equal('status', 'published'),
    Query.orderDesc('$createdAt'),
    Query.limit(10)
]);

Production Hardening

# Update Appwrite
cd /opt/appwrite
docker compose pull
docker compose up -d

# Enable automatic backups for MariaDB
docker exec appwrite-mariadb mysqldump -u appwrite -p appwrite > /backup/appwrite-$(date +%Y%m%d).sql

# Set up daily backup cron
echo "0 2 * * * docker exec appwrite-mariadb mysqldump -u appwrite -pyourpassword appwrite > /backup/appwrite-\$(date +\%Y\%m\%d).sql" | sudo crontab -

# Monitor disk usage (uploads directory can grow large)
du -sh /var/lib/docker/volumes/appwrite_appwrite-uploads/_data

Troubleshooting

Console not loading:

# Check Appwrite container logs
docker compose logs appwrite --tail 100

# Verify nginx/traefik is routing correctly
docker compose logs traefik --tail 50

# Check if port 80 is accessible
curl -I http://localhost:80

Function deployment fails:

# Check function runtime is available
docker images | grep appwrite-runtime

# View function execution logs
docker compose logs appwrite-worker-functions --tail 50

Database connection errors:

# Check MariaDB is running
docker compose ps | grep mariadb

# Test database connectivity
docker compose exec appwrite php -r "
\$pdo = new PDO('mysql:host=mariadb;dbname=appwrite', 'appwrite', 'yourpassword');
echo \$pdo->query('SELECT 1')->fetchColumn();
"

Conclusion

Appwrite delivers a complete, self-hosted BaaS that rivals Firebase in feature coverage while keeping all data on your own infrastructure. Its Docker-based deployment makes it easy to install on any Linux VPS, and the consistent SDK experience across JavaScript, Python, Flutter, and other platforms means your team can build full-stack applications without managing backend infrastructure code.