Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions blueprints/nebulynk/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# dokploy: allow-host-ports
# LiveKit requires public TCP/UDP media ports 7881 and 7882 for WebRTC.
# Nebulynk Dokploy template. Import the generated import.base64 file through
# Compose -> Advanced -> Import. Dokploy owns routing and the isolated network.
version: "3.8"
services:
frontend:
build:
context: "https://github.com/sapientorius/Nebulynk.git#${NEBULYNK_SOURCE_REF:-stable}"
dockerfile: frontend/Dockerfile
args:
NODE_IMAGE: "${NEBULYNK_NODE_IMAGE:-node:22.23.1-alpine3.24}"
NGINX_IMAGE: "${NEBULYNK_NGINX_IMAGE:-nginxinc/nginx-unprivileged:1.31-alpine3.23@sha256:6320020c7da8714feab524e02c08c5a1958675c4e68700e93a2fd8970b065786}"
# These URLs are baked into the browser bundle.
VITE_API_URL: "${VITE_API_URL:?VITE_API_URL must be set}"
VITE_LIVEKIT_URL: "${LIVEKIT_PUBLIC_URL:?LIVEKIT_PUBLIC_URL must be set}"
VITE_VAPID_PUBLIC_KEY: "${VAPID_PUBLIC_KEY:-}"
VITE_AUTH_CSRF_COOKIE_NAME: "${AUTH_CSRF_COOKIE_NAME:-nebulynk_csrf_token}"
depends_on:
- backend
expose:
- "8080"
restart: unless-stopped

postgres:
image: "${NEBULYNK_POSTGRES_IMAGE:-postgres:17-alpine3.24@sha256:742f40ea20b9ff2ff31db5458d127452988a2164df9e17441e191f3b72252193}"
environment:
POSTGRES_DB: "${POSTGRES_DB:-nebulynk}"
POSTGRES_USER: "${POSTGRES_USER:-nebulynk}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}"
volumes:
- nebulynk_postgres_data:/var/lib/postgresql/data
restart: unless-stopped

redis:
image: "${NEBULYNK_REDIS_IMAGE:-redis:7.4.7-alpine3.21}"
volumes:
- nebulynk_redis_data:/data
restart: unless-stopped

# Prepare named Garage volumes for the unprivileged Garage process.
garage-volume-init:
image: alpine:3.21.5
user: "0:0"
command: ["sh", "-ec", "chown -R 65532:65532 /var/lib/garage/meta /var/lib/garage/data"]
volumes:
- nebulynk_garage_meta:/var/lib/garage/meta
- nebulynk_garage_data:/var/lib/garage/data
restart: "no"

garage:
build:
context: "https://github.com/sapientorius/Nebulynk.git#${NEBULYNK_SOURCE_REF:-stable}"
dockerfile: garage.Dockerfile
args:
GARAGE_IMAGE: "${NEBULYNK_GARAGE_IMAGE:-dxflrs/garage:v2.3.0}"
depends_on:
garage-volume-init:
condition: service_completed_successfully
command: /garage server --single-node --default-bucket
environment:
GARAGE_RPC_SECRET: "${GARAGE_RPC_SECRET:?GARAGE_RPC_SECRET must be set}"
GARAGE_DEFAULT_ACCESS_KEY: "${STORAGE_S3_ACCESS_KEY:?STORAGE_S3_ACCESS_KEY must be set}"
GARAGE_DEFAULT_SECRET_KEY: "${STORAGE_S3_SECRET_KEY:?STORAGE_S3_SECRET_KEY must be set}"
GARAGE_DEFAULT_BUCKET: "${STORAGE_S3_BUCKET:-nebulynk-files}"
volumes:
- nebulynk_garage_meta:/var/lib/garage/meta
- nebulynk_garage_data:/var/lib/garage/data
expose:
- "3900"
restart: unless-stopped

livekit:
build:
context: "https://github.com/sapientorius/Nebulynk.git#${NEBULYNK_SOURCE_REF:-stable}"
dockerfile: livekit.Dockerfile
args:
LIVEKIT_SERVER_IMAGE: "${NEBULYNK_LIVEKIT_SERVER_IMAGE:-livekit/livekit-server:v1.13.4}"
command: --config /livekit.yaml
depends_on:
- redis
environment:
LIVEKIT_KEYS: "${LIVEKIT_API_KEY:?LIVEKIT_API_KEY must be set}: ${LIVEKIT_API_SECRET:?LIVEKIT_API_SECRET must be set}"
expose:
- "7880"
ports:
- "7881:7881"
- "7882:7882/udp"
restart: unless-stopped

