Initial commit: Plane stack with MinIO, Redis, RabbitMQ, PostgreSQL

This commit is contained in:
tiderian
2025-08-09 18:38:52 +03:00
commit 14049229d0
6 changed files with 491 additions and 0 deletions

82
.env.example Normal file
View File

@@ -0,0 +1,82 @@
APP_DOMAIN=example.com
APP_RELEASE=v0.28.0
SSL=false
WEB_REPLICAS=1
SPACE_REPLICAS=1
ADMIN_REPLICAS=1
API_REPLICAS=1
WORKER_REPLICAS=1
BEAT_WORKER_REPLICAS=1
LIVE_REPLICAS=1
LISTEN_HTTP_PORT=9080
LISTEN_HTTPS_PORT=9443
WEB_URL=http://${APP_DOMAIN}
DEBUG=0
CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN}
API_BASE_URL=http://api:8000
#DB SETTINGS
PGHOST=plane-db
PGDATABASE=plane
POSTGRES_USER=plane
POSTGRES_PASSWORD=plane
POSTGRES_DB=plane
POSTGRES_PORT=5432
PGDATA=/var/lib/postgresql/data
DATABASE_URL=
# REDIS SETTINGS
REDIS_HOST=plane-redis
REDIS_PORT=6379
REDIS_URL=
# RabbitMQ Settings
RABBITMQ_HOST=plane-mq
RABBITMQ_PORT=5672
RABBITMQ_USER=plane
RABBITMQ_PASSWORD=plane
RABBITMQ_VHOST=plane
AMQP_URL=
# If SSL Cert to be generated, set CERT_EMAIl="email <EMAIL_ADDRESS>"
CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory
TRUSTED_PROXIES=0.0.0.0/0
SITE_ADDRESS=:80
CERT_EMAIL=
# For DNS Challenge based certificate generation, set the CERT_ACME_DNS, CERT_EMAIL
# CERT_ACME_DNS="acme_dns <CERT_DNS_PROVIDER> <CERT_DNS_PROVIDER_API_KEY>"
CERT_ACME_DNS=
# Secret Key
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
# DATA STORE SETTINGS
USE_MINIO=1
AWS_REGION=
AWS_ACCESS_KEY_ID=access-key
AWS_SECRET_ACCESS_KEY=secret-key
AWS_S3_ENDPOINT_URL=http://plane-minio:9000
AWS_S3_BUCKET_NAME=uploads
FILE_SIZE_LIMIT=5242880
# Gunicorn Workers
GUNICORN_WORKERS=1
# UNCOMMENT `DOCKER_PLATFORM` IF YOU ARE ON `ARM64` AND DOCKER IMAGE IS NOT AVAILABLE FOR RESPECTIVE `APP_RELEASE`
# DOCKER_PLATFORM=linux/amd64
# Force HTTPS for handling SSL Termination
MINIO_ENDPOINT_SSL=0
# API key rate limit
API_KEY_RATE_LIMIT=60/minute
DOCKERHUB_USER=artifacts.plane.so/makeplane
PULL_POLICY=if_not_present
CUSTOM_BUILD=false

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/volumes
.env

20
LICENSE Normal file
View File

@@ -0,0 +1,20 @@
MIT License
Copyright (c) 2025 Igor
Permission is hereby granted, free of charge, to any person obtaining a copy
of this stack and associated documentation files (the "Plane Stack"), to deal
in the Stack without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Stack, and to permit persons to whom the Stack is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Stack.
THE STACK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE STACK OR THE USE OR OTHER DEALINGS IN THE STACK.

260
docker-compose.yaml Normal file
View File

