Initial push of Plunk Next

This commit is contained in:
Dries Augustyns
2025-12-01 09:56:56 +01:00
parent 07cea20262
commit ff1876d580
566 changed files with 89036 additions and 28423 deletions
@@ -0,0 +1,228 @@
---
title: Database Setup
description: Configure and manage your PostgreSQL database
---
## Prerequisites
- PostgreSQL 14 or higher
- Database created
- Database user with permissions
## Installation
### Using Docker
```bash
docker run -d \
--name plunk-postgres \
-e POSTGRES_PASSWORD=your-password \
-e POSTGRES_DB=plunk \
-p 5432:5432 \
-v postgres_data:/var/lib/postgresql/data \
postgres:14
```
### Using Package Manager
#### Ubuntu/Debian
```bash
sudo apt update
sudo apt install postgresql postgresql-contrib
```
#### macOS
```bash
brew install postgresql@14
brew services start postgresql@14
```
## Database Creation
```sql
CREATE DATABASE plunk;
CREATE USER plunk WITH ENCRYPTED PASSWORD 'your-password';
GRANT ALL PRIVILEGES ON DATABASE plunk TO plunk;
```
## Connection String
```bash
DATABASE_URL="postgresql://plunk:your-password@localhost:5432/plunk"
DIRECT_DATABASE_URL="postgresql://plunk:your-password@localhost:5432/plunk"
```
## Running Migrations
### Development
```bash
yarn workspace @plunk/db migrate:dev
```
### Production
```bash
yarn workspace @plunk/db migrate:prod
```
## Database Schema
Plunk uses Prisma ORM. The schema is located at:
```
packages/db/prisma/schema.prisma
```
### Core Tables
- **User**: User accounts
- **Project**: Workspaces/tenants
- **Membership**: User-project relationships
- **Contact**: Email contacts
- **Template**: Email templates
- **Campaign**: Email campaigns
- **Workflow**: Automated sequences
- **Email**: Email tracking
- **Event**: Custom events
## Indexes
Important indexes for performance:
```sql
-- Contact email index (unique per project)
CREATE INDEX idx_contact_email ON "Contact" (email, "projectId");
-- Contact subscription index
CREATE INDEX idx_contact_subscribed ON "Contact" (subscribed);
-- Email tracking indexes
CREATE INDEX idx_email_contact ON "Email" ("contactId");
CREATE INDEX idx_email_created ON "Email" ("createdAt");
-- Event indexes
CREATE INDEX idx_event_contact ON "Event" ("contactId");
CREATE INDEX idx_event_name ON "Event" (event);
```
## Performance Tuning
### For Large Datasets (1M+ contacts)
```sql
-- Increase shared buffers (25% of RAM)
ALTER SYSTEM SET shared_buffers = '2GB';
-- Increase work memory
ALTER SYSTEM SET work_mem = '50MB';
-- Increase maintenance work memory
ALTER SYSTEM SET maintenance_work_mem = '512MB';
-- Enable parallel queries
ALTER SYSTEM SET max_parallel_workers_per_gather = 4;
-- Reload configuration
SELECT pg_reload_conf();
```
### Vacuum and Analyze
Run regularly for optimal performance:
```bash
# Manual vacuum
vacuumdb --analyze --verbose plunk
# Auto-vacuum (enabled by default)
```
## Backup and Restore
### Backup
```bash
pg_dump -U plunk -d plunk > backup-$(date +%Y%m%d).sql
```
### Restore
```bash
psql -U plunk -d plunk < backup.sql
```
### Automated Backups
Set up cron job:
```bash
0 2 * * * pg_dump -U plunk plunk > /backups/plunk-$(date +\%Y\%m\%d).sql
```
## Monitoring
### Connection Count
```sql
SELECT count(*) FROM pg_stat_activity;
```
### Database Size
```sql
SELECT pg_size_pretty(pg_database_size('plunk'));
```
### Table Sizes
```sql
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname || '.' || tablename) DESC;
```
### Slow Queries
```sql
SELECT
query,
calls,
total_time,
mean_time
FROM pg_stat_statements
ORDER BY mean_time DESC
LIMIT 10;
```
## Troubleshooting
### Connection refused
Check PostgreSQL is running:
```bash
sudo systemctl status postgresql
```
### Authentication failed
Verify credentials in connection string.
### Too many connections
Increase max_connections:
```sql
ALTER SYSTEM SET max_connections = 200;
SELECT pg_reload_conf();
```
## Next Steps
- [Configure email delivery](/self-hosting/email-setup)
- [Deploy with Docker](/self-hosting/docker)
- [Environment variables](/self-hosting/environment-variables)
@@ -0,0 +1,394 @@
---
title: Docker Deployment
description: Deploy Plunk with Docker Compose
---
## Prerequisites
- Docker installed
- Docker Compose installed
- Git installed
## Quick Start
### 1. Clone Repository
```bash
git clone https://github.com/useplunk/plunk.git
cd plunk
```
### 2. Copy Environment File
```bash
cp .env.self-host.example .env
```
### 3. Configure Environment
Edit `.env` and configure required variables:
```bash
# Database Password (PostgreSQL)
DB_PASSWORD="changeme123"
# JWT Secret (generate with: openssl rand -base64 32)
JWT_SECRET="your-secret-here"
# Domains (for subdomain-based routing)
API_DOMAIN="api.localhost"
DASHBOARD_DOMAIN="app.localhost"
LANDING_DOMAIN="www.localhost"
WIKI_DOMAIN="docs.localhost"
# Set to 'true' for HTTPS in production
USE_HTTPS="false"
# AWS SES (for email sending)
AWS_SES_REGION="us-east-1"
AWS_SES_ACCESS_KEY_ID="your-access-key"
AWS_SES_SECRET_ACCESS_KEY="your-secret-key"
SES_CONFIGURATION_SET="plunk-configuration-set"
# S3-compatible storage (Minio is included by default)
# Leave defaults unless using external S3
S3_ENDPOINT="http://minio:9000"
S3_ACCESS_KEY_ID="plunk"
S3_ACCESS_KEY_SECRET="plunkminiopass"
S3_BUCKET="uploads"
S3_PUBLIC_URL="http://localhost:9000/uploads"
S3_FORCE_PATH_STYLE="true"
```
### 4. Start Services
```bash
docker compose up -d
```
This starts:
- PostgreSQL database
- Redis
- Minio (S3-compatible storage)
- Plunk application (all services in one container with nginx)
- API server
- Worker process
- Web dashboard
- Landing page
- Documentation
### 5. Access Services
The services are available at the configured domains:
- **Dashboard**: `http://app.localhost` (or your configured domain)
- **API**: `http://api.localhost`
- **Landing**: `http://www.localhost`
- **Docs**: `http://docs.localhost`
- **Minio Console**: `http://localhost:9001`
Create your first account and start sending emails!
## Docker Compose Configuration
The `docker-compose.yml` file uses the pre-built Plunk image from GitHub Container Registry:
```yaml
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: plunk-postgres
restart: unless-stopped
environment:
POSTGRES_DB: plunk
POSTGRES_USER: plunk
POSTGRES_PASSWORD: ${DB_PASSWORD:-changeme123}
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- plunk
redis:
image: redis:7-alpine
container_name: plunk-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- plunk
minio:
image: minio/minio:latest
container_name: plunk-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-plunk}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-plunkminiopass}
volumes:
- minio_data:/data
ports:
- "9000:9000" # API
- "9001:9001" # Console
networks:
- plunk
plunk:
image: ghcr.io/useplunk/plunk:latest
container_name: plunk
restart: unless-stopped
environment:
SERVICE: all # Runs all services (API, Worker, Web, Landing, Wiki)
DATABASE_URL: postgresql://plunk:${DB_PASSWORD}@postgres:5432/plunk
REDIS_URL: redis://redis:6379
JWT_SECRET: ${JWT_SECRET}
# Domain configuration for subdomain routing
API_DOMAIN: ${API_DOMAIN:-api.localhost}
DASHBOARD_DOMAIN: ${DASHBOARD_DOMAIN:-app.localhost}
LANDING_DOMAIN: ${LANDING_DOMAIN:-www.localhost}
WIKI_DOMAIN: ${WIKI_DOMAIN:-docs.localhost}
USE_HTTPS: ${USE_HTTPS:-false}
# AWS SES
AWS_SES_REGION: ${AWS_SES_REGION}
AWS_SES_ACCESS_KEY_ID: ${AWS_SES_ACCESS_KEY_ID}
AWS_SES_SECRET_ACCESS_KEY: ${AWS_SES_SECRET_ACCESS_KEY}
# S3/Minio storage
S3_ENDPOINT: ${S3_ENDPOINT:-http://minio:9000}
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:-plunk}
S3_ACCESS_KEY_SECRET: ${S3_ACCESS_KEY_SECRET:-plunkminiopass}
ports:
- "465:465" # SMTP (implicit TLS)
- "587:587" # SMTP (STARTTLS)
depends_on:
- postgres
- redis
- minio
networks:
- plunk
volumes:
postgres_data:
redis_data:
minio_data:
plunk_data:
networks:
plunk:
driver: bridge
```
**Note**: The Plunk image contains all applications (API, Worker, Web, Landing, Wiki) and uses nginx for subdomain-based routing.
## Production Deployment
### Using Pre-built Image
The easiest way to deploy is using the pre-built image from GitHub Container Registry:
```bash
docker pull ghcr.io/useplunk/plunk:latest
docker compose up -d
```
### Building Your Own Image
If you want to build from source:
```bash
docker build -t plunk:custom .
```
Then update `docker-compose.yml` to use your custom image:
```yaml
plunk:
image: plunk:custom
# ... rest of configuration
```
### Security Hardening
1. **Use strong passwords**
```bash
DB_PASSWORD=$(openssl rand -base64 32)
JWT_SECRET=$(openssl rand -base64 32)
```
2. **Use HTTPS**
- Set `USE_HTTPS=true` in your `.env`
- Set up reverse proxy (Traefik, Caddy, or nginx)
- Configure SSL certificates (Let's Encrypt)
3. **Configure domains**
```bash
API_DOMAIN=api.yourdomain.com
DASHBOARD_DOMAIN=app.yourdomain.com
LANDING_DOMAIN=www.yourdomain.com
WIKI_DOMAIN=docs.yourdomain.com
USE_HTTPS=true
```
4. **Restrict network access**
- Don't expose database and Redis ports publicly
- Use internal Docker networks
- Only expose port 80/443 (via reverse proxy) and SMTP ports
5. **Regular backups**
- Database backups (automated via cron)
- Minio data backups
### Scaling
The Plunk image runs all services in a single container by default. For higher scale:
#### Separate Services
You can run services separately by setting the `SERVICE` environment variable:
```yaml
# API only
plunk-api:
image: ghcr.io/useplunk/plunk:latest
environment:
SERVICE: api
# ... configuration
# Worker only
plunk-worker:
image: ghcr.io/useplunk/plunk:latest
environment:
SERVICE: worker
# ... configuration
# Web only
plunk-web:
image: ghcr.io/useplunk/plunk:latest
environment:
SERVICE: web
# ... configuration
```
#### Scale Workers
For higher email throughput, run multiple worker containers:
```bash
docker compose up -d --scale plunk-worker=3
```
#### External Services
For production at scale, use managed services:
- Managed PostgreSQL (AWS RDS, DigitalOcean, Supabase)
- Managed Redis (AWS ElastiCache, Redis Cloud, Upstash)
- AWS S3 (instead of Minio)
## Maintenance
### View Logs
```bash
# All services
docker compose logs -f
# Specific service
docker compose logs -f plunk
docker compose logs -f postgres
```
### Restart Services
```bash
docker compose restart plunk
```
### Update Plunk
Pull the latest image and restart:
```bash
docker compose pull plunk
docker compose up -d plunk
```
If you built from source:
```bash
git pull
docker build -t plunk:custom .
docker compose up -d
```
### Backup Database
```bash
docker compose exec postgres pg_dump -U plunk plunk > backup-$(date +%Y%m%d).sql
```
### Restore Database
```bash
docker compose exec -T postgres psql -U plunk plunk < backup.sql
```
### Backup Minio Data
```bash
docker compose exec minio mc alias set local http://localhost:9000 plunk plunkminiopass
docker compose exec minio mc mirror local/uploads /backups/minio
```
## Troubleshooting
### Services won't start
Check logs:
```bash
docker compose logs plunk
```
### Database connection errors
Ensure DATABASE_URL is correct and database is running:
```bash
docker compose ps postgres
docker compose exec postgres psql -U plunk -d plunk -c "SELECT 1;"
```
### Worker not processing jobs
Check Plunk container logs for worker output:
```bash
docker compose logs plunk | grep worker
```
Verify Redis connection:
```bash
docker compose exec redis redis-cli PING
```
### Cannot access services
Check that your domains resolve correctly:
```bash
# For local development with *.localhost domains, these should work automatically
# For production domains, ensure DNS is configured correctly
curl http://api.localhost
curl http://app.localhost
```
### Minio not accessible
Check Minio is running:
```bash
docker compose ps minio
docker compose logs minio
```
Access Minio console at `http://localhost:9001` with credentials from `.env`.
## Next Steps
- [Configure environment variables](/self-hosting/environment-variables)
- [Set up email delivery](/self-hosting/email-setup)
- [Database setup and migrations](/self-hosting/database-setup)
@@ -0,0 +1,218 @@
---
title: Email Setup (AWS SES)
description: Configure AWS SES for email delivery
---
## Prerequisites
- AWS account
- AWS SES access
- Domain ownership (for custom domains)
## AWS SES Setup
### 1. Create AWS Account
Sign up at [aws.amazon.com](https://aws.amazon.com)
### 2. Request Production Access
By default, SES is in sandbox mode (limited to verified addresses).
1. Go to AWS SES Console
2. Click "Request production access"
3. Fill out the form
4. Wait for approval (usually 24-48 hours)
### 3. Create IAM User
Create dedicated IAM user for Plunk:
1. Go to IAM Console
2. Create new user: "plunk-ses"
3. Attach policy: `AmazonSESFullAccess`
4. Create access keys
5. Save access key ID and secret key
### 4. Configure Environment Variables
```bash
AWS_SES_REGION="us-east-1"
AWS_SES_ACCESS_KEY_ID="your-access-key-id"
AWS_SES_SECRET_ACCESS_KEY="your-secret-access-key"
```
## Verify Email Addresses
### Single Email
```bash
aws ses verify-email-identity --email-address [email protected]
```
Check your inbox and click verification link.
### Domain Verification
1. Go to SES Console → Verified Identities
2. Click "Create identity"
3. Choose "Domain"
4. Enter your domain: `yourdomain.com`
5. Add DNS records provided by AWS
DNS records (example):
```
Type: TXT
Name: _amazonses.yourdomain.com
Value: provided-by-aws
```
Wait for verification (up to 72 hours).
## Configuration Sets
Create configuration sets for tracking:
### 1. Tracking Configuration Set
```bash
aws ses create-configuration-set \
--configuration-set-name plunk-tracking
```
### 2. No-Tracking Configuration Set
```bash
aws ses create-configuration-set \
--configuration-set-name plunk-no-tracking
```
### 3. Update Environment
```bash
SES_CONFIGURATION_SET="plunk-tracking"
SES_CONFIGURATION_SET_NO_TRACKING="plunk-no-tracking"
```
## SNS for Email Events
Set up SNS to receive email events (opens, clicks, bounces):
### 1. Create SNS Topic
```bash
aws sns create-topic --name plunk-email-events
```
### 2. Subscribe Plunk Webhook
```bash
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:123456789:plunk-email-events \
--protocol https \
--notification-endpoint https://api.yourdomain.com/webhooks/sns
```
### 3. Configure SES Event Publishing
1. Go to SES Console → Configuration Sets
2. Select `plunk-tracking`
3. Add destination → SNS
4. Select your SNS topic
5. Enable events: Delivery, Bounce, Complaint, Open, Click
## DKIM Setup
Enable DKIM signing for better deliverability:
1. Go to SES Console → Verified Identities
2. Select your domain
3. Enable "Easy DKIM"
4. Add CNAME records to your DNS
```
Type: CNAME
Name: xxx._domainkey.yourdomain.com
Value: xxx.dkim.amazonses.com
```
Repeat for all 3 CNAME records provided.
## Testing Email Delivery
```bash
curl -X POST {{API_URL}}/v1/send \
-H "Authorization: Bearer sk_your_secret_key" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Test Email",
"body": "Hello from Plunk!",
"subscribed": true
}'
```
Check AWS SES Console → Email sending → Sending statistics.
## Monitoring
### SES Dashboard
View in AWS Console:
- Sends
- Bounces
- Complaints
- Reputation
### CloudWatch Metrics
Set up alarms for:
- Bounce rate > 5%
- Complaint rate > 0.1%
- Send quota utilization > 80%
## Troubleshooting
### Emails in sandbox mode only
Request production access via SES Console.
### Domain not verified
Check DNS records and wait for propagation (up to 72 hours).
### High bounce rate
- Clean your contact list
- Use double opt-in
- Remove hard bounces immediately
### Low reputation score
- Reduce bounce and complaint rates
- Send only to engaged users
- Implement feedback loops
## Best Practices
1. **Warm up gradually**: Start with low volume, increase slowly
2. **Monitor metrics**: Watch bounces and complaints closely
3. **Clean lists**: Remove inactive and bounced addresses
4. **Use DKIM**: Enable for better deliverability
5. **Segment sends**: Don't send same content to everyone
## Cost Optimization
- First 62,000 emails/month: **FREE** (from EC2)
- Additional: **$0.10 per 1,000 emails**
- Data transfer: **$0.12 per GB**
Example:
- 100,000 emails/month: ~$3.80/month
- 1,000,000 emails/month: ~$94/month
## Next Steps
- [Complete environment setup](/self-hosting/environment-variables)
- [Deploy with Docker](/self-hosting/docker)
- [Send your first email](/getting-started/quick-start)
@@ -0,0 +1,182 @@
---
title: Environment Variables
description: Complete environment variable reference
---
## Required Variables
### Database
```bash
# PostgreSQL connection string
DATABASE_URL="postgresql://user:password@host:5432/plunk"
# Direct connection (for Prisma migrations)
DIRECT_DATABASE_URL="postgresql://user:password@host:5432/plunk"
```
### Redis
```bash
# Redis connection URL
REDIS_URL="redis://host:6379"
```
### Security
```bash
# JWT signing secret (generate with: openssl rand -base64 32)
JWT_SECRET="your-secret-here"
```
### AWS SES (Email Delivery)
```bash
AWS_SES_REGION="us-east-1"
AWS_SES_ACCESS_KEY_ID="your-access-key"
AWS_SES_SECRET_ACCESS_KEY="your-secret-key"
# SES Configuration Sets
SES_CONFIGURATION_SET="plunk-tracking"
SES_CONFIGURATION_SET_NO_TRACKING="plunk-no-tracking"
```
### Application URLs
```bash
# Protocol configuration (auto-generates URIs with http:// or https://)
USE_HTTPS="false" # Set to "true" for HTTPS in production
# Application URIs (auto-generated from domains if not set)
API_URI="https://api.yourdomain.com"
DASHBOARD_URI="https://app.yourdomain.com"
LANDING_URI="https://www.yourdomain.com"
# For Next.js (build time)
NEXT_PUBLIC_API_URI="https://api.yourdomain.com"
NEXT_PUBLIC_DASHBOARD_URI="https://app.yourdomain.com"
NEXT_PUBLIC_LANDING_URI="https://www.yourdomain.com"
```
**Note**: When using domain-based configuration (e.g., `API_DOMAIN=api.yourdomain.com`), the application URIs are automatically generated. Set `USE_HTTPS=true` to use HTTPS protocol, otherwise HTTP will be used by default. You can also manually set the full URIs to override the auto-generation.
## Optional Variables
### Plunk API
If you're using the email package's `sendEmail` function to send emails via the Plunk API:
```bash
# Plunk API Key (obtained from dashboard)
PLUNK_API_KEY="sk_your_secret_key"
```
### S3-Compatible Storage (Minio)
**Note**: When using Docker Compose, Minio is included and these variables are automatically configured with defaults. You typically don't need to set these unless you want to use external S3 storage.
```bash
# Only configure if NOT using the bundled Minio
S3_ENDPOINT="http://minio:9000" # Default: uses bundled Minio
S3_ACCESS_KEY_ID="plunk" # Default: plunk
S3_ACCESS_KEY_SECRET="plunkminiopass" # Default: plunkminiopass
S3_BUCKET="uploads" # Default: uploads
S3_PUBLIC_URL="http://localhost:9000/uploads" # Default: Minio URL
S3_FORCE_PATH_STYLE="true" # Required for Minio
```
### OAuth Providers
```bash
# GitHub OAuth
GITHUB_OAUTH_CLIENT="your-client-id"
GITHUB_OAUTH_SECRET="your-client-secret"
# Google OAuth
GOOGLE_OAUTH_CLIENT="your-client-id"
GOOGLE_OAUTH_SECRET="your-client-secret"
```
### Stripe Billing
```bash
STRIPE_SK="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."
# Stripe Products
STRIPE_PRICE_ONBOARDING="price_..."
STRIPE_PRICE_EMAIL_USAGE="price_..."
# Stripe Metering
STRIPE_METER_EVENT_NAME="email_sent"
```
### Internal
```bash
# Node environment
NODE_ENV="production"
```
## Example .env File
```bash
# Database
DATABASE_URL="postgresql://postgres:password@localhost:5432/plunk"
DIRECT_DATABASE_URL="postgresql://postgres:password@localhost:5432/plunk"
# Redis
REDIS_URL="redis://localhost:6379"
# Security
JWT_SECRET="generated-secret-here"
# AWS SES
AWS_SES_REGION="us-east-1"
AWS_SES_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
AWS_SES_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
SES_CONFIGURATION_SET="plunk-tracking"
SES_CONFIGURATION_SET_NO_TRACKING="plunk-no-tracking"
# Protocol & URLs
USE_HTTPS="false"
API_URI="http://localhost:3001"
DASHBOARD_URI="http://localhost:3000"
LANDING_URI="http://localhost:3002"
# Next.js Public URLs
NEXT_PUBLIC_API_URI="http://localhost:3001"
NEXT_PUBLIC_DASHBOARD_URI="http://localhost:3000"
NEXT_PUBLIC_LANDING_URI="http://localhost:3002"
# Node Environment
NODE_ENV="development"
```
## Generating Secrets
### JWT Secret
```bash
openssl rand -base64 32
```
### Strong Passwords
```bash
openssl rand -base64 24
```
## Security Best Practices
1. **Never commit secrets** to version control
2. **Use environment-specific files** (.env.production, .env.development)
3. **Rotate secrets regularly**
4. **Use secret management** (AWS Secrets Manager, HashiCorp Vault) in production
5. **Limit access** to production environment variables
## Next Steps
- [Set up database](/self-hosting/database-setup)
- [Configure email delivery](/self-hosting/email-setup)
- [Deploy with Docker](/self-hosting/docker)
@@ -0,0 +1,151 @@
---
title: Self-Hosting Introduction
description: Deploy Plunk on your own infrastructure
---
## Overview
Plunk is fully open-source and can be self-hosted on your own infrastructure. This gives you complete control over your data, email delivery, and infrastructure costs.
## Requirements
### System Requirements
- **Node.js**: Version 20 or higher
- **PostgreSQL**: Version 14 or higher
- **Redis**: Version 6 or higher
- **Docker** (recommended): For easy deployment
### AWS Services
- **AWS SES** (Required): For email sending
- **AWS S3** (Optional): For asset storage (Minio is included by default)
### Minimum Server Specs
For small to medium usage (up to 100K contacts):
- **CPU**: 1-2 cores
- **RAM**: 2GB
- **Storage**: 10GB (grows with contact data)
For larger scale (1M+ contacts):
- **CPU**: 2-4 cores
- **RAM**: 4GB
- **Storage**: 50GB+
## Architecture Components
Plunk uses a containerized architecture with the following components:
### 1. Plunk Application Container
Single container running all application services (API, Worker, Web, Landing, Wiki) with nginx reverse proxy for subdomain-based routing.
**Resources**: 1GB RAM, 1 CPU core (can scale up as needed)
**Services included**:
- **API Server**: Express.js application handling HTTP requests
- **Worker Process**: BullMQ worker processing background jobs
- **Web Dashboard**: Next.js application for the UI
- **Landing Page**: Marketing website
- **Documentation**: Wiki/docs site
- **SMTP Relay**: Email relay server (ports 465, 587)
**Note**: Services can be run separately by setting the `SERVICE` environment variable (`api`, `worker`, `web`, `landing`, `wiki`, or `all`).
### 2. PostgreSQL Database
Stores all data (contacts, campaigns, workflows, etc.).
**Resources**: 512MB-1GB RAM, SSD storage recommended
### 3. Redis
Queue system for background jobs (BullMQ).
**Resources**: 256MB-512MB RAM
### 4. Minio (S3-compatible Storage)
Object storage for file uploads and assets.
**Resources**: 256MB-512MB RAM, storage for uploaded files
## Deployment Options
### Docker Compose (Recommended)
Easiest way to get started. Includes all services pre-configured.
[View Docker Guide](/self-hosting/docker)
### Kubernetes
For production deployments at scale.
### Manual Deployment
Deploy each component separately on your infrastructure.
## Quick Start
1. Clone the repository
2. Copy `.env.self-host.example` to `.env`
3. Configure environment variables (see [Environment Variables](/self-hosting/environment-variables))
4. Run `docker compose up -d`
5. Access dashboard at `http://app.localhost` (or your configured domain)
## What's Included
- ✅ Full API server
- ✅ Worker process
- ✅ Web dashboard
- ✅ PostgreSQL database
- ✅ Redis queue
- ✅ All features (campaigns, workflows, segments)
- ✅ No feature limitations
- ✅ No phone-home telemetry
## What's Not Included
- ❌ Managed infrastructure
- ❌ Automatic updates
- ❌ Support (community only)
- ❌ SLA guarantees
## Cost Considerations
### AWS SES Costs
- First 62,000 emails/month: **FREE** (when sent from EC2)
- Additional emails: **$0.10 per 1,000 emails**
### Infrastructure Costs
**All-in-One VPS** (recommended for small to medium usage):
- **Single VPS**: $5-12/month (2GB RAM, services like DigitalOcean, Hetzner, Vultr)
- Runs all containers (Plunk, PostgreSQL, Redis, Minio)
- **AWS SES**: $0-10/month (depends on volume)
- **Storage**: Included in VPS
**Total**: ~$5-20/month for self-hosting
**Managed Services** (for larger scale or production):
- **VPS**: $10-20/month (4GB RAM for Plunk application)
- **Managed PostgreSQL**: $10-15/month (512MB-1GB)
- **Managed Redis**: $5-10/month (256MB-512MB)
- **AWS SES**: $10-50/month (depends on volume)
- **AWS S3**: $1-5/month (if not using Minio)
**Total**: ~$35-100/month for production with managed services
## Support
### Community Support
- GitHub Issues
- Community Forum
- Documentation
## Next Steps
- [Deploy with Docker](/self-hosting/docker)
- [Configure environment variables](/self-hosting/environment-variables)
- [Set up database](/self-hosting/database-setup)
- [Configure email delivery](/self-hosting/email-setup)
@@ -0,0 +1,4 @@
{
"title": "Self-Hosting",
"pages": ["introduction", "docker", "environment-variables", "database-setup", "email-setup"]
}