livekit-egress:
build:
context: "https://github.com/sapientorius/Nebulynk.git#${NEBULYNK_SOURCE_REF:-stable}"
dockerfile: livekit-egress.Dockerfile
args:
LIVEKIT_EGRESS_IMAGE: "${NEBULYNK_LIVEKIT_EGRESS_IMAGE:-livekit/egress:v1.13.0}"
command: --config /livekit-egress.yaml
environment:
EGRESS_CONFIG_FILE: /livekit-egress.yaml
LIVEKIT_API_KEY: "${LIVEKIT_API_KEY:?LIVEKIT_API_KEY must be set}"
LIVEKIT_API_SECRET: "${LIVEKIT_API_SECRET:?LIVEKIT_API_SECRET must be set}"
LIVEKIT_WS_URL: ws://livekit:7880
AWS_ACCESS_KEY_ID: "${STORAGE_S3_ACCESS_KEY:?STORAGE_S3_ACCESS_KEY must be set}"
AWS_SECRET_ACCESS_KEY: "${STORAGE_S3_SECRET_KEY:?STORAGE_S3_SECRET_KEY must be set}"
AWS_DEFAULT_REGION: "${STORAGE_S3_REGION:-${MEETING_RECORDINGS_S3_REGION:-us-east-1}}"
depends_on:
- livekit
- redis
- garage
restart: unless-stopped

