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.