@@ -0,0 +1,260 @@
x-db-env: &db-env
PGHOST: ${PGHOST:-plane-db}
PGDATABASE: ${PGDATABASE:-plane}
POSTGRES_USER: ${POSTGRES_USER:-plane}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-plane}
POSTGRES_DB: ${POSTGRES_DB:-plane}
POSTGRES_PORT: ${POSTGRES_PORT:-5432}
PGDATA: ${PGDATA:-/var/lib/postgresql/data}
x-redis-env: &redis-env
REDIS_HOST: ${REDIS_HOST:-plane-redis}
REDIS_PORT: ${REDIS_PORT:-6379}
REDIS_URL: ${REDIS_URL:-redis://plane-redis:6379/}
x-minio-env: &minio-env
MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID:-access-key}
MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY:-secret-key}
x-aws-s3-env: &aws-s3-env
AWS_REGION: ${AWS_REGION:-}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-access-key}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-secret-key}
AWS_S3_ENDPOINT_URL: ${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
x-proxy-env: &proxy-env
SSL: ${SSL:-false}
APP_DOMAIN: ${APP_DOMAIN:-localhost}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
CERT_EMAIL: ${CERT_EMAIL}
CERT_ACME_CA: ${CERT_ACME_CA}
CERT_ACME_DNS: ${CERT_ACME_DNS}
LISTEN_HTTP_PORT: ${LISTEN_HTTP_PORT:-80}
LISTEN_HTTPS_PORT: ${LISTEN_HTTPS_PORT:-443}
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
SITE_ADDRESS: ${SITE_ADDRESS:-:80}
x-mq-env: &mq-env # RabbitMQ Settings
RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq}
RABBITMQ_PORT: ${RABBITMQ_PORT:-5672}
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-plane}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-plane}
RABBITMQ_DEFAULT_VHOST: ${RABBITMQ_VHOST:-plane}
RABBITMQ_VHOST: ${RABBITMQ_VHOST:-plane}
x-live-env: &live-env
API_BASE_URL: ${API_BASE_URL:-http://api:8000}
x-app-env: &app-env
WEB_URL: ${WEB_URL:-http://localhost}
DEBUG: ${DEBUG:-0}
CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS}
GUNICORN_WORKERS: 1
USE_MINIO: ${USE_MINIO:-1}
DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
SECRET_KEY: ${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute}
MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
services:
web:
image: artifacts.plane.so/makeplane/plane-frontend:${APP_RELEASE:-v0.28.0}
restart: unless-stopped
depends_on:
- api
- worker
networks:
plane-net:
ipv4_address: 172.16.16.73
space:
image: artifacts.plane.so/makeplane/plane-space:${APP_RELEASE:-v0.28.0}
restart: unless-stopped
depends_on:
- api
- worker
- web
networks:
plane-net:
ipv4_address: 172.16.16.74
admin:
image: artifacts.plane.so/makeplane/plane-admin:${APP_RELEASE:-v0.28.0}
restart: unless-stopped
depends_on:
- api
- web
networks:
plane-net:
ipv4_address: 172.16.16.75
live:
image: artifacts.plane.so/makeplane/plane-live:${APP_RELEASE:-v0.28.0}
environment:
<<: [*live-env]
restart: unless-stopped
depends_on:
- api
- web
networks:
plane-net:
ipv4_address: 172.16.16.76
api:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v0.28.0}
command: ./bin/docker-entrypoint-api.sh
restart: unless-stopped
volumes:
- ./volumes/logs_api:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- plane-db
- plane-redis
- plane-mq
networks:
plane-net:
ipv4_address: 172.16.16.69
worker:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v0.28.0}
command: ./bin/docker-entrypoint-worker.sh
restart: unless-stopped
volumes:
- ./volumes/logs_worker:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- api
- plane-db
- plane-redis
- plane-mq
networks:
plane-net:
ipv4_address: 172.16.16.70
beat-worker:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v0.28.0}
command: ./bin/docker-entrypoint-beat.sh
restart: unless-stopped
volumes:
- ./volumes/logs_beat-worker:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- api
- plane-db
- plane-redis
- plane-mq
networks:
plane-net:
ipv4_address: 172.16.16.71
migrator:
image: artifacts.plane.so/makeplane/plane-backend:${APP_RELEASE:-v0.28.0}
command: ./bin/docker-entrypoint-migrator.sh
restart: unless-stopped
volumes:
- ./volumes/logs_migrator:/code/plane/logs
environment:
<<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env]
depends_on:
- plane-db
- plane-redis
networks:
plane-net:
ipv4_address: 172.16.16.72
# Comment this if you already have a database running
plane-db:
image: postgres:15.7-alpine
command: postgres -c 'max_connections=1000'
restart: unless-stopped
environment:
<<: *db-env
volumes:
- ./volumes/pgdata:/var/lib/postgresql/data
networks:
plane-net:
ipv4_address: 172.16.16.65
plane-redis:
image: valkey/valkey:7.2.5-alpine
restart: unless-stopped
volumes:
- ./volumes/redisdata:/data
networks:
plane-net:
ipv4_address: 172.16.16.66
plane-mq:
image: rabbitmq:3.13.6-management-alpine
restart: unless-stopped
environment:
<<: *mq-env
volumes:
- ./volumes/rabbitmq_data:/var/lib/rabbitmq
networks:
plane-net:
ipv4_address: 172.16.16.67
# Comment this if you using any external s3 compatible storage
plane-minio:
image: minio/minio:latest
command: server /export --console-address ":9090"
restart: unless-stopped
environment:
<<: *minio-env
volumes:
- ./volumes/uploads:/export
- ./volumes/minio_data:/data
networks:
plane-net:
ipv4_address: 172.16.16.68
# Comment this if you already have a reverse proxy running
proxy:
image: artifacts.plane.so/makeplane/plane-proxy:${APP_RELEASE:-v0.28.0}
command:
[
"caddy",
"run",
"--config",
"/etc/caddy/Caddyfile",
"--adapter",
"caddyfile",
]
restart: unless-stopped
environment:
<<: *proxy-env
# ports:
# - target: 80
# published: ${LISTEN_HTTP_PORT:-80}
# protocol: tcp
# mode: host
# - target: 443
# published: ${LISTEN_HTTPS_PORT:-443}
# protocol: tcp
# mode: host
volumes:
- ./volumes/proxy_config:/config
- ./volumes/proxy_data:/data
depends_on:
- web
- api
- space
- admin
- live
networks:
plane-net:
ipv4_address: 172.16.16.77
networks:
plane-net:
driver: bridge
ipam:
config:
- subnet: 172.16.16.64/28
gateway: 172.16.16.78