backend:
build:
context: "https://github.com/sapientorius/Nebulynk.git#${NEBULYNK_SOURCE_REF:-stable}"
dockerfile: backend/Dockerfile
args:
NODE_IMAGE: "${NEBULYNK_NODE_IMAGE:-node:22.23.1-alpine3.24}"
environment:
NODE_ENV: "${NODE_ENV:-development}"
JWT_SECRET: "${JWT_SECRET:?JWT_SECRET must be set}"
AI_SECRET_KEY: "${AI_SECRET_KEY:?AI_SECRET_KEY must be set}"
AUTH_2FA_SECRET_KEY: "${AUTH_2FA_SECRET_KEY:-}"
BACKEND_PORT: "${BACKEND_PORT:-3030}"
LOG_LEVEL: "${LOG_LEVEL:-info}"
MAX_FILE_SIZE: "${MAX_FILE_SIZE:-26214400}"
AUTHENTICATION_RATE_LIMIT_IP_LIMIT: "${AUTHENTICATION_RATE_LIMIT_IP_LIMIT:-}"
AUTH_BROWSER_ACCESS_TOKEN_TTL: "${AUTH_BROWSER_ACCESS_TOKEN_TTL:-15m}"
AUTH_REFRESH_TOKEN_TTL: "${AUTH_REFRESH_TOKEN_TTL:-1d}"
AUTH_REMEMBER_REFRESH_TOKEN_TTL: "${AUTH_REMEMBER_REFRESH_TOKEN_TTL:-30d}"
AUTH_REFRESH_COOKIE_NAME: "${AUTH_REFRESH_COOKIE_NAME:-nebulynk_refresh_session}"
AUTH_CSRF_COOKIE_NAME: "${AUTH_CSRF_COOKIE_NAME:-nebulynk_csrf_token}"
AUTH_COOKIE_DOMAIN: "${AUTH_COOKIE_DOMAIN:-}"
RATE_LIMIT_DRIVER: "${RATE_LIMIT_DRIVER:-redis}"
PASSKEY_RP_ID: "${PASSKEY_RP_ID:?PASSKEY_RP_ID must be set}"
AI_PROVIDER_BASE_URL_ALLOWLIST: "${AI_PROVIDER_BASE_URL_ALLOWLIST:-}"
POSTGRES_HOST: postgres
POSTGRES_PORT: "5432"
POSTGRES_DB: "${POSTGRES_DB:-nebulynk}"
POSTGRES_USER: "${POSTGRES_USER:-nebulynk}"
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}"
REDIS_HOST: redis
REDIS_PORT: "6379"
STORAGE_S3_ENDPOINT: http://garage:3900
STORAGE_S3_PUBLIC_ENDPOINT: "${STORAGE_S3_PUBLIC_ENDPOINT:?STORAGE_S3_PUBLIC_ENDPOINT must be set}"
STORAGE_S3_ACCESS_KEY: "${STORAGE_S3_ACCESS_KEY:?STORAGE_S3_ACCESS_KEY must be set}"
STORAGE_S3_SECRET_KEY: "${STORAGE_S3_SECRET_KEY:?STORAGE_S3_SECRET_KEY must be set}"
STORAGE_S3_BUCKET: "${STORAGE_S3_BUCKET:-nebulynk-files}"
STORAGE_S3_REGION: "${STORAGE_S3_REGION:-${MEETING_RECORDINGS_S3_REGION:-us-east-1}}"
MEETING_RECORDINGS_PREFIX: meeting-recordings
MEETING_RECORDINGS_BUCKET: "${STORAGE_S3_BUCKET:-nebulynk-files}"
MEETING_RECORDINGS_S3_ENDPOINT: http://garage:3900
MEETING_RECORDINGS_EGRESS_S3_ENDPOINT: http://garage:3900
MEETING_RECORDINGS_S3_REGION: "${MEETING_RECORDINGS_S3_REGION:-${STORAGE_S3_REGION:-us-east-1}}"
MEETING_TRANSCRIPT_WAIT_TIMEOUT_MS: "${MEETING_TRANSCRIPT_WAIT_TIMEOUT_MS:-1800000}"
LIVEKIT_HOST: http://livekit:7880
LIVEKIT_PUBLIC_URL: "${LIVEKIT_PUBLIC_URL:?LIVEKIT_PUBLIC_URL must be set}"
LIVEKIT_API_KEY: "${LIVEKIT_API_KEY:?LIVEKIT_API_KEY must be set}"
LIVEKIT_API_SECRET: "${LIVEKIT_API_SECRET:?LIVEKIT_API_SECRET must be set}"
KLIPY_API_KEY: "${KLIPY_API_KEY:-}"
VAPID_PUBLIC_KEY: "${VAPID_PUBLIC_KEY:-}"
VAPID_PRIVATE_KEY: "${VAPID_PRIVATE_KEY:-}"
VAPID_SUBJECT: "${VAPID_SUBJECT:-mailto:admin@example.com}"
SMTP_HOST: "${SMTP_HOST:-}"
SMTP_PORT: "${SMTP_PORT:-587}"
SMTP_SECURE: "${SMTP_SECURE:-false}"
SMTP_IGNORE_TLS: "${SMTP_IGNORE_TLS:-false}"
SMTP_USER: "${SMTP_USER:-}"
SMTP_PASS: "${SMTP_PASS:-}"
SMTP_FROM: "${SMTP_FROM:-noreply@nebulynk.local}"
SMTP_FROM_NAME: "${SMTP_FROM_NAME:-Nebulynk}"
FRONTEND_URL: "${FRONTEND_URL:?FRONTEND_URL must be set}"
TRUST_PROXY: "${TRUST_PROXY:-true}"
NEBULYNK_BUILD_SHA: "${NEBULYNK_BUILD_SHA:-}"
depends_on:
- postgres
- redis
- garage
- livekit
- livekit-egress
expose:
- "3030"
restart: unless-stopped

volumes:
nebulynk_postgres_data:
nebulynk_redis_data:
nebulynk_garage_meta:
nebulynk_garage_data:
28 changes: 28 additions & 0 deletions blueprints/nebulynk/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"id": "nebulynk",
"name": "Nebulynk",
"version": "stable",
"description": "Nebulynk is a self-hosted collaboration platform for teams with real-time messaging, file sharing, video meetings, and AI-powered transcription and summaries.",
"logo": "nebulynk.png",
"links": {
"github": "https://github.com/sapientorius/Nebulynk",
"docs": "https://github.com/sapientorius/Nebulynk",
"website": "https://nebulynk.net"
},
"tags": [
"communication",
"collaboration",
"chat",
"video-conferencing",
"self-hosted",
"messaging",
"file-sharing",
"ai-integration",
"team-collaboration",
"voice-chat",
"productivity",
"remote-work",
"transcription",
"meeting"
]
}
Binary file added blueprints/nebulynk/nebulynk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
104 changes: 104 additions & 0 deletions blueprints/nebulynk/template.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Values in [variables] are resolved once when Dokploy imports the template.
# The generated values are then stored in the Compose service environment.
[variables]
frontend_domain = "${domain}"
backend_domain = "${domain}"
livekit_domain = "${domain}"
garage_domain = "${domain}"

postgres_password = "${password:64}"
garage_rpc_secret = "${hash:64}"
storage_s3_access_key = "${password:24}"
storage_s3_secret_key = "${password:64}"
jwt_secret = "${password:64}"
ai_secret_key = "${password:64}"
auth_2fa_secret_key = "${password:64}"
livekit_api_key = "${password:24}"
livekit_api_secret = "${password:64}"

# Generated sslip.io domains are HTTP-only until Dokploy TLS is configured.
frontend_url = "http://${frontend_domain}"
backend_url = "http://${backend_domain}"
livekit_public_url = "http://${livekit_domain}"
garage_public_url = "http://${garage_domain}"
source_ref = "stable"

[config]
isolated = true

[[config.domains]]
serviceName = "frontend"
port = 8080
host = "${frontend_domain}"
path = "/"

[[config.domains]]
serviceName = "backend"
port = 3030
host = "${backend_domain}"
path = "/"

[[config.domains]]
serviceName = "livekit"
port = 7880
host = "${livekit_domain}"
path = "/"

[[config.domains]]
serviceName = "garage"
port = 3900
host = "${garage_domain}"
path = "/"

[config.env]
NODE_ENV = "development"
NEBULYNK_SOURCE_REF = "${source_ref}"
POSTGRES_DB = "nebulynk"
POSTGRES_USER = "nebulynk"
POSTGRES_PASSWORD = "${postgres_password}"
GARAGE_RPC_SECRET = "${garage_rpc_secret}"
STORAGE_S3_ACCESS_KEY = "${storage_s3_access_key}"
STORAGE_S3_SECRET_KEY = "${storage_s3_secret_key}"
STORAGE_S3_BUCKET = "nebulynk-files"
STORAGE_S3_REGION = "us-east-1"
JWT_SECRET = "${jwt_secret}"
AI_SECRET_KEY = "${ai_secret_key}"
AUTH_2FA_SECRET_KEY = "${auth_2fa_secret_key}"
LIVEKIT_API_KEY = "${livekit_api_key}"
LIVEKIT_API_SECRET = "${livekit_api_secret}"
FRONTEND_URL = "${frontend_url}"
PASSKEY_RP_ID = "${frontend_domain}"
VITE_API_URL = "${backend_url}"
LIVEKIT_PUBLIC_URL = "${livekit_public_url}"
STORAGE_S3_PUBLIC_ENDPOINT = "${garage_public_url}"

# Optional integrations. Leave instance-specific values empty until configured.
KLIPY_API_KEY = ""
VAPID_PUBLIC_KEY = ""
VAPID_PRIVATE_KEY = ""
VAPID_SUBJECT = ""

SMTP_HOST = ""
SMTP_PORT = "587"
SMTP_SECURE = "false"
SMTP_IGNORE_TLS = "false"
SMTP_USER = ""
SMTP_PASS = ""
SMTP_FROM = ""
SMTP_FROM_NAME = "Nebulynk"

# Optional operational and security settings.
AUTHENTICATION_RATE_LIMIT_IP_LIMIT = ""
AUTH_BROWSER_ACCESS_TOKEN_TTL = "15m"
AUTH_REFRESH_TOKEN_TTL = "1d"
AUTH_REMEMBER_REFRESH_TOKEN_TTL = "30d"
AUTH_REFRESH_COOKIE_NAME = "nebulynk_refresh_session"
AUTH_CSRF_COOKIE_NAME = "nebulynk_csrf_token"
AUTH_COOKIE_DOMAIN = ""
RATE_LIMIT_DRIVER = "redis"
AI_PROVIDER_BASE_URL_ALLOWLIST = ""
LOG_LEVEL = "info"
MAX_FILE_SIZE = "26214400"
MEETING_TRANSCRIPT_WAIT_TIMEOUT_MS = "1800000"
TRUST_PROXY = "true"
NEBULYNK_BUILD_SHA = ""
Loading