57
makefile Normal file
View File

@@ -0,0 +1,57 @@
# 🌈 Terminal color magic
GREEN := \033[0;32m
YELLOW := \033[1;33m
NC := \033[0m
# 📄 Compose file
COMPOSE_FILE := docker-compose.yaml
all: help
## 🚀 Start the entire Plane infrastructure
up:
@printf "$(YELLOW)🚀 Starting Plane services...$(NC)\n"
@docker-compose -f $(COMPOSE_FILE) up -d
@printf "$(GREEN)✅ All services are up and running!$(NC)\n\n"
## 🧹 Stop and clean everything
down:
@printf "$(YELLOW)🧹 Stopping and cleaning up...$(NC)\n"
@docker-compose -f $(COMPOSE_FILE) down -v
@printf "$(GREEN)✔️ All stopped and volumes removed$(NC)\n\n"
## 📜 View logs (backend & frontend)
logs:
@printf "$(YELLOW)📜 Viewing logs (api & web)...$(NC)\n"
@docker-compose -f $(COMPOSE_FILE) logs -f api web || true
@printf "\n"
## 🔄 Restart frontend only
restart-web:
@printf "$(YELLOW)🔄 Restarting frontend...$(NC)\n"
@docker-compose -f $(COMPOSE_FILE) restart web
@printf "$(GREEN)💫 Restart complete$(NC)\n\n"
## 📊 Status of all containers
status:
@printf "$(YELLOW)📊 Checking container status...$(NC)\n"
@docker ps --filter name=plane-db --filter name=plane-redis --filter name=plane-mq --filter name=api --filter name=web --filter name=proxy
@printf "\n"
## 🔍 Check environment variables
env-check:
@printf "$(YELLOW)🔍 Checking environment variables (.env)...$(NC)\n"
@cat .env | grep -v '^#'
@printf "\n"
## 🧭 Help
help:
@printf "\n"
@printf "$(YELLOW)🧭 Available commands:$(NC)\n"
@printf " make up — start all services\n"
@printf " make down — stop and remove volumes\n"
@printf " make logs — view api & web logs\n"
@printf " make restart-web — restart frontend only\n"
@printf " make status — show status of core components\n"
@printf " make env-check — check environment variables (.env)\n"
@printf "\n"

70
readme.md Normal file
View File

@@ -0,0 +1,70 @@
🛫 Plane Stack: Elegant, Modular, Yours
A transparent and self-contained Plane setup using Docker Compose.
Built with clarity, shared with warmth.
📦 Stack Components
PostgreSQL Server: Stores Plane's workspace and user data
Redis: Handles background jobs and caching
RabbitMQ: Message broker for async tasks
MinIO: S3-compatible object storage for uploads
Plane Backend (API, Worker, Beat, Migrator): Core logic and orchestration
Plane Frontend (Web, Space, Admin, Live): User-facing interfaces
Caddy Proxy: TLS termination and routing (optional)
🛠 Usage
Copy the example environment:
cp .env.example .env
Start the stack:
make up
Interact with services:
make logs # View logs (web & backend)
make status # Show running containers
make restart-web # Restart the frontend
make down # Tear down the stack
🌐 Network
Custom IP configuration via bridge subnet:
| Service | IP Address |
|----------------|-------------------|
| plane-db | 172.16.16.65 |
| plane-redis | 172.16.16.66 |
| plane-mq | 172.16.16.67 |
| plane-minio | 172.16.16.68 |
| api | 172.16.16.69 |
| worker | 172.16.16.70 |
| beat-worker | 172.16.16.71 |
| migrator | 172.16.16.72 |
| web | 172.16.16.73 |
| space | 172.16.16.74 |
| admin | 172.16.16.75 |
| live | 172.16.16.76 |
| proxy | 172.16.16.77 |
Subnet: 172.16.16.64/28, Gateway: .78
📝 Environment
Configure the `.env` file to set database credentials, S3 keys, RabbitMQ settings, domain, and secrets.
An example file is provided in `.env.example`.
🔒 Local Directories
Persistent data stored in `/pgdata`, `/redisdata`, `/uploads`, `/logs_*`, `/proxy_config`, `/proxy_data`
All sensitive files (`.env`, volumes) are excluded via `.gitignore`
❤️ Licensing
This stack is shared under the MIT License.
Use it freely, adapt it for your needs — but keep the spirit of elegance and care.
Created by Igor V. & Celestia B.,
for those who believe infrastructure can be both powerful and poetic.
---
This isnt just Compose.
Its a quiet dialogue between a system and the one who built it.
A symphony of containers, tuned to your rhythm.