diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 597c33bf..e17f1964 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -8,7 +8,6 @@ Key components: - **Blueprints**: Self-contained templates with `docker-compose.yml` (service definitions) and `template.toml` (Dokploy-specific configuration for domains, env vars, mounts). - **meta.json**: Centralized index of all templates, aggregated from blueprint metadata. Entries include `id`, `name`, `version`, `description`, `logo`, `links`, and `tags`. -- **app/**: Vite-based React frontend for local preview/development (runs at http://localhost:5173). Copies blueprints and meta.json to dist during build. - **Scripts**: Node.js tools in root and `build-scripts/` for maintaining `meta.json` (deduplication, sorting, validation). Data flow: New templates added to `blueprints/` → Metadata updated in `meta.json` → Processing scripts ensure consistency → App builds include static blueprints/meta for preview. @@ -22,7 +21,6 @@ The "why": Enables rapid, standardized deployment of 200+ OSS apps on Dokploy wi - `docker-compose.yml`: Standard Docker Compose v3.8. Avoid `ports`, `container_name`, `networks`—Dokploy handles isolation via internal networks. - `template.toml`: Defines variables (e.g., `${domain}`), domains (service:port → host), env vars, and mounts. Use helpers like `${password:32}`, `${uuid}`, `${jwt:secret_var}`. - `logo.svg/png`: Service icon, referenced in `meta.json`. -- `app/vite.config.ts`: Configures build to copy `blueprints/*` and `meta.json` to dist root for static serving. - `dedupe-and-sort-meta.js`: Standalone script—reads `meta.json`, removes duplicate `id`s (keeps first), sorts by `id` (case-insensitive), creates timestamped backup. - `build-scripts/process-meta.js`: Advanced processor with CLI options (`--verbose`, `--no-backup`, `--input`/`--output`), JSON schema validation (required: `id`, `name`, `version`, `description`, `links.github`, `logo`, `tags` array). @@ -32,6 +30,8 @@ Exemplary blueprint: `blueprints/ghost/`—`docker-compose.yml` exposes port 236 1. **Add/Update Template**: + - **REQUIREMENT**: Service **MUST** be open source. Only add templates for applications with an open-source license (e.g., MIT, Apache, GPL, AGPL). Proprietary or closed-source services are not allowed. + - **Verify Docker Images**: Before using any Docker image in `docker-compose.yml`, verify it exists using `docker manifest inspect ` (e.g., `docker manifest inspect docker.io/bitnami/discourse:3.5.0`). This ensures the image is available and prevents deployment failures. - Create `blueprints//` (e.g., `ghost`). - Implement `docker-compose.yml` (single service typical; use volumes for persistence). - Configure `template.toml`—reference vars in `[config.domains]`, `[config.env]`, `[config.mounts]`. @@ -39,14 +39,7 @@ Exemplary blueprint: `blueprints/ghost/`—`docker-compose.yml` exposes port 236 - Run `node dedupe-and-sort-meta.js --backup` to validate/sort. - Commit; PR triggers Dokploy preview (base64 import for testing). -2. **Local Development**: - - - App: `cd app && pnpm install && pnpm dev` (Vite dev server). - - Meta processing: `npm run process-meta` or `make process-meta` (uses Makefile targets: `validate`, `check`, `build`). - - Build app: `cd app && pnpm build`—copies blueprints/meta to `dist/` for static hosting. - - Test template: Use PR preview URL or local Dokploy instance; import base64 from template card. - -3. **CI/CD**: +2. **CI/CD**: - `.github/workflows/validate-meta.yml` (if present): Runs validation on push/PR—fails on duplicates, invalid JSON, missing fields. - Integrate processing: Add `npm run process-meta` to build steps; use `--no-backup` in CI. @@ -54,20 +47,22 @@ No tests in repo—focus on manual validation via scripts and Dokploy deploys. D ## Conventions and Patterns +- **Open Source Requirement**: **ALL services MUST be open source**. Only applications with open-source licenses (MIT, Apache, GPL, AGPL, etc.) are allowed. Proprietary or closed-source services are strictly prohibited. - **Template IDs**: Lowercase, kebab-case (e.g., `active-pieces`); unique across repo—enforced by dedupe script. -- **Docker Compose**: Minimal—omit `ports` (Dokploy proxies), `restart: unless-stopped`, persistent volumes (e.g., `- db-data:/var/lib/postgresql/data`). Services named after folder (e.g., `ghost` service). +- **Docker Compose**: Minimal—omit `ports` (Dokploy proxies), persistent volumes (e.g., `- db-data:/var/lib/postgresql/data`). Services named after folder (e.g., `ghost` service). - **template.toml**: - Variables: `[variables] main_domain = "${domain}"`; use helpers for secrets (`${password:64}`, `${base64:32}`). - Domains: `[[config.domains]] serviceName = "" port = 80 host = "${main_domain}"` (path="/" optional). - Env: `[[config.env]]` array of "KEY=VALUE" strings, interpolating vars (e.g., "DB_PASSWORD=${db_pass}"). + - **URL Variables**: When environment variables require URLs (e.g., `WEB_URL`, `NEXTAUTH_URL`, `PUBLIC_URL`), **always use HTTP by default** (e.g., `"http://${main_domain}"`). HTTPS should only be used if explicitly required by the application or when using a reverse proxy with SSL termination. - Mounts: `[[config.mounts]] filePath = "/etc/config" content = """multi-line\ncontent"""`. - JWT helper: `${jwt:secret_var:payload_var}` for auth tokens; payload as JSON string with `exp: ${timestamps:YYYY-MM-DDTHH:mm:ssZ}`. - **Meta.json**: Entries as JSON objects; tags array of lowercase strings (e.g., ["monitoring", "database"]); links object with `github`, `website`, `docs`. - **No Networks**: Rely on Dokploy's isolated deployments—avoid explicit `networks:`. -- **Versions**: Pin images to specific versions in `docker-compose.yml` (e.g., `ghost:5.82.0-alpine`); match in `meta.json.version`. +- **Versions**: Pin images to specific versions in `docker-compose.yml` (e.g., `ghost:5.82.0-alpine`); match in `meta.json.version`. **NEVER use `latest` tag**—it can break templates when upstream images change unexpectedly. **Always verify image exists** using `docker manifest inspect ` before committing. - **Logos**: SVG preferred; size ~128x128; file name in `meta.json.logo` (e.g., "ghost.svg"). -Cross-component: No runtime communication—templates independent. App consumes static blueprints/meta for UI rendering (e.g., search, cards via React components in `app/src/`). +Cross-component: Templates are independent and ship as static blueprints/meta. ## Integration Points diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index a342ac7a..d04171e6 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -5,9 +5,6 @@ on: workflows: [Build Preview Deployment] types: - completed - pull_request: - branches: - - canary permissions: actions: read deployments: write diff --git a/.github/workflows/validate-docker-compose.yml b/.github/workflows/validate-docker-compose.yml index ddd16aab..25d4eaf3 100644 --- a/.github/workflows/validate-docker-compose.yml +++ b/.github/workflows/validate-docker-compose.yml @@ -17,13 +17,10 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: - fetch-depth: 0 # Necesitamos el historial completo para comparar con base + fetch-depth: 0 - name: Set up Docker Compose - run: | - echo "🐳 Setting up Docker Compose..." - # Docker Compose V2 viene preinstalado en ubuntu-latest - docker compose version + run: docker compose version - name: Set up Node.js uses: actions/setup-node@v4 @@ -36,282 +33,89 @@ jobs: version: 8 - name: Install dependencies - run: | - echo "📦 Installing Node.js dependencies..." - cd build-scripts && pnpm install + run: cd build-scripts && pnpm install - - name: Get changed files - id: changed-files + - name: Detect changed blueprints + id: changed run: | - echo "🔍 Detecting changed files..." - - # Obtener la rama base BASE_SHA=$(git merge-base HEAD origin/${{ github.base_ref }}) - # Encontrar todos los archivos docker-compose.yml y template.toml modificados/agregados - CHANGED_COMPOSE=$(git diff --name-only --diff-filter=ACMRT $BASE_SHA HEAD | grep -E 'blueprints/.*/docker-compose\.yml$' || true) - CHANGED_TOML=$(git diff --name-only --diff-filter=ACMRT $BASE_SHA HEAD | grep -E 'blueprints/.*/template\.toml$' || true) + # Obtener todos los blueprints que tienen cambios (en docker-compose.yml o template.toml) + CHANGED_BLUEPRINTS=$(git diff --name-only --diff-filter=ACMRT $BASE_SHA HEAD | \ + grep -E 'blueprints/[^/]+/(docker-compose\.yml|template\.toml)$' | \ + sed 's|blueprints/\([^/]*\)/.*|\1|' | \ + sort -u) - # Crear lista de directorios únicos que tienen cambios - CHANGED_DIRS=$(echo -e "$CHANGED_COMPOSE\n$CHANGED_TOML" | sed 's|blueprints/\([^/]*\)/.*|\1|' | sort -u) - - echo "Changed compose files:" - echo "$CHANGED_COMPOSE" | while read file; do [ -n "$file" ] && echo " - $file"; done - - echo "Changed TOML files:" - echo "$CHANGED_TOML" | while read file; do [ -n "$file" ] && echo " - $file"; done - - echo "Changed directories:" - echo "$CHANGED_DIRS" | while read dir; do [ -n "$dir" ] && echo " - $dir"; done - - # Guardar para usar en siguientes pasos - echo "compose_files<> $GITHUB_OUTPUT - echo "$CHANGED_COMPOSE" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - echo "toml_files<> $GITHUB_OUTPUT - echo "$CHANGED_TOML" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - echo "directories<> $GITHUB_OUTPUT - echo "$CHANGED_DIRS" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - - name: Validate Docker Compose files syntax - id: validate-compose-syntax - run: | - echo "🔍 Validating Docker Compose files syntax..." - - ERROR=0 - COMPOSE_FILES="${{ steps.changed-files.outputs.compose_files }}" - - if [ -z "$COMPOSE_FILES" ]; then - echo "ℹ️ No docker-compose.yml files changed, skipping validation" - exit 0 - fi - - echo "$COMPOSE_FILES" | while read -r compose_file; do - if [ -z "$compose_file" ]; then - continue - fi - - TEMPLATE_DIR=$(dirname "$compose_file") - TEMPLATE_NAME=$(basename "$TEMPLATE_DIR") - - echo "" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "📦 Validating syntax: $TEMPLATE_NAME" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - - # Validar sintaxis de docker-compose.yml usando docker compose - echo "🔍 Validating docker-compose.yml syntax..." - if ! docker compose -f "$compose_file" config > /dev/null 2>&1; then - echo "❌ ERROR: docker-compose.yml syntax is invalid in $TEMPLATE_NAME" - echo "Running docker compose config to show errors:" - docker compose -f "$compose_file" config 2>&1 || true - ERROR=1 - else - echo "✅ docker-compose.yml syntax is valid" - fi - - # Obtener lista de servicios del compose - SERVICES=$(docker compose -f "$compose_file" config --services 2>/dev/null || echo "") - echo "📋 Services found in docker-compose.yml:" - echo "$SERVICES" | while read service; do - [ -n "$service" ] && echo " - $service" - done - - # Guardar servicios para validación posterior - echo "$SERVICES" > "/tmp/${TEMPLATE_NAME}_services.txt" + echo "Changed blueprints:" + echo "$CHANGED_BLUEPRINTS" | while read blueprint; do + [ -n "$blueprint" ] && echo " - $blueprint" done - if [ $ERROR -eq 1 ]; then - echo "" - echo "❌ Docker Compose syntax validation failed" - exit 1 - else - echo "" - echo "✅ All Docker Compose files have valid syntax" - fi + # Guardar lista de blueprints (una por línea) + echo "blueprints<> $GITHUB_OUTPUT + echo "$CHANGED_BLUEPRINTS" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT - - name: Validate Docker Compose best practices - id: validate-compose-practices + - name: Validate blueprints run: | - echo "🔍 Validating Docker Compose best practices..." + BLUEPRINTS="${{ steps.changed.outputs.blueprints }}" - ERROR=0 - COMPOSE_FILES="${{ steps.changed-files.outputs.compose_files }}" - - if [ -z "$COMPOSE_FILES" ]; then - echo "ℹ️ No docker-compose.yml files changed, skipping validation" + if [ -z "$BLUEPRINTS" ] || [ "$BLUEPRINTS" = "" ]; then + echo "ℹ️ No blueprints changed, skipping validation" exit 0 fi - # Convert to array to avoid subshell issues with pipe - # This ensures ERROR=1 inside the loop propagates to the parent shell - mapfile -t COMPOSE_ARRAY <<< "$COMPOSE_FILES" - - for compose_file in "${COMPOSE_ARRAY[@]}"; do - if [ -z "$compose_file" ]; then - continue - fi - - TEMPLATE_DIR=$(dirname "$compose_file") - TEMPLATE_NAME=$(basename "$TEMPLATE_DIR") - - echo "" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "📦 Validating best practices: $TEMPLATE_NAME" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - - # Validar usando el script de TypeScript - if ! (cd build-scripts && pnpm exec tsx validate-docker-compose.ts --file "../$compose_file" --verbose); then - ERROR=1 - fi - done - - if [ $ERROR -eq 1 ]; then - echo "" - echo "❌ Docker Compose best practices validation failed" - exit 1 - else - echo "" - echo "✅ All Docker Compose files follow best practices" - fi - - - name: Validate template.toml files - id: validate-toml - run: | - echo "🔍 Validating template.toml files..." - ERROR=0 - DIRECTORIES="${{ steps.changed-files.outputs.directories }}" - if [ -z "$DIRECTORIES" ]; then - echo "ℹ️ No template directories changed, skipping TOML validation" - exit 0 - fi + # Convertir a array para evitar problemas con subshells + mapfile -t BLUEPRINT_ARRAY <<< "$BLUEPRINTS" - # Convert to array to avoid subshell issues with pipe - # This ensures ERROR=1 inside the loop propagates to the parent shell - mapfile -t DIRS_ARRAY <<< "$DIRECTORIES" - - for template_dir in "${DIRS_ARRAY[@]}"; do - if [ -z "$template_dir" ]; then - continue - fi + # Iterar sobre cada blueprint + for blueprint in "${BLUEPRINT_ARRAY[@]}"; do + [ -z "$blueprint" ] && continue - TEMPLATE_PATH="blueprints/$template_dir" - TOML_FILE="$TEMPLATE_PATH/template.toml" - - if [ ! -f "$TOML_FILE" ]; then - echo "⚠️ WARNING: template.toml not found in $template_dir (might be deleted)" - continue - fi + BLUEPRINT_PATH="blueprints/$blueprint" + COMPOSE_FILE="$BLUEPRINT_PATH/docker-compose.yml" + TOML_FILE="$BLUEPRINT_PATH/template.toml" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "📝 Validating: $template_dir/template.toml" + echo "📦 Validating: $blueprint" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - # Validar usando el script de TypeScript con tsx - # Ejecutar desde build-scripts para tener acceso a node_modules - if ! (cd build-scripts && pnpm exec tsx validate-template.ts --dir "../$TEMPLATE_PATH" --verbose); then - ERROR=1 - fi - done - - if [ $ERROR -eq 1 ]; then - echo "" - echo "❌ template.toml validation failed" - exit 1 - else - echo "" - echo "✅ All template.toml files are valid" - fi - - - name: Test Docker Compose (dry-run) - id: test-compose - run: | - echo "🧪 Testing Docker Compose files (dry-run)..." - - ERROR=0 - DIRECTORIES="${{ steps.changed-files.outputs.directories }}" - - if [ -z "$DIRECTORIES" ]; then - echo "ℹ️ No template directories changed, skipping dry-run test" - exit 0 - fi - - echo "$DIRECTORIES" | while read -r template_dir; do - if [ -z "$template_dir" ]; then - continue - fi - - COMPOSE_FILE="blueprints/$template_dir/docker-compose.yml" - + # 1. Validar best practices de docker-compose.yml if [ ! -f "$COMPOSE_FILE" ]; then + echo "⚠️ WARNING: docker-compose.yml not found" + ERROR=1 + continue + fi + echo "🔍 Validating docker-compose.yml best practices..." + if ! (cd build-scripts && pnpm exec tsx validate-docker-compose.ts --file "../$COMPOSE_FILE" --verbose); then + ERROR=1 continue fi - echo "" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "🧪 Testing: $template_dir" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - - # Cambiar al directorio del template para resolver rutas relativas - cd "blueprints/$template_dir" - - # Validar que docker-compose puede parsear el archivo completamente - echo "🔍 Running docker compose config (full validation)..." - if docker compose config > /dev/null 2>&1; then - echo "✅ Docker Compose file is fully valid and can be processed" - - # Mostrar información útil - echo "📋 Configuration summary:" - docker compose config --services | while read service; do - [ -n "$service" ] && echo " Service: $service" - done + # 3. Validar template.toml + if [ -f "$TOML_FILE" ]; then + echo "🔍 Validating template.toml..." + if ! (cd build-scripts && pnpm exec tsx validate-template.ts --dir "../$BLUEPRINT_PATH" --verbose); then + ERROR=1 + continue + fi else - echo "❌ ERROR: Docker Compose file failed full validation" - docker compose config 2>&1 || true + echo "⚠️ WARNING: template.toml not found" ERROR=1 + continue fi - cd - > /dev/null + echo "✅ All validations passed for $blueprint" done if [ $ERROR -eq 1 ]; then echo "" - echo "❌ Docker Compose dry-run test failed" + echo "❌ Validation failed for one or more blueprints" exit 1 else echo "" - echo "✅ All Docker Compose files passed dry-run test" + echo "✅ All blueprints validated successfully" fi - - - name: Summary - if: always() - run: | - echo "" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "📊 Validation Summary" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - - if [ "${{ steps.validate-compose-syntax.outcome }}" == "success" ] && \ - [ "${{ steps.validate-compose-practices.outcome }}" == "success" ] && \ - [ "${{ steps.validate-toml.outcome }}" == "success" ] && \ - [ "${{ steps.test-compose.outcome }}" == "success" ]; then - echo "✅ All validations passed!" - echo "" - echo "Your Docker Compose and template.toml files are valid and ready to merge." - else - echo "❌ Some validations failed. Please review the errors above." - echo "" - echo "Common issues to check:" - echo " - docker-compose.yml syntax errors" - echo " - template.toml syntax errors" - echo " - serviceName in template.toml must match service names in docker-compose.yml" - echo " - Avoid using container_name, explicit networks, or port mappings" - fi - diff --git a/.gitignore b/.gitignore index b512c09d..2f8606a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -node_modules \ No newline at end of file +node_modules +package-lock.json +meta.json.backup.* diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..c34d6beb --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,212 @@ +# AGENTS.md: AI Collaboration Guide + +This document provides essential context for AI models interacting with this project. Adhering to these guidelines will ensure consistency and maintain code quality. + +## 1. Project Overview & Purpose + +- **Primary Goal:** This is the official repository for Dokploy Open Source Templates, maintaining Docker Compose templates for deploying 200+ open-source applications via Dokploy (a self-hosted PaaS alternative to Heroku). The project enables rapid, standardized deployment of OSS applications without manual configuration. +- **Business Domain:** Self-hosted Platform as a Service (PaaS), DevOps tooling, containerized application deployment, and open-source software distribution. + +## 2. Core Technologies & Stack + +- **Languages:** JavaScript (Node.js), TypeScript (React frontend), YAML (Docker Compose), TOML (template configuration), JSON (metadata), Shell (build scripts). +- **Frameworks & Runtimes:** Node.js runtime, Vite 5.x (for React 19.x frontend), Docker Compose v3.8+, React Router 7.x. +- **Databases:** No direct database usage in core project (templates may include various databases like PostgreSQL, MySQL, Redis, etc.). +- **Key Libraries/Dependencies:** + - **Core:** `nodemon` for development, custom Node.js scripts for meta processing. + - **Frontend:** `fuse.js` (fuzzy search), `zustand` (state management), `@iarna/toml` (TOML parsing), `shadcn/ui` components, `@radix-ui` primitives, `@codemirror` (code editor), `react-router-dom`, `tailwindcss`. + - **Build:** `vite-plugin-static-copy` for copying blueprints to dist. +- **Platforms:** Linux (primary), Docker containers, Dokploy PaaS, Web browsers (for frontend preview), Cloudflare Pages (for PR previews). +- **Package Manager:** npm for root project, pnpm for frontend (`app/` directory). + +## 3. Architectural Patterns + +- **Overall Architecture:** Template collection and management system with decentralized blueprint architecture. Each blueprint is a self-contained Docker Compose application with Dokploy-specific configuration. +- **Directory Structure Philosophy:** + - `/blueprints`: Contains all deployable application templates, each as a subdirectory with `docker-compose.yml`, `template.toml`, and logo files. Each blueprint is independent with no shared state. + - `/app`: Vite + React + TypeScript frontend for local preview and development. + - `/src/components`: React components (UI components in `/ui` subdirectory using shadcn/ui). + - `/src/hooks`: Custom React hooks (e.g., `useFuseSearch.ts` for fuzzy search). + - `/src/store`: Zustand state management store. + - `/src/lib`: Utility functions and helpers. + - `/build-scripts`: Advanced meta.json processing tools with CLI options and JSON schema validation. + - `/.github/workflows`: CI/CD workflows for validation, preview builds, and deployments. + - Root level: Core processing scripts (`dedupe-and-sort-meta.js`), metadata index (`meta.json`), build configuration (`Makefile`, `package.json`). +- **Module Organization:** Node.js scripts for metadata processing, React components for frontend UI, Docker Compose files for service definitions, TOML files for Dokploy configuration. Frontend uses component-based architecture with hooks for business logic and Zustand for global state. + +## 4. Coding Conventions & Style Guide + +- **Formatting:** JavaScript follows standard conventions with 2-space indentation. TypeScript in frontend uses ESLint configuration. YAML uses 2-space indentation. TOML files use standard formatting. +- **Naming Conventions:** + - Variables, functions: camelCase (`myVariable`, `myFunction`) + - React components: PascalCase (`TemplateGrid`, `SearchBar`) + - Constants: SCREAMING_SNAKE_CASE (`MAX_BUFFER_SIZE`) + - Template IDs: lowercase, kebab-case (`activepieces`, `ghost`) - **MUST** be unique across repository + - Files: snake_case for scripts (`dedupe-and-sort-meta.js`), PascalCase for React components (`TemplateGrid.tsx`), kebab-case for directories (`build-scripts`) + - Docker services: **MUST** match blueprint folder name exactly (e.g., `ghost` service in `blueprints/ghost/`) +- **API Design:** + - **Backend:** Procedural scripting approach with CLI interfaces. Template system uses declarative configuration over imperative code. + - **Frontend:** Component-based React architecture with hooks for logic separation. Zustand for centralized state management. Custom hooks encapsulate complex logic (e.g., `useFuseSearch` for search functionality). +- **Common Patterns & Idioms:** + - **Metaprogramming:** Minimal use of advanced JavaScript features in scripts, focusing on simple, maintainable code. + - **Memory Management:** Relies on Node.js garbage collection and React's automatic memory management. + - **Polymorphism:** Uses JavaScript prototype-based objects and functional programming patterns. React components use composition over inheritance. + - **Type Safety:** + - Backend scripts: JavaScript with JSDoc comments for documentation. + - Frontend: TypeScript with strict type checking enabled. + - **Concurrency:** + - Backend: Synchronous processing model for meta.json operations. + - Frontend: React's concurrent rendering, `useDeferredValue` for debouncing, `useEffect` for async operations. + - **State Management:** Zustand store pattern with selectors for optimal re-renders. URL params synced with search state via React Router. +- **Error Handling:** + - Backend: Node.js error-first callback pattern and try-catch blocks. Scripts validate JSON structure and fail fast on errors. + - Frontend: Error boundaries for React components, try-catch for async operations, user-friendly error messages via toast notifications. + +## 5. Key Files & Entrypoints + +- **Main Entrypoints:** + - **Backend:** `dedupe-and-sort-meta.js` - Primary script for processing meta.json file. + - **Frontend:** `app/src/main.tsx` - React application entry point. +- **Configuration:** + - `package.json` - Root Node.js project configuration and npm scripts. + - `app/package.json` - Frontend dependencies and pnpm scripts. + - `meta.json` - Centralized template registry (200+ entries). + - `Makefile` - Build automation with targets for processing, validation, and cleanup. + - `app/vite.config.ts` - Vite build configuration with static copy plugin. + - `app/tsconfig.json` - TypeScript compiler configuration. +- **CI/CD Pipeline:** + - `.github/workflows/validate-meta.yml` - Validates meta.json structure, duplicates, and sort order. + - `.github/workflows/build-preview.yml` - Builds preview deployments for PRs. + - `.github/workflows/deploy-preview.yml` - Deploys previews to Cloudflare Pages. + +## 6. Development & Testing Workflow + +- **Local Development Environment:** + - **Install dependencies** + + ```bash + # Root project + npm install + + # Frontend (uses pnpm) + cd app && pnpm install + ``` + + - **Process meta.json** (CRITICAL: Run after ANY meta.json edits) + ```bash + npm run process-meta + # or + make process-meta + # or + node dedupe-and-sort-meta.js + ``` + - **Validate without modifying** + ```bash + npm run validate-meta + # or + make validate + ``` + - **Quick check for duplicates/sort status** + ```bash + make check + ``` + - **Clean backup files** + ```bash + make clean + ``` +- **Task Configuration:** + - **NPM Scripts:** Run `npm run` to list available scripts. Key scripts: + - `process-meta`: Remove duplicates and sort meta.json + - `process-meta-verbose`: Process with detailed output + - `validate-meta`: Validate structure without changes + - **Makefile Targets:** Run `make help` to list targets. Key targets: + - `process-meta`: Process meta.json + - `validate`: Validate without modifying + - `check`: Quick duplicate/sort check + - `build`: Full build process + - `clean`: Remove backup files +- **Testing:** No formal unit testing framework. Validation occurs through: + - Script-based validation of meta.json structure and schema + - Manual testing via Dokploy preview deployments (import base64 from PR preview) + - JSON schema validation in `build-scripts/process-meta.js` + - TypeScript compilation errors caught during build + - ESLint for code quality in frontend +- **CI/CD Process:** + - **On meta.json changes:** Validates structure, checks for duplicates, verifies sort order, compares processed vs original. + - **On PR creation:** Builds preview deployment, generates base64 import for testing in Dokploy. + - **Preview testing:** Use PR description link → Search template → Copy base64 → Import in Dokploy instance. + +## 7. Specific Instructions for AI Collaboration + +- **Contribution Guidelines:** + - Follow existing Dokploy template structure strictly. Each blueprint must be independent with no shared state. + - **CRITICAL:** Always run `node dedupe-and-sort-meta.js` or `npm run process-meta` after ANY meta.json edits. + - Test templates in Dokploy preview before submitting PRs (use base64 import from PR preview). + - Add logo file (SVG preferred, ~128x128px) to blueprint folder. + - Ensure template `id` in meta.json exactly matches blueprint folder name (lowercase kebab-case). +- **Docker Compose Conventions (CRITICAL):** + + - **Version:** MUST be `3.8` + - **NEVER include:** `ports` (use `expose` only), `container_name`, `networks` (Dokploy handles isolation) + - **ALWAYS include:** `restart: unless-stopped` or `restart: always`, persistent volumes + - **Service naming:** MUST match blueprint folder name exactly + - **Example:** + ```yaml + version: "3.8" + services: + ghost: + image: ghost:6-alpine + restart: always + volumes: + - ghost:/var/lib/ghost/content + volumes: + ghost: + ``` + +- **template.toml Conventions:** + + - **Variables:** Define in `[variables]` section, use helpers for secrets + - **Domains:** `[[config.domains]]` with `serviceName`, `port`, `host` (path optional) + - **Env:** Array of strings: `env = ["KEY=VALUE", "DB_PASSWORD=${db_pass}"]` + - **Available helpers:** `${domain}`, `${password:length}`, `${base64:length}`, `${hash:length}`, `${uuid}`, `${randomPort}`, `${email}`, `${username}`, `${timestamp}`, `${timestamps:datetime}`, `${timestampms:datetime}`, `${jwt:secret_var:payload_var}` + - **JWT helper example:** `${jwt:mysecret:mypayload}` with payload containing `exp: ${timestamps:2030-01-01T00:00:00Z}` + +- **meta.json Requirements:** + + - **Required fields:** `id`, `name`, `version`, `description`, `links` (with `github`), `logo`, `tags` (array) + - **Tags:** Lowercase strings (e.g., `["monitoring", "database"]`) + - **Version:** MUST match Docker image version in docker-compose.yml + - **Logo:** Filename only (e.g., `"ghost.jpeg"`), file must exist in blueprint folder + +- **Frontend Development:** + + - Use TypeScript with strict type checking + - Follow React hooks patterns, avoid class components + - Use Zustand selectors for state access to optimize re-renders + - Fuse.js searches across `name`, `description`, `tags`, `id` fields + - Use shadcn/ui components for consistency + - Sync URL params with search state via React Router + +- **Security:** + + - Be mindful of security when handling template configurations + - NEVER hardcode secrets in templates - use Dokploy's variable system with helpers + - Pin Docker images to specific versions to avoid supply chain attacks + - Validate user input in frontend before processing + +- **Dependencies:** + + - When adding new templates, ensure Docker images are pinned to specific versions + - Update meta.json with exact version matching Docker Compose image version + - For frontend dependencies: Use `pnpm add ` in `app/` directory + - For root dependencies: Use `npm install ` in root directory + +- **Commit Messages:** Follow conventional commit patterns (e.g., `feat:`, `fix:`, `docs:`, `chore:`). + +- **Common Pitfalls to Avoid:** + 1. Forgetting to process meta.json after editing (CI will fail) + 2. Template ID mismatch between meta.json and folder name + 3. Including `ports`, `container_name`, or `networks` in docker-compose.yml + 4. Using object syntax for env vars in template.toml (must be array of strings) + 5. Logo file missing or filename mismatch in meta.json + 6. Version mismatch between meta.json and docker-compose.yml image tag diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 657ce29d..2671d5af 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -148,7 +148,6 @@ Use these in `${}` for dynamic values: - Omit explicit ports; let Dokploy handle exposure. - Use persistent volumes for data (e.g., databases). - - Set `restart: unless-stopped` for services. - **Template.toml**: diff --git a/blueprints/appwrite/docker-compose.yml b/blueprints/appwrite/docker-compose.yml index 130bb5d3..cb622284 100644 --- a/blueprints/appwrite/docker-compose.yml +++ b/blueprints/appwrite/docker-compose.yml @@ -6,31 +6,32 @@ x-logging: &x-logging options: max-file: "5" max-size: "10m" - services: appwrite: - image: appwrite/appwrite:1.6.1 - container_name: appwrite + image: appwrite/appwrite:1.8.0 <<: *x-logging restart: unless-stopped - networks: - - dokploy-network labels: - traefik.enable=true - traefik.constraint-label-stack=appwrite volumes: - appwrite-uploads:/storage/uploads:rw + - appwrite-imports:/storage/imports:rw - appwrite-cache:/storage/cache:rw - appwrite-config:/storage/config:rw - appwrite-certificates:/storage/certificates:rw - appwrite-functions:/storage/functions:rw + - appwrite-sites:/storage/sites:rw + - appwrite-builds:/storage/builds:rw depends_on: - mariadb - redis + # - clamav environment: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_LOCALE + - _APP_COMPRESSION_MIN_SIZE_BYTES - _APP_CONSOLE_WHITELIST_ROOT - _APP_CONSOLE_WHITELIST_EMAILS - _APP_CONSOLE_SESSION_ALERTS @@ -43,10 +44,14 @@ services: - _APP_OPTIONS_ABUSE - _APP_OPTIONS_ROUTER_PROTECTION - _APP_OPTIONS_FORCE_HTTPS - - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS + - _APP_OPTIONS_ROUTER_FORCE_HTTPS - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - - _APP_DOMAIN_TARGET + - _APP_DOMAIN_TARGET_CNAME + - _APP_DOMAIN_TARGET_AAAA + - _APP_DOMAIN_TARGET_A + - _APP_DOMAIN_TARGET_CAA + - _APP_DNS - _APP_DOMAIN_FUNCTIONS - _APP_REDIS_HOST - _APP_REDIS_PORT @@ -73,6 +78,7 @@ services: - _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_S3_ENDPOINT - _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_REGION @@ -89,21 +95,26 @@ services: - _APP_STORAGE_WASABI_SECRET - _APP_STORAGE_WASABI_REGION - _APP_STORAGE_WASABI_BUCKET - - _APP_FUNCTIONS_SIZE_LIMIT + - _APP_COMPUTE_SIZE_LIMIT - _APP_FUNCTIONS_TIMEOUT - - _APP_FUNCTIONS_BUILD_TIMEOUT - - _APP_FUNCTIONS_CPUS - - _APP_FUNCTIONS_MEMORY + - _APP_SITES_TIMEOUT + - _APP_COMPUTE_BUILD_TIMEOUT + - _APP_COMPUTE_CPUS + - _APP_COMPUTE_MEMORY - _APP_FUNCTIONS_RUNTIMES + - _APP_SITES_RUNTIMES + - _APP_DOMAIN_SITES - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST - _APP_LOGGING_CONFIG - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_DELAY + - _APP_MAINTENANCE_START_TIME - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE - _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_AUDIT + - _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_SCHEDULES - _APP_SMS_PROVIDER @@ -120,94 +131,25 @@ services: - _APP_MIGRATIONS_FIREBASE_CLIENT_ID - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET - _APP_ASSISTANT_OPENAI_API_KEY - appwrite-console: - image: appwrite/console:5.0.12 - container_name: appwrite-console <<: *x-logging + image: appwrite/console:7.4.7 restart: unless-stopped - networks: - - dokploy-network labels: - "traefik.enable=true" - "traefik.constraint-label-stack=appwrite" - environment: - - _APP_ENV - - _APP_WORKER_PER_CORE - - _APP_LOCALE - - _APP_CONSOLE_WHITELIST_ROOT - - _APP_CONSOLE_WHITELIST_EMAILS - - _APP_CONSOLE_SESSION_ALERTS - - _APP_CONSOLE_WHITELIST_IPS - - _APP_CONSOLE_HOSTNAMES - - _APP_SYSTEM_EMAIL_NAME - - _APP_SYSTEM_EMAIL_ADDRESS - - _APP_EMAIL_SECURITY - - _APP_SYSTEM_RESPONSE_FORMAT - - _APP_OPTIONS_ABUSE - - _APP_OPTIONS_ROUTER_PROTECTION - - _APP_OPTIONS_FORCE_HTTPS - - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS - - _APP_OPENSSL_KEY_V1 - - _APP_DOMAIN - - _APP_DOMAIN_TARGET - - _APP_DOMAIN_FUNCTIONS - - _APP_REDIS_HOST - - _APP_REDIS_PORT - - _APP_REDIS_USER - - _APP_REDIS_PASS - - _APP_DB_HOST - - _APP_DB_PORT - - _APP_DB_SCHEMA - - _APP_DB_USER - - _APP_DB_PASS - - _APP_SMTP_HOST - - _APP_SMTP_PORT - - _APP_SMTP_SECURE - - _APP_SMTP_USERNAME - - _APP_SMTP_PASSWORD - - _APP_USAGE_STATS - - _APP_STORAGE_LIMIT - - _APP_STORAGE_PREVIEW_LIMIT - - _APP_STORAGE_ANTIVIRUS - - _APP_STORAGE_ANTIVIRUS_HOST - - _APP_STORAGE_ANTIVIRUS_PORT - - _APP_STORAGE_DEVICE - - _APP_STORAGE_S3_ACCESS_KEY - - _APP_STORAGE_S3_SECRET - - _APP_STORAGE_S3_REGION - - _APP_STORAGE_S3_BUCKET - - _APP_STORAGE_DO_SPACES_ACCESS_KEY - - _APP_STORAGE_DO_SPACES_SECRET - - _APP_STORAGE_DO_SPACES_REGION - - _APP_STORAGE_DO_SPACES_BUCKET - - _APP_STORAGE_BACKBLAZE_ACCESS_KEY - - _APP_STORAGE_BACKBLAZE_SECRET - - _APP_STORAGE_BACKBLAZE_REGION - - _APP_STORAGE_BACKBLAZE_BUCKET - - _APP_STORAGE_LINODE_ACCESS_KEY - - _APP_STORAGE_LINODE_SECRET - - _APP_STORAGE_LINODE_REGION - - _APP_STORAGE_LINODE_BUCKET - - _APP_STORAGE_WASABI_ACCESS_KEY - - _APP_STORAGE_WASABI_SECRET - - _APP_STORAGE_WASABI_REGION - - _APP_STORAGE_WASABI_BUCKET appwrite-realtime: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: realtime - container_name: appwrite-realtime <<: *x-logging restart: unless-stopped - networks: - - dokploy-network + labels: + - "traefik.enable=true" + - "traefik.constraint-label-stack=appwrite" depends_on: - mariadb - redis - labels: - - "traefik.enable=true" - - "traefik.constraint-label-stack=appwrite" environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -227,13 +169,10 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-audits: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-audits <<: *x-logging - container_name: appwrite-worker-audits restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb @@ -253,13 +192,10 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-webhooks: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-webhooks <<: *x-logging - container_name: appwrite-worker-webhooks restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb @@ -281,13 +217,10 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-deletes: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-deletes <<: *x-logging - container_name: appwrite-worker-deletes restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb @@ -295,6 +228,7 @@ services: - appwrite-uploads:/storage/uploads:rw - appwrite-cache:/storage/cache:rw - appwrite-functions:/storage/functions:rw + - appwrite-sites:/storage/sites:rw - appwrite-builds:/storage/builds:rw - appwrite-certificates:/storage/certificates:rw environment: @@ -315,6 +249,7 @@ services: - _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_S3_ENDPOINT - _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_REGION @@ -336,16 +271,16 @@ services: - _APP_EXECUTOR_HOST - _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_AUDIT + - _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE - _APP_MAINTENANCE_RETENTION_EXECUTION + - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - _APP_EMAIL_CERTIFICATES appwrite-worker-databases: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-databases <<: *x-logging - container_name: appwrite-worker-databases restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb @@ -365,19 +300,18 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-builds: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-builds <<: *x-logging - container_name: appwrite-worker-builds restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb volumes: - appwrite-functions:/storage/functions:rw + - appwrite-sites:/storage/sites:rw - appwrite-builds:/storage/builds:rw + - appwrite-uploads:/storage/uploads:rw environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -398,18 +332,20 @@ services: - _APP_VCS_GITHUB_PRIVATE_KEY - _APP_VCS_GITHUB_APP_ID - _APP_FUNCTIONS_TIMEOUT - - _APP_FUNCTIONS_BUILD_TIMEOUT - - _APP_FUNCTIONS_CPUS - - _APP_FUNCTIONS_MEMORY - - _APP_FUNCTIONS_SIZE_LIMIT + - _APP_SITES_TIMEOUT + - _APP_COMPUTE_BUILD_TIMEOUT + - _APP_COMPUTE_CPUS + - _APP_COMPUTE_MEMORY + - _APP_COMPUTE_SIZE_LIMIT - _APP_OPTIONS_FORCE_HTTPS - - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS + - _APP_OPTIONS_ROUTER_FORCE_HTTPS - _APP_DOMAIN - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_S3_ENDPOINT - _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_REGION @@ -426,15 +362,13 @@ services: - _APP_STORAGE_WASABI_SECRET - _APP_STORAGE_WASABI_REGION - _APP_STORAGE_WASABI_BUCKET + - _APP_DOMAIN_SITES appwrite-worker-certificates: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-certificates <<: *x-logging - container_name: appwrite-worker-certificates restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb @@ -446,7 +380,11 @@ services: - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - - _APP_DOMAIN_TARGET + - _APP_DOMAIN_TARGET_CNAME + - _APP_DOMAIN_TARGET_AAAA + - _APP_DOMAIN_TARGET_A + - _APP_DOMAIN_TARGET_CAA + - _APP_DNS - _APP_DOMAIN_FUNCTIONS - _APP_EMAIL_CERTIFICATES - _APP_REDIS_HOST @@ -461,13 +399,10 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-functions: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-functions <<: *x-logging - container_name: appwrite-worker-functions restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb @@ -488,9 +423,10 @@ services: - _APP_DB_USER - _APP_DB_PASS - _APP_FUNCTIONS_TIMEOUT - - _APP_FUNCTIONS_BUILD_TIMEOUT - - _APP_FUNCTIONS_CPUS - - _APP_FUNCTIONS_MEMORY + - _APP_SITES_TIMEOUT + - _APP_COMPUTE_BUILD_TIMEOUT + - _APP_COMPUTE_CPUS + - _APP_COMPUTE_MEMORY - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST - _APP_USAGE_STATS @@ -499,13 +435,10 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-mails: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-mails <<: *x-logging - container_name: appwrite-worker-mails restart: unless-stopped - networks: - - dokploy-network depends_on: - redis environment: @@ -529,15 +462,14 @@ services: - _APP_SMTP_USERNAME - _APP_SMTP_PASSWORD - _APP_LOGGING_CONFIG + - _APP_DOMAIN + - _APP_OPTIONS_FORCE_HTTPS appwrite-worker-messaging: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-messaging - container_name: appwrite-worker-messaging <<: *x-logging restart: unless-stopped - networks: - - dokploy-network volumes: - appwrite-uploads:/storage/uploads:rw depends_on: @@ -563,6 +495,7 @@ services: - _APP_STORAGE_S3_SECRET - _APP_STORAGE_S3_REGION - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_S3_ENDPOINT - _APP_STORAGE_DO_SPACES_ACCESS_KEY - _APP_STORAGE_DO_SPACES_SECRET - _APP_STORAGE_DO_SPACES_REGION @@ -581,13 +514,12 @@ services: - _APP_STORAGE_WASABI_BUCKET appwrite-worker-migrations: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: worker-migrations <<: *x-logging - container_name: appwrite-worker-migrations restart: unless-stopped - networks: - - dokploy-network + volumes: + - appwrite-imports:/storage/imports:rw depends_on: - mariadb environment: @@ -595,7 +527,11 @@ services: - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - - _APP_DOMAIN_TARGET + - _APP_DOMAIN_TARGET_CNAME + - _APP_DOMAIN_TARGET_AAAA + - _APP_DOMAIN_TARGET_A + - _APP_DOMAIN_TARGET_CAA + - _APP_DNS - _APP_EMAIL_SECURITY - _APP_REDIS_HOST - _APP_REDIS_PORT @@ -611,20 +547,21 @@ services: - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET appwrite-task-maintenance: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: maintenance <<: *x-logging - container_name: appwrite-task-maintenance restart: unless-stopped - networks: - - dokploy-network depends_on: - redis environment: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_DOMAIN - - _APP_DOMAIN_TARGET + - _APP_DOMAIN_TARGET_CNAME + - _APP_DOMAIN_TARGET_AAAA + - _APP_DOMAIN_TARGET_A + - _APP_DOMAIN_TARGET_CAA + - _APP_DNS - _APP_DOMAIN_FUNCTIONS - _APP_OPENSSL_KEY_V1 - _APP_REDIS_HOST @@ -641,17 +578,15 @@ services: - _APP_MAINTENANCE_RETENTION_CACHE - _APP_MAINTENANCE_RETENTION_ABUSE - _APP_MAINTENANCE_RETENTION_AUDIT + - _APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_SCHEDULES - appwrite-worker-usage: - image: appwrite/appwrite:1.6.1 - entrypoint: worker-usage - container_name: appwrite-worker-usage + appwrite-task-stats-resources: + image: appwrite/appwrite:1.8.0 + entrypoint: stats-resources <<: *x-logging restart: unless-stopped - networks: - - dokploy-network depends_on: - redis - mariadb @@ -670,15 +605,39 @@ services: - _APP_REDIS_PASS - _APP_USAGE_STATS - _APP_LOGGING_CONFIG - - _APP_USAGE_AGGREGATION_INTERVAL + - _APP_DATABASE_SHARED_TABLES + - _APP_STATS_RESOURCES_INTERVAL - appwrite-worker-usage-dump: - image: appwrite/appwrite:1.6.1 - entrypoint: worker-usage-dump - container_name: appwrite-worker-usage-dump + appwrite-worker-stats-resources: + image: appwrite/appwrite:1.8.0 + entrypoint: worker-stats-resources <<: *x-logging - networks: - - dokploy-network + restart: unless-stopped + depends_on: + - redis + - mariadb + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_USAGE_STATS + - _APP_LOGGING_CONFIG + - _APP_STATS_RESOURCES_INTERVAL + + appwrite-worker-stats-usage: + image: appwrite/appwrite:1.8.0 + entrypoint: worker-stats-usage + <<: *x-logging + restart: unless-stopped depends_on: - redis - mariadb @@ -700,13 +659,10 @@ services: - _APP_USAGE_AGGREGATION_INTERVAL appwrite-task-scheduler-functions: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: schedule-functions - container_name: appwrite-task-scheduler-functions <<: *x-logging restart: unless-stopped - networks: - - dokploy-network depends_on: - mariadb - redis @@ -725,13 +681,10 @@ services: - _APP_DB_PASS appwrite-task-scheduler-executions: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: schedule-executions - container_name: appwrite-task-scheduler-executions <<: *x-logging restart: unless-stopped - networks: - - dokploy-network depends_on: - mariadb - redis @@ -750,13 +703,10 @@ services: - _APP_DB_PASS appwrite-task-scheduler-messages: - image: appwrite/appwrite:1.6.1 + image: appwrite/appwrite:1.8.0 entrypoint: schedule-messages - container_name: appwrite-task-scheduler-messages <<: *x-logging restart: unless-stopped - networks: - - dokploy-network depends_on: - mariadb - redis @@ -775,44 +725,48 @@ services: - _APP_DB_PASS appwrite-assistant: - image: appwrite/assistant:0.4.0 - container_name: appwrite-assistant + image: appwrite/assistant:0.8.3 <<: *x-logging restart: unless-stopped - networks: - - dokploy-network environment: - _APP_ASSISTANT_OPENAI_API_KEY + appwrite-browser: + image: appwrite/browser:0.2.4 + <<: *x-logging + restart: unless-stopped + openruntimes-executor: - container_name: openruntimes-executor hostname: exc1 <<: *x-logging restart: unless-stopped stop_signal: SIGINT - image: openruntimes/executor:0.6.11 - networks: - - dokploy-network + image: openruntimes/executor:0.7.22 volumes: - /var/run/docker.sock:/var/run/docker.sock - appwrite-builds:/storage/builds:rw - appwrite-functions:/storage/functions:rw + - appwrite-sites:/storage/sites:rw + # Host mount necessary to share files between executor and runtimes. + # It's not possible to share mount file between 2 containers without host mount (copying is too slow) - /tmp:/tmp:rw environment: - - OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD - - OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL - - OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK + - OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_COMPUTE_INACTIVE_THRESHOLD + - OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_COMPUTE_MAINTENANCE_INTERVAL + - OPR_EXECUTOR_NETWORK=$_APP_COMPUTE_RUNTIMES_NETWORK - OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME - OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD - OPR_EXECUTOR_ENV=$_APP_ENV - - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES + - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET + - OPR_EXECUTOR_RUNTIME_VERSIONS=v5 - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY - OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET - OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION - OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET + - OPR_EXECUTOR_STORAGE_S3_ENDPOINT=$_APP_STORAGE_S3_ENDPOINT - OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY - OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET - OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION @@ -831,12 +785,9 @@ services: - OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET mariadb: - image: mariadb:10.11 - container_name: appwrite-mariadb + image: mariadb:10.11 # fix issues when upgrading using: mysql_upgrade -u root -p <<: *x-logging restart: unless-stopped - networks: - - dokploy-network volumes: - appwrite-mariadb:/var/lib/mysql:rw environment: @@ -849,39 +800,30 @@ services: redis: image: redis:7.2.4-alpine - container_name: appwrite-redis <<: *x-logging restart: unless-stopped command: > redis-server - --maxmemory 512mb - --maxmemory-policy allkeys-lru - --maxmemory-samples 5 - networks: - - dokploy-network + --maxmemory 512mb + --maxmemory-policy allkeys-lru + --maxmemory-samples 5 volumes: - appwrite-redis:/data:rw -# Uncomment and configure if ClamAV is needed -# clamav: -# image: appwrite/clamav:1.2.0 -# container_name: appwrite-clamav -# restart: unless-stopped -# networks: -# - dokploy-network -# volumes: -# - appwrite-uploads:/storage/uploads + # clamav: + # image: appwrite/clamav:1.2.0 + # restart: unless-stopped + # volumes: + # - appwrite-uploads:/storage/uploads volumes: appwrite-mariadb: appwrite-redis: appwrite-cache: appwrite-uploads: + appwrite-imports: appwrite-certificates: appwrite-functions: + appwrite-sites: appwrite-builds: appwrite-config: - -networks: - dokploy-network: - external: true diff --git a/blueprints/appwrite/template.toml b/blueprints/appwrite/template.toml index 3188ea17..cca2d43d 100644 --- a/blueprints/appwrite/template.toml +++ b/blueprints/appwrite/template.toml @@ -1,5 +1,11 @@ [variables] main_domain = "${domain}" +functions_domain = "functions.${main_domain}" +sites_domain = "sites.${main_domain}" +openssl_key = "${password:32}" +db_root_pw = "${password:32}" +db_user_pw = "${password:32}" +executor_secret = "${password:32}" [config] env = [ @@ -8,11 +14,19 @@ env = [ "_APP_OPTIONS_ABUSE=enabled", "_APP_OPTIONS_FORCE_HTTPS=disabled", "_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=disabled", + "_APP_OPTIONS_ROUTER_FORCE_HTTPS=disabled", "_APP_OPTIONS_ROUTER_PROTECTION=disabled", - "_APP_OPENSSL_KEY_V1=your-secret-key", + "_APP_OPENSSL_KEY_V1=${openssl_key}", "_APP_DOMAIN=${main_domain}", - "_APP_DOMAIN_FUNCTIONS=${main_domain}", - "_APP_DOMAIN_TARGET=${main_domain}", + "_APP_CUSTOM_DOMAIN_DENY_LIST=example.com,test.com,app.example.com", + "_APP_DOMAIN_FUNCTIONS=${functions_domain}", + "_APP_DOMAIN_SITES=${sites_domain}", + "_APP_DOMAIN_TARGET=localhost", + "_APP_DOMAIN_TARGET_CNAME=localhost", + "_APP_DOMAIN_TARGET_AAAA=::1", + "_APP_DOMAIN_TARGET_A=127.0.0.1", + "_APP_DOMAIN_TARGET_CAA=", + "_APP_DNS=8.8.8.8", "_APP_CONSOLE_WHITELIST_ROOT=enabled", "_APP_CONSOLE_WHITELIST_EMAILS=", "_APP_CONSOLE_WHITELIST_IPS=", @@ -32,6 +46,8 @@ env = [ "_APP_USAGE_DATABASE_INTERVAL=900", "_APP_WORKER_PER_CORE=6", "_APP_CONSOLE_SESSION_ALERTS=disabled", + "_APP_COMPRESSION_ENABLED=enabled", + "_APP_COMPRESSION_MIN_SIZE_BYTES=1024", "_APP_REDIS_HOST=redis", "_APP_REDIS_PORT=6379", "_APP_REDIS_USER=", @@ -40,8 +56,8 @@ env = [ "_APP_DB_PORT=3306", "_APP_DB_SCHEMA=appwrite", "_APP_DB_USER=user", - "_APP_DB_PASS=password", - "_APP_DB_ROOT_PASS=rootsecretpassword", + "_APP_DB_PASS=${db_user_pw}", + "_APP_DB_ROOT_PASS=${db_root_pw}", "_APP_INFLUXDB_HOST=influxdb", "_APP_INFLUXDB_PORT=8086", "_APP_STATSD_HOST=telegraf", @@ -63,6 +79,7 @@ env = [ "_APP_STORAGE_S3_SECRET=", "_APP_STORAGE_S3_REGION=us-east-1", "_APP_STORAGE_S3_BUCKET=", + "_APP_STORAGE_S3_ENDPOINT=", "_APP_STORAGE_DO_SPACES_ACCESS_KEY=", "_APP_STORAGE_DO_SPACES_SECRET=", "_APP_STORAGE_DO_SPACES_REGION=us-east-1", @@ -80,27 +97,36 @@ env = [ "_APP_STORAGE_WASABI_REGION=eu-central-1", "_APP_STORAGE_WASABI_BUCKET=", "_APP_FUNCTIONS_SIZE_LIMIT=30000000", + "_APP_COMPUTE_SIZE_LIMIT=30000000", "_APP_FUNCTIONS_BUILD_SIZE_LIMIT=2000000000", "_APP_FUNCTIONS_TIMEOUT=900", "_APP_FUNCTIONS_BUILD_TIMEOUT=900", + "_APP_COMPUTE_BUILD_TIMEOUT=900", "_APP_FUNCTIONS_CONTAINERS=10", "_APP_FUNCTIONS_CPUS=0", + "_APP_COMPUTE_CPUS=0", "_APP_FUNCTIONS_MEMORY=0", + "_APP_COMPUTE_MEMORY=0", "_APP_FUNCTIONS_MEMORY_SWAP=0", "_APP_FUNCTIONS_RUNTIMES=node-16.0,php-8.0,python-3.9,ruby-3.0", - "_APP_EXECUTOR_SECRET=your-secret-key", + "_APP_EXECUTOR_SECRET=${executor_secret}", "_APP_EXECUTOR_HOST=http://exc1/v1", "_APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes", "_APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0", "_APP_FUNCTIONS_INACTIVE_THRESHOLD=60", + "_APP_COMPUTE_INACTIVE_THRESHOLD=60", "DOCKERHUB_PULL_USERNAME=", "DOCKERHUB_PULL_PASSWORD=", "DOCKERHUB_PULL_EMAIL=", "OPEN_RUNTIMES_NETWORK=appwrite_runtimes", - "_APP_FUNCTIONS_RUNTIMES_NETWORK=runtimes", + "_APP_FUNCTIONS_RUNTIMES_NETWORK=dokploy-network", + "_APP_COMPUTE_RUNTIMES_NETWORK=dokploy-network", "_APP_DOCKER_HUB_USERNAME=", "_APP_DOCKER_HUB_PASSWORD=", "_APP_FUNCTIONS_MAINTENANCE_INTERVAL=3600", + "_APP_COMPUTE_MAINTENANCE_INTERVAL=3600", + "_APP_SITES_TIMEOUT=900", + "_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.29", "_APP_VCS_GITHUB_APP_NAME=", "_APP_VCS_GITHUB_PRIVATE_KEY=", "_APP_VCS_GITHUB_APP_ID=", @@ -109,9 +135,11 @@ env = [ "_APP_VCS_GITHUB_WEBHOOK_SECRET=", "_APP_MAINTENANCE_INTERVAL=86400", "_APP_MAINTENANCE_DELAY=0", + "_APP_MAINTENANCE_START_TIME=00:00", "_APP_MAINTENANCE_RETENTION_CACHE=2592000", "_APP_MAINTENANCE_RETENTION_EXECUTION=1209600", "_APP_MAINTENANCE_RETENTION_AUDIT=1209600", + "_APP_MAINTENANCE_RETENTION_AUDIT_CONSOLE=15778800", "_APP_MAINTENANCE_RETENTION_ABUSE=86400", "_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000", "_APP_MAINTENANCE_RETENTION_SCHEDULES=86400", @@ -130,6 +158,18 @@ port = 80 host = "${main_domain}" path = "/" +[[config.domains]] +serviceName = "appwrite" +port = 80 +host = "${sites_domain}" +path = "/" + +[[config.domains]] +serviceName = "appwrite" +port = 80 +host = "${functions_domain}" +path = "/" + [[config.domains]] serviceName = "appwrite-console" port = 80 diff --git a/blueprints/autobase/docker-compose.yml b/blueprints/autobase/docker-compose.yml index 07b99485..13b23d57 100644 --- a/blueprints/autobase/docker-compose.yml +++ b/blueprints/autobase/docker-compose.yml @@ -1,6 +1,6 @@ services: autobase-console: - image: autobase/console:2.3.0 + image: autobase/console:2.5.2 restart: unless-stopped ports: - "80" diff --git a/blueprints/capso/docker-compose.yml b/blueprints/capso/docker-compose.yml index 637b1ded..4714ef0c 100644 --- a/blueprints/capso/docker-compose.yml +++ b/blueprints/capso/docker-compose.yml @@ -17,6 +17,9 @@ services: S3_INTERNAL_ENDPOINT: "http://minio:3902" expose: - 3000 + depends_on: + - ps-mysql + - minio ps-mysql: image: mysql:8.0 @@ -34,11 +37,10 @@ services: - ps-mysql:/var/lib/mysql minio: - image: bitnami/minio:latest + image: quay.io/minio/minio:RELEASE.2025-05-24T17-08-30Z restart: unless-stopped + command: server /bitnami/minio/data --address ":3902" --console-address ":3903" environment: - MINIO_API_PORT_NUMBER: 3902 - MINIO_CONSOLE_PORT_NUMBER: 3903 MINIO_ROOT_USER: ${MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} expose: @@ -47,6 +49,11 @@ services: volumes: - minio-data:/bitnami/minio/data - minio-certs:/certs + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3902/minio/health/ready"] + interval: 30s + timeout: 20s + retries: 3 volumes: ps-mysql: diff --git a/blueprints/cloudreve/cloudreve.png b/blueprints/cloudreve/cloudreve.png new file mode 100644 index 00000000..28020b06 Binary files /dev/null and b/blueprints/cloudreve/cloudreve.png differ diff --git a/blueprints/cloudreve/docker-compose.yml b/blueprints/cloudreve/docker-compose.yml new file mode 100644 index 00000000..f90f3685 --- /dev/null +++ b/blueprints/cloudreve/docker-compose.yml @@ -0,0 +1,48 @@ +version: "3.8" + +services: + cloudreve: + image: cloudreve/cloudreve:4.10.1 + depends_on: + postgresql: + condition: service_healthy + redis: + condition: service_started + restart: unless-stopped + environment: + - CR_CONF_Database.Type=postgres + - CR_CONF_Database.Host=postgresql + - CR_CONF_Database.User=${POSTGRES_USER} + - CR_CONF_Database.Password=${POSTGRES_PASSWORD} + - CR_CONF_Database.Name=${POSTGRES_DB} + - CR_CONF_Database.Port=5432 + - CR_CONF_Redis.Server=redis:6379 + volumes: + - cloudreve_data:/cloudreve/data + + postgresql: + image: postgres:17 + restart: unless-stopped + environment: + - POSTGRES_USER + - POSTGRES_PASSWORD + - POSTGRES_DB + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + + redis: + image: redis:8.4.0 + restart: unless-stopped + volumes: + - redis_data:/data + +volumes: + cloudreve_data: + postgres_data: + redis_data: diff --git a/blueprints/cloudreve/template.toml b/blueprints/cloudreve/template.toml new file mode 100644 index 00000000..a5acf6b4 --- /dev/null +++ b/blueprints/cloudreve/template.toml @@ -0,0 +1,16 @@ +[variables] +main_domain = "${domain}" +db_password = "${password:32}" +db_user = "cloudreve" +db_name = "cloudreve" + +[config] +[[config.domains]] +serviceName = "cloudreve" +port = 5212 +host = "${main_domain}" + +[config.env] +POSTGRES_PASSWORD = "${db_password}" +POSTGRES_USER = "${db_user}" +POSTGRES_DB = "${db_name}" diff --git a/blueprints/discourse/docker-compose.yml b/blueprints/discourse/docker-compose.yml index 2b938b85..caafab5b 100644 --- a/blueprints/discourse/docker-compose.yml +++ b/blueprints/discourse/docker-compose.yml @@ -32,7 +32,7 @@ services: restart: unless-stopped discourse-app: - image: docker.io/bitnami/discourse:3.3.2 + image: docker.io/bitnamilegacy/discourse:3.5.0 volumes: - discourse-data:/bitnami/discourse @@ -59,7 +59,7 @@ services: restart: unless-stopped discourse-sidekiq: - image: docker.io/bitnami/discourse:3.3.2 + image: docker.io/bitnamilegacy/discourse:3.5.0 volumes: - discourse-sidekiq-data:/bitnami/discourse diff --git a/blueprints/dolibarr/docker-compose.yml b/blueprints/dolibarr/docker-compose.yml new file mode 100644 index 00000000..9e364c46 --- /dev/null +++ b/blueprints/dolibarr/docker-compose.yml @@ -0,0 +1,40 @@ +services: + dolibarr: + image: dolibarr/dolibarr:21.0.0 + restart: always + environment: + DOLI_DB_HOST: db + DOLI_DB_NAME: $DB_NAME + DOLI_DB_USER: $DB_USER + DOLI_DB_PASSWORD: $DB_PASSWORD + DOLI_URL_ROOT: ${DOLIBARR_HOST} + DOLI_ADMIN_LOGIN: admin + DOLI_ADMIN_PASSWORD: $ADMIN_PASSWORD + volumes: + - dolibarr_documents:/var/www/documents + - dolibarr_html:/var/www/html + depends_on: + db: + condition: service_healthy + + db: + image: mariadb:10.11 + restart: always + environment: + MYSQL_ROOT_PASSWORD: $DB_ROOT_PASSWORD + MYSQL_DATABASE: $DB_NAME + MYSQL_USER: $DB_USER + MYSQL_PASSWORD: $DB_PASSWORD + volumes: + - db_data:/var/lib/mysql + healthcheck: + test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + +volumes: + dolibarr_documents: + dolibarr_html: + db_data: diff --git a/blueprints/dolibarr/logo.svg b/blueprints/dolibarr/logo.svg new file mode 100644 index 00000000..94b7c1a6 --- /dev/null +++ b/blueprints/dolibarr/logo.svg @@ -0,0 +1 @@ + diff --git a/blueprints/dolibarr/template.toml b/blueprints/dolibarr/template.toml new file mode 100644 index 00000000..923b0de7 --- /dev/null +++ b/blueprints/dolibarr/template.toml @@ -0,0 +1,23 @@ +[variables] +main_domain = "${domain}" +db_name = "dolibarr" +db_user = "dolibarr" +db_password = "${password:32}" +db_root_password = "${password:32}" +admin_password = "${password:32}" + +[config] +env = [ + "DOLIBARR_HOST=${main_domain}", + "DB_NAME=${db_name}", + "DB_USER=${db_user}", + "DB_PASSWORD=${db_password}", + "DB_ROOT_PASSWORD=${db_root_password}", + "ADMIN_PASSWORD=${admin_password}" +] +mounts = [] + +[[config.domains]] +serviceName = "dolibarr" +port = 80 +host = "${main_domain}" diff --git a/blueprints/easyappointments/docker-compose.yml b/blueprints/easyappointments/docker-compose.yml new file mode 100644 index 00000000..ee2e1edf --- /dev/null +++ b/blueprints/easyappointments/docker-compose.yml @@ -0,0 +1,29 @@ +version: "3.8" + +services: + easyappointments: + image: alextselegidis/easyappointments:1.5.0 + restart: unless-stopped + environment: + - BASE_URL=http://${DOMAIN} + - DB_HOST=mysql + - DB_NAME=easyappointments + - DB_USERNAME=root + - DB_PASSWORD=${DB_PASSWORD} + volumes: + - easyappointments:/var/www/html + depends_on: + - mysql + + mysql: + image: mysql:8.0 + restart: unless-stopped + environment: + - MYSQL_ROOT_PASSWORD=${DB_PASSWORD} + - MYSQL_DATABASE=easyappointments + volumes: + - mysql:/var/lib/mysql + +volumes: + easyappointments: + mysql: diff --git a/blueprints/easyappointments/logo.png b/blueprints/easyappointments/logo.png new file mode 100644 index 00000000..422670b9 Binary files /dev/null and b/blueprints/easyappointments/logo.png differ diff --git a/blueprints/easyappointments/template.toml b/blueprints/easyappointments/template.toml new file mode 100644 index 00000000..997ee0e1 --- /dev/null +++ b/blueprints/easyappointments/template.toml @@ -0,0 +1,13 @@ +[variables] +main_domain = "${domain}" +db_password = "${password:32}" + +[config] +[[config.domains]] +serviceName = "easyappointments" +port = 80 +host = "${main_domain}" + +[config.env] +DOMAIN = "${main_domain}" +DB_PASSWORD = "${db_password}" diff --git a/blueprints/emqx/docker-compose.yml b/blueprints/emqx/docker-compose.yml new file mode 100644 index 00000000..4b11f010 --- /dev/null +++ b/blueprints/emqx/docker-compose.yml @@ -0,0 +1,58 @@ +# This templates requires additional traefik port mapping and entry point +# for port 8883 (mqtts over TCP) +# +# For the full instructions, refer to: +# - https://github.com/Dokploy/dokploy/discussions/3126 +# +# The initial login credentials are: +# - USERNAME: admin +# - PASSWORD: public + +services: + emqx: + image: emqx/emqx-enterprise:6.0.1 + hostname: node1.emqx.com + environment: + EMQX_NODE_NAME: emqx@node1.emqx.com + expose: + - 1883 # MQTT + - 8083 # WS + - 18083 # Dashboard + volumes: + - emqx_data:/opt/emqx/data + - emqx_log:/opt/emqx/log + networks: + dokploy-network: + aliases: + - emqx-service + restart: unless-stopped + healthcheck: + test: ["CMD", "/opt/emqx/bin/emqx_ctl", "status"] + interval: 30s + timeout: 5s + retries: 3 + labels: + # MQTT over TLS + - "traefik.tcp.routers.emqx-mqtts.entrypoints=mqtts" + - "traefik.tcp.routers.emqx-mqtts.rule=HostSNI(`broker.yourdomain.com`)" # Change domain + - "traefik.tcp.routers.emqx-mqtts.tls.certresolver=letsencrypt" + - "traefik.tcp.routers.emqx-mqtts.service=emqx-service" + - "traefik.tcp.services.emqx-service.loadbalancer.server.port=1883" + + # + # Optional Web UI: + # - https://github.com/emqx/MQTTX/tree/main/web + # + # mqttx-web: + # image: emqx/mqttx-web:latest + # expose: + # - 80 + # + +volumes: + emqx_data: + emqx_log: + +networks: + dokploy-network: + external: true diff --git a/blueprints/emqx/emqx.svg b/blueprints/emqx/emqx.svg new file mode 100644 index 00000000..ce0c1ec9 --- /dev/null +++ b/blueprints/emqx/emqx.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/blueprints/emqx/template.toml b/blueprints/emqx/template.toml new file mode 100644 index 00000000..5fc03e5f --- /dev/null +++ b/blueprints/emqx/template.toml @@ -0,0 +1,11 @@ +[variables] + +[[config.domains]] +serviceName = "emqx" +port = 18083 +host = "emqx.yourdomain.com" + +[[config.domains]] +serviceName = "emqx" +port = 8083 +host = "broker.yourdomain.com" diff --git a/blueprints/excalidraw/docker-compose.yml b/blueprints/excalidraw/docker-compose.yml index d68065c0..9f2c3091 100644 --- a/blueprints/excalidraw/docker-compose.yml +++ b/blueprints/excalidraw/docker-compose.yml @@ -1,5 +1,8 @@ +version: "3.8" + services: excalidraw: + restart: unless-stopped image: excalidraw/excalidraw:latest healthcheck: test: diff --git a/blueprints/instantdb/docker-compose.yml b/blueprints/instantdb/docker-compose.yml new file mode 100644 index 00000000..b40e043d --- /dev/null +++ b/blueprints/instantdb/docker-compose.yml @@ -0,0 +1,64 @@ +services: + postgres: + image: ghcr.io/instantdb/postgresql:postgresql-16-pg-hint-plan + restart: unless-stopped + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_DB: ${POSTGRES_DB} + volumes: + - backend-db:/var/lib/postgresql/data + healthcheck: + test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}"] + interval: 10s + timeout: 5s + retries: 5 + command: + - "postgres" + - "-c" + - "wal_level=logical" + - "-c" + - "max_replication_slots=4" + - "-c" + - "max_wal_senders=4" + - "-c" + - "shared_preload_libraries=pg_hint_plan" + - "-c" + - "random_page_cost=1.1" + server: + depends_on: + postgres: + condition: service_healthy + image: hari1367709/instantdb-server:latest + restart: unless-stopped + working_dir: /app + environment: + DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}" + NREPL_BIND_ADDRESS: "0.0.0.0" + PORT: "8888" + HOST: "0.0.0.0" + # AWS Credentials for KMS (required for InstantDB) + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} + AWS_REGION: ${AWS_REGION:-us-east-1} + # Force unbuffered output for logs + PYTHONUNBUFFERED: "1" + NODE_ENV: "production" + command: ["java", "-Djava.awt.headless=true", "-server", "-jar", "target/instant-standalone.jar"] + ports: + - "8888" + - "6005" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8888/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s +volumes: + backend-db: + diff --git a/blueprints/instantdb/instant.svg b/blueprints/instantdb/instant.svg new file mode 100644 index 00000000..4e2dc24c --- /dev/null +++ b/blueprints/instantdb/instant.svg @@ -0,0 +1,4 @@ + + + + diff --git a/blueprints/instantdb/template.toml b/blueprints/instantdb/template.toml new file mode 100644 index 00000000..571e6b7a --- /dev/null +++ b/blueprints/instantdb/template.toml @@ -0,0 +1,29 @@ +[variables] +main_domain = "${domain}" +postgres_password = "${password:32}" +postgres_user = "instant" +postgres_db = "instant" +aws_access_key_id = "FILL-YOUR-CREDENTIALS" +aws_secret_access_key = "FILL-YOUR-CREDENTIALS" +aws_region = "us-east-1" + +[config] +env = [ + "POSTGRES_PASSWORD=${postgres_password}", + "POSTGRES_USER=${postgres_user}", + "POSTGRES_DB=${postgres_db}", + "DATABASE_URL=postgresql://${postgres_user}:${postgres_password}@postgres:5432/${postgres_db}", + "NREPL_BIND_ADDRESS=0.0.0.0", + "PORT=8888", + "HOST=0.0.0.0", + "AWS_ACCESS_KEY_ID=${aws_access_key_id}", + "AWS_SECRET_ACCESS_KEY=${aws_secret_access_key}", + "AWS_REGION=${aws_region}", +] +mounts = [] + +[[config.domains]] +serviceName = "server" +port = 8888 +host = "${main_domain}" + diff --git a/blueprints/jenkins/docker-compose.yml b/blueprints/jenkins/docker-compose.yml new file mode 100644 index 00000000..f2b8ad3c --- /dev/null +++ b/blueprints/jenkins/docker-compose.yml @@ -0,0 +1,13 @@ +version: "3.8" + +services: + jenkins: + image: jenkins/jenkins:latest + volumes: + - jenkins-home:/var/jenkins_home + - /var/run/docker.sock:/var/run/docker.sock + ports: + - 8080 + +volumes: + jenkins-home: {} \ No newline at end of file diff --git a/blueprints/jenkins/jenkins.svg b/blueprints/jenkins/jenkins.svg new file mode 100644 index 00000000..b511310d --- /dev/null +++ b/blueprints/jenkins/jenkins.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/blueprints/jenkins/template.toml b/blueprints/jenkins/template.toml new file mode 100644 index 00000000..46a84921 --- /dev/null +++ b/blueprints/jenkins/template.toml @@ -0,0 +1,12 @@ +[variables] +main_domain = "${domain}" + +[config] +env = {} +mounts = [] + +[[config.domains]] +serviceName = "jenkins" +port = 8080 +host = "${main_domain}" + diff --git a/blueprints/komari-monitor/docker-compose.yml b/blueprints/komari-monitor/docker-compose.yml new file mode 100644 index 00000000..149999b0 --- /dev/null +++ b/blueprints/komari-monitor/docker-compose.yml @@ -0,0 +1,13 @@ +version: "3.8" +services: + komari: + image: ghcr.io/komari-monitor/komari:latest + restart: unless-stopped + volumes: + - komari-data:/app/data + environment: + - ADMIN_USERNAME + - ADMIN_PASSWORD + +volumes: + komari-data: {} diff --git a/blueprints/komari-monitor/komari-monitor.ico b/blueprints/komari-monitor/komari-monitor.ico new file mode 100644 index 00000000..f314b8f2 Binary files /dev/null and b/blueprints/komari-monitor/komari-monitor.ico differ diff --git a/blueprints/komari-monitor/template.toml b/blueprints/komari-monitor/template.toml new file mode 100644 index 00000000..20955090 --- /dev/null +++ b/blueprints/komari-monitor/template.toml @@ -0,0 +1,15 @@ +[variables] +main_domain = "${domain}" +admin_password = "${password:16}" + +[config] +mounts = [] + +[[config.domains]] +serviceName = "komari" +port = 25_774 +host = "${main_domain}" + +[config.env] +ADMIN_USERNAME = "admin" +ADMIN_PASSWORD = "${admin_password}" diff --git a/blueprints/lavalink/docker-compose.yml b/blueprints/lavalink/docker-compose.yml new file mode 100644 index 00000000..1f4e91cf --- /dev/null +++ b/blueprints/lavalink/docker-compose.yml @@ -0,0 +1,41 @@ +services: + fix-perms: + image: busybox:1.36 + command: > + sh -c "mkdir -p /opt/Lavalink/plugins && + chmod -R 0777 /opt/Lavalink/plugins || true && + chown -R 1000:1000 /opt/Lavalink/plugins || true && + echo perms-fixed && sleep 1" + volumes: + - "../files/plugins/:/opt/Lavalink/plugins/" + - "../files/application.yml:/opt/Lavalink/application.yml" + restart: "no" + lavalink: + image: ghcr.io/lavalink-devs/lavalink:4 + depends_on: + - fix-perms + restart: unless-stopped + environment: + _JAVA_OPTIONS: "${_JAVA_OPTIONS:--Xmx6G}" + LAVALINK_SERVER_PASSWORD: "${LAVALINK_SERVER_PASSWORD:-youshallnotpass}" + SERVER_PORT: "${SERVER_PORT:-2333}" + volumes: + - "../files/application.yml:/opt/Lavalink/application.yml:rw" + - "../files/plugins/:/opt/Lavalink/plugins/:rw" + ports: + - ${SERVER_PORT} + + healthcheck: + test: > + sh -c 'wget --header="Authorization: ${LAVALINK_SERVER_PASSWORD}" -qO- http://127.0.0.1:${SERVER_PORT}/v4/info >/dev/null 2>&1 || exit 1' + interval: 100s + timeout: 5s + retries: 5 + start_period: 30s + + entrypoint: > + sh -c 'until [ -w /opt/Lavalink/plugins ] ; do + echo "waiting for /opt/Lavalink/plugins to be writable"; + sleep 1; + done; + exec java -jar /opt/Lavalink/Lavalink.jar' diff --git a/blueprints/lavalink/lavalink.svg b/blueprints/lavalink/lavalink.svg new file mode 100644 index 00000000..0ade923f --- /dev/null +++ b/blueprints/lavalink/lavalink.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + diff --git a/blueprints/lavalink/template.toml b/blueprints/lavalink/template.toml new file mode 100644 index 00000000..6c9a92cd --- /dev/null +++ b/blueprints/lavalink/template.toml @@ -0,0 +1,123 @@ +[variables] +main_domain = "${domain}" +server_port = "2333" +lavalink_server_password = "${password}" + +[config] +[[config.mounts]] +filePath = "./application.yml" +content = """ +server: # REST and WS server + port: 2333 + address: 0.0.0.0 + http2: + enabled: false +plugins: +# name: # Name of the plugin +# some_key: some_value # Some key-value pair for the plugin +# another_key: another_value +lavalink: + plugins: + # - dependency: "com.github.username.pluginName:pluginName-plugin:x.y.z" + # snapshot: false + # pluginsDir: "/opt/Lavalink/plugins" + # defaultPluginRepository: "https://maven.lavalink.dev/releases" + # defaultPluginSnapshotRepository: "https://maven.lavalink.dev/snapshots" + server: + password: "youshallnotpass" + sources: + # The default Youtube source is now deprecated and won't receive further updates. Please use https://github.com/lavalink-devs/youtube-source#plugin instead. + youtube: true + bandcamp: true + soundcloud: true + twitch: true + vimeo: true + nico: true + http: true + local: false + filters: + volume: true + equalizer: true + karaoke: true + timescale: true + tremolo: true + vibrato: true + distortion: true + rotation: true + channelMix: true + lowPass: true + nonAllocatingFrameBuffer: false + bufferDurationMs: 400 + frameBufferDurationMs: 5000 + opusEncodingQuality: 10 + resamplingQuality: LOW + trackStuckThresholdMs: 10000 + useSeekGhosting: true + youtubePlaylistLoadLimit: 6 + playerUpdateInterval: 5 + youtubeSearchEnabled: true + soundcloudSearchEnabled: true + gc-warnings: true + #ratelimit: + #ipBlocks: ["1.0.0.0/8", "..."] # list of ip blocks + #excludedIps: ["...", "..."] # ips which should be explicit excluded from usage by lavalink + #strategy: "RotateOnBan" # RotateOnBan | LoadBalance | NanoSwitch | RotatingNanoSwitch + #searchTriggersFail: true # Whether a search 429 should trigger marking the ip as failing + #retryLimit: -1 # -1 = use default lavaplayer value | 0 = infinity | >0 = retry will happen this numbers times + #youtubeConfig: # Required for avoiding all age restrictions by YouTube, some restricted videos still can be played without. + #email: "" # Email of Google account + #password: "" # Password of Google account + #httpConfig: # Useful for blocking bad-actors from ip-grabbing your music node and attacking it, this way only the http proxy will be attacked + #proxyHost: "localhost" # Hostname of the proxy, (ip or domain) + #proxyPort: 3128 # Proxy port, 3128 is the default for squidProxy + #proxyUser: "" # Optional user for basic authentication fields, leave blank if you don't use basic auth + #proxyPassword: "" # Password for basic authentication + timeouts: + connectTimeoutMs: 3000 + connectionRequestTimeoutMs: 3000 + socketTimeoutMs: 3000 + +metrics: + prometheus: + enabled: false + endpoint: /metrics + +sentry: + dsn: "" + environment: "" +# tags: +# some_key: some_value +# another_key: another_value + +logging: + file: + path: ./logs/ + + level: + root: INFO + lavalink: INFO + + request: + enabled: true + includeClientInfo: true + includeHeaders: false + includeQueryString: true + includePayload: true + maxPayloadLength: 10000 + + + logback: + rollingpolicy: + max-file-size: 1GB + max-history: 30 +""" + +[[config.domains]] +serviceName = "lavalink" +port = 2_333 +host = "${main_domain}" + +[config.env] +_JAVA_OPTIONS = "-Xmx6G" +LAVALINK_SERVER_PASSWORD = "${lavalink_server_password}" +SERVER_PORT = "${server_port}" diff --git a/blueprints/mage-ai/docker-compose.yml b/blueprints/mage-ai/docker-compose.yml new file mode 100644 index 00000000..7c9bbc23 --- /dev/null +++ b/blueprints/mage-ai/docker-compose.yml @@ -0,0 +1,26 @@ +# https://docs.mage.ai/getting-started/setup#docker-compose +# +# The default credentials are: +# USERNAME: admin@admin.com +# PASSWORD: admin + +services: + mage-ai: + image: mageai/mageai:0.9.78 + command: mage start ${PROJECT_NAME} + environment: + USER_CODE_PATH: /home/src/${PROJECT_NAME} + ENV: ${ENV} + expose: + - 6789 + volumes: + - mageai_data:/home/src/ + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-s", "-f", "-o", "/dev/null", "http://localhost:6789"] + interval: 30s + timeout: 10s + retries: 5 + +volumes: + mageai_data: diff --git a/blueprints/mage-ai/mage-ai.svg b/blueprints/mage-ai/mage-ai.svg new file mode 100644 index 00000000..d45a7d1b --- /dev/null +++ b/blueprints/mage-ai/mage-ai.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/blueprints/mage-ai/template.toml b/blueprints/mage-ai/template.toml new file mode 100644 index 00000000..12cd84e6 --- /dev/null +++ b/blueprints/mage-ai/template.toml @@ -0,0 +1,11 @@ +[variables] +main_domain = "${domain}" + +[[config.domains]] +serviceName = "mage-ai" +port = 6789 +host = "${main_domain}" + +[config.env] +PROJECT_NAME = "mage-ai" +ENV = "production" diff --git a/blueprints/mautic/docker-compose.yml b/blueprints/mautic/docker-compose.yml new file mode 100644 index 00000000..223ea7ee --- /dev/null +++ b/blueprints/mautic/docker-compose.yml @@ -0,0 +1,131 @@ +version: "3.8" + +services: + # ------------------------------------------------------------------------- + # Service 1: Database + # ------------------------------------------------------------------------- + mysql: + image: mysql:8.0 + command: --default-authentication-plugin=mysql_native_password + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + MYSQL_DATABASE: ${MAUTIC_DB_DATABASE} + MYSQL_USER: ${MAUTIC_DB_USER} + MYSQL_PASSWORD: ${MAUTIC_DB_PASSWORD} + volumes: + - mysql_data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 10s + timeout: 5s + retries: 5 + + # ------------------------------------------------------------------------- + # Service 2: Mautic Web (The Leader) + # ------------------------------------------------------------------------- + mautic: + image: mautic/mautic:5.1.1-apache + restart: unless-stopped + depends_on: + mysql: + condition: service_healthy + ports: + - 80 + environment: + - DOCKER_MAUTIC_ROLE=mautic_web + - DOCKER_MAUTIC_RUN_MIGRATIONS=true + - MAUTIC_DB_HOST=${MAUTIC_DB_HOST} + - MAUTIC_DB_PORT=${MAUTIC_DB_PORT} + - MAUTIC_DB_DATABASE=${MAUTIC_DB_DATABASE} + - MAUTIC_DB_USER=${MAUTIC_DB_USER} + - MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD} + - MAUTIC_URL=${MAUTIC_URL} + - MAUTIC_TRUSTED_PROXIES=${MAUTIC_TRUSTED_PROXIES} + - MAUTIC_MESSENGER_DSN_EMAIL=${MAUTIC_MESSENGER_DSN_EMAIL} + - MAUTIC_MESSENGER_DSN_HIT=${MAUTIC_MESSENGER_DSN_HIT} + - PHP_INI_DATE_TIMEZONE=${PHP_INI_DATE_TIMEZONE} + - PHP_MEMORY_LIMIT=${PHP_MEMORY_LIMIT} + volumes: + - mautic_data:/var/www/html + # AUTOMATION FIX 1: Force permissions to be correct on every start + entrypoint: ["/bin/sh", "-c", "chown -R www-data:www-data /var/www/html && /entrypoint.sh apache2-foreground"] + # AUTOMATION FIX 2: Check if the CONFIG FILE exists. If not, report 'unhealthy'. + # This signals the other containers to keep waiting. + healthcheck: + test: ["CMD-SHELL", "test -f /var/www/html/config/local.php || exit 1"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 300s # Give you 5 mins to run the installer before marking failed + + # ------------------------------------------------------------------------- + # Service 3: Mautic Cron (Waits for Install) + # ------------------------------------------------------------------------- + mautic-cron: + image: mautic/mautic:5.1.1-apache + restart: unless-stopped + depends_on: + mautic: + condition: service_healthy # AUTOMATION FIX 3: Do not start until config file exists + environment: + - DOCKER_MAUTIC_ROLE=mautic_cron + - MAUTIC_DB_HOST=${MAUTIC_DB_HOST} + - MAUTIC_DB_PORT=${MAUTIC_DB_PORT} + - MAUTIC_DB_DATABASE=${MAUTIC_DB_DATABASE} + - MAUTIC_DB_USER=${MAUTIC_DB_USER} + - MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD} + - MAUTIC_URL=${MAUTIC_URL} + - PHP_INI_DATE_TIMEZONE=${PHP_INI_DATE_TIMEZONE} + volumes: + - mautic_data:/var/www/html + + # ------------------------------------------------------------------------- + # Service 4: Mautic Worker (Waits for Install) + # ------------------------------------------------------------------------- + mautic-worker: + image: mautic/mautic:5.1.1-apache + restart: unless-stopped + depends_on: + mautic: + condition: service_healthy # AUTOMATION FIX 3: Do not start until config file exists + deploy: + resources: + limits: + memory: 512M + environment: + - DOCKER_MAUTIC_ROLE=mautic_worker + - DOCKER_MAUTIC_WORKERS_CONSUME_EMAIL=2 + - DOCKER_MAUTIC_WORKERS_CONSUME_HIT=2 + - DOCKER_MAUTIC_WORKERS_CONSUME_FAILED=2 + - MAUTIC_DB_HOST=${MAUTIC_DB_HOST} + - MAUTIC_DB_PORT=${MAUTIC_DB_PORT} + - MAUTIC_DB_DATABASE=${MAUTIC_DB_DATABASE} + - MAUTIC_DB_USER=${MAUTIC_DB_USER} + - MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD} + - MAUTIC_URL=${MAUTIC_URL} + - MAUTIC_MESSENGER_DSN_EMAIL=${MAUTIC_MESSENGER_DSN_EMAIL} + - MAUTIC_MESSENGER_DSN_HIT=${MAUTIC_MESSENGER_DSN_HIT} + - PHP_INI_DATE_TIMEZONE=${PHP_INI_DATE_TIMEZONE} + volumes: + - mautic_data:/var/www/html + + # ------------------------------------------------------------------------- + # Service 5: phpMyAdmin + # ------------------------------------------------------------------------- + phpmyadmin: + image: phpmyadmin/phpmyadmin + restart: unless-stopped + depends_on: + mysql: + condition: service_healthy + environment: + PMA_HOST: mysql + PMA_PORT: 3306 + UPLOAD_LIMIT: 64M + ports: + - 80 + +volumes: + mysql_data: + mautic_data: diff --git a/blueprints/mautic/mautic.svg b/blueprints/mautic/mautic.svg new file mode 100644 index 00000000..3f5229ae --- /dev/null +++ b/blueprints/mautic/mautic.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blueprints/mautic/template.toml b/blueprints/mautic/template.toml new file mode 100644 index 00000000..eeb79eef --- /dev/null +++ b/blueprints/mautic/template.toml @@ -0,0 +1,52 @@ +[variables] +# Domain 1: For the main Mautic Application +mautic_domain = "${domain}" + +# Domain 2: For phpMyAdmin (Database Manager) +pma_domain = "${domain}" + +# Security: Random passwords +db_password = "${password:32}" +root_password = "${password:32}" + +[config] + +# --- Service 1: Mautic Web --- +[[config.domains]] +serviceName = "mautic" +port = 80 +host = "${mautic_domain}" +path = "/" + +# --- Service 2: phpMyAdmin --- +[[config.domains]] +serviceName = "phpmyadmin" +port = 80 +host = "${pma_domain}" +path = "/" + +# --- Shared Environment Variables --- +[config.env] + +# URL Configuration +MAUTIC_URL = "https://${mautic_domain}" + +# Database Connections +MAUTIC_DB_HOST = "mysql" +MAUTIC_DB_PORT = "3306" +MAUTIC_DB_DATABASE = "mautic" +MAUTIC_DB_USER = "mautic" +MAUTIC_DB_PASSWORD = "${db_password}" +MYSQL_ROOT_PASSWORD = "${root_password}" + +# Security & Proxy (JSON ARRAY FIXED) +# We use single quotes '...' so TOML treats the inner [...] as a string +MAUTIC_TRUSTED_PROXIES = '["0.0.0.0/0"]' + +# Queue Settings +MAUTIC_MESSENGER_DSN_EMAIL = "doctrine://default" +MAUTIC_MESSENGER_DSN_HIT = "doctrine://default" + +# PHP Settings +PHP_INI_DATE_TIMEZONE = "UTC" +PHP_MEMORY_LIMIT = "512M" \ No newline at end of file diff --git a/blueprints/minepanel/docker-compose.yml b/blueprints/minepanel/docker-compose.yml new file mode 100644 index 00000000..e69b75f9 --- /dev/null +++ b/blueprints/minepanel/docker-compose.yml @@ -0,0 +1,29 @@ +version: "3.8" +services: + backend: + image: ketbom/minepanel-backend:1.7.1 + restart: unless-stopped + environment: + - NODE_ENV=production + - FRONTEND_URL=${FRONTEND_URL} + - JWT_SECRET=${JWT_SECRET} + - CLIENT_PASSWORD=${CLIENT_PASSWORD} + - CLIENT_USERNAME=${CLIENT_USERNAME} + - BASE_DIR=${BASE_DIR} + volumes: + - minepanel-servers:/app/servers + - minepanel-data:/app/data + - /var/run/docker.sock:/var/run/docker.sock + + frontend: + image: ketbom/minepanel-frontend:1.7.1 + restart: unless-stopped + environment: + - NEXT_PUBLIC_BACKEND_URL=${NEXT_PUBLIC_BACKEND_URL} + - NEXT_PUBLIC_DEFAULT_LANGUAGE=${NEXT_PUBLIC_DEFAULT_LANGUAGE} + depends_on: + - backend + +volumes: + minepanel-servers: + minepanel-data: diff --git a/blueprints/minepanel/minepanel.webp b/blueprints/minepanel/minepanel.webp new file mode 100644 index 00000000..21a6f7a4 Binary files /dev/null and b/blueprints/minepanel/minepanel.webp differ diff --git a/blueprints/minepanel/template.toml b/blueprints/minepanel/template.toml new file mode 100644 index 00000000..4f1b0862 --- /dev/null +++ b/blueprints/minepanel/template.toml @@ -0,0 +1,28 @@ +[variables] +main_domain = "${domain}" +jwt_secret = "${base64:32}" +client_username = "admin" +client_password = "${password:16}" +default_language = "en" + +[config] +mounts = [] + +[[config.domains]] +serviceName = "frontend" +port = 3_000 +host = "${main_domain}" + +[[config.domains]] +serviceName = "backend" +port = 8_091 +host = "api-${main_domain}" + +[config.env] +JWT_SECRET = "${jwt_secret}" +CLIENT_USERNAME = "${client_username}" +CLIENT_PASSWORD = "${client_password}" +FRONTEND_URL = "http://${main_domain}" +NEXT_PUBLIC_BACKEND_URL = "http://api-${main_domain}" +NEXT_PUBLIC_DEFAULT_LANGUAGE = "${default_language}" +BASE_DIR = "/app" diff --git a/blueprints/misaka-danmu-server/docker-compose.yml b/blueprints/misaka-danmu-server/docker-compose.yml new file mode 100644 index 00000000..42252c25 --- /dev/null +++ b/blueprints/misaka-danmu-server/docker-compose.yml @@ -0,0 +1,43 @@ +version: "3.8" +services: + postgres: + image: postgres:18 + restart: unless-stopped + environment: + - POSTGRES_PASSWORD + - POSTGRES_USER + - POSTGRES_DB + - TZ=Asia/Shanghai + volumes: + - postgres-data:/var/lib/postgresql + healthcheck: + test: ["CMD-SHELL", "pg_isready -U danmuapi -d danmuapi"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 60s + + danmu-app: + image: l429609201/misaka_danmu_server:latest + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + environment: + - PUID=1000 + - PGID=1000 + - UMASK=0022 + - TZ=Asia/Shanghai + - DANMUAPI_DATABASE__TYPE + - DANMUAPI_DATABASE__HOST + - DANMUAPI_DATABASE__PORT + - DANMUAPI_DATABASE__NAME + - DANMUAPI_DATABASE__USER + - DANMUAPI_DATABASE__PASSWORD + - DANMUAPI_ADMIN__INITIAL_USER + volumes: + - danmu-config:/app/config + +volumes: + postgres-data: {} + danmu-config: {} diff --git a/blueprints/misaka-danmu-server/misaka-danmu-server.png b/blueprints/misaka-danmu-server/misaka-danmu-server.png new file mode 100644 index 00000000..30990611 Binary files /dev/null and b/blueprints/misaka-danmu-server/misaka-danmu-server.png differ diff --git a/blueprints/misaka-danmu-server/template.toml b/blueprints/misaka-danmu-server/template.toml new file mode 100644 index 00000000..62e1c268 --- /dev/null +++ b/blueprints/misaka-danmu-server/template.toml @@ -0,0 +1,30 @@ +[variables] +main_domain = "${domain}" +db_password = "${password:24}" +db_user = "danmuapi" +db_name = "danmuapi" + +[config] +mounts = [] + +[[config.domains]] +serviceName = "danmu-app" +port = 7768 +host = "${main_domain}" + +[config.env] +# PostgreSQL +POSTGRES_PASSWORD = "${db_password}" +POSTGRES_USER = "${db_user}" +POSTGRES_DB = "${db_name}" + +# Danmu App Database Connection +DANMUAPI_DATABASE__TYPE = "postgresql" +DANMUAPI_DATABASE__HOST = "postgres" +DANMUAPI_DATABASE__PORT = "5432" +DANMUAPI_DATABASE__NAME = "${db_name}" +DANMUAPI_DATABASE__USER = "${db_user}" +DANMUAPI_DATABASE__PASSWORD = "${db_password}" + +# Admin +DANMUAPI_ADMIN__INITIAL_USER = "admin" diff --git a/blueprints/openpanel/docker-compose.yml b/blueprints/openpanel/docker-compose.yml index 566299d0..53c95bd2 100644 --- a/blueprints/openpanel/docker-compose.yml +++ b/blueprints/openpanel/docker-compose.yml @@ -1,8 +1,12 @@ -x-database: &x-database - DATABASE_URL: postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@op-db:5432/${OPENPANEL_POSTGRES_DB}?schema=public - DATABASE_URL_DIRECT: postgres://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@op-db:5432/${OPENPANEL_POSTGRES_DB}?schema=public - REDIS_URL: redis://default:${SERVICE_PASSWORD_REDIS}@op-kv:6379 - CLICKHOUSE_URL: ${OPENPANEL_CLICKHOUSE_URL:-http://op-ch:8123/openpanel} +x-common: &x-common + NODE_ENV: production + SELF_HOSTED: "true" + API_URL: ${API_URL} + DASHBOARD_URL: ${DASHBOARD_URL} + DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@op-db:5432/${POSTGRES_DB}?schema=public + DATABASE_URL_DIRECT: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@op-db:5432/${POSTGRES_DB}?schema=public + REDIS_URL: redis://default:${REDIS_PASSWORD}@op-kv:6379 + CLICKHOUSE_URL: http://op-ch:8123/openpanel services: op-db: @@ -11,44 +15,46 @@ services: volumes: - op-db-data:/var/lib/postgresql/data healthcheck: - test: [ 'CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}' ] + test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'] interval: 10s timeout: 5s retries: 5 environment: - - POSTGRES_DB=${OPENPANEL_POSTGRES_DB} - - POSTGRES_USER=${SERVICE_USER_POSTGRES} - - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} + - POSTGRES_DB=${POSTGRES_DB} + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} op-kv: image: redis:7.2.5-alpine restart: always volumes: - op-kv-data:/data - command: redis-server --requirepass ${SERVICE_PASSWORD_REDIS} --maxmemory-policy noeviction + command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory-policy noeviction healthcheck: - test: [CMD, redis-cli, -a, "${SERVICE_PASSWORD_REDIS}", ping] + test: ['CMD', 'redis-cli', '-a', '${REDIS_PASSWORD}', 'ping'] interval: 10s timeout: 5s retries: 5 op-ch: - image: clickhouse/clickhouse-server:24.3.2-alpine + image: clickhouse/clickhouse-server:25.10.2.65 restart: always volumes: - op-ch-data:/var/lib/clickhouse - op-ch-logs:/var/log/clickhouse-server - - ../files/clickhouse/clickhouse-config.xml:/etc/clickhouse-server/config.d/op-config.xml:ro - - ../files/clickhouse/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/op-user-config.xml:ro - - ../files/clickhouse/init-db.sql:/docker-entrypoint-initdb.d/1_init-db.sql:ro + - ../files/clickhouse_config:/etc/clickhouse-server/config.d + - ../files/clickhouse_users:/etc/clickhouse-server/users.d + - ../files/clickhouse_init:/docker-entrypoint-initdb.d + environment: + - CLICKHOUSE_SKIP_USER_SETUP=1 healthcheck: - test: [CMD-SHELL, 'clickhouse-client --query "SELECT 1" -d openpanel'] + test: ['CMD-SHELL', 'clickhouse-client --query "SELECT 1" -d openpanel'] interval: 10s timeout: 5s retries: 5 op-api: - image: lindesvard/openpanel-api:${OP_API_VERSION:-latest} + image: lindesvard/openpanel-api:2 restart: always command: > sh -c " @@ -57,39 +63,28 @@ services: sleep 1 done echo 'PostgreSQL is ready' - + echo 'Waiting for ClickHouse to be ready...' while ! nc -z op-ch 8123; do sleep 1 done echo 'ClickHouse is ready' - + echo 'Running migrations...' - - echo '$DATABASE_URL' - + CI=true pnpm -r run migrate:deploy - + pnpm start " environment: - # Common - NODE_ENV: production - NEXT_PUBLIC_SELF_HOSTED: true - # URLs - SERVICE_FQDN_OPAPI: /api - # Set coolify FQDN domain - NEXT_PUBLIC_API_URL: $SERVICE_FQDN_OPAPI - NEXT_PUBLIC_DASHBOARD_URL: $SERVICE_FQDN_OPDASHBOARD - # Others - COOKIE_SECRET: ${SERVICE_BASE64_COOKIESECRET} - ALLOW_REGISTRATION: ${OPENPANEL_ALLOW_REGISTRATION:-false} - ALLOW_INVITATION: ${OPENPANEL_ALLOW_INVITATION:-true} - EMAIL_SENDER: ${OPENPANEL_EMAIL_SENDER} + COOKIE_SECRET: ${COOKIE_SECRET} + ALLOW_REGISTRATION: ${ALLOW_REGISTRATION} + ALLOW_INVITATION: ${ALLOW_INVITATION} + EMAIL_SENDER: ${EMAIL_SENDER} RESEND_API_KEY: ${RESEND_API_KEY} - <<: *x-database + <<: *x-common healthcheck: - test: [ "CMD-SHELL", "curl -f http://localhost:3000/healthcheck || exit 1" ] + test: ['CMD-SHELL', 'curl -f http://localhost:3000/healthcheck || exit 1'] interval: 10s timeout: 5s retries: 5 @@ -102,55 +97,35 @@ services: condition: service_healthy op-dashboard: - image: lindesvard/openpanel-dashboard:${OP_DASHBOARD_VERSION:-latest} + image: lindesvard/openpanel-dashboard:2 restart: always depends_on: op-api: condition: service_healthy environment: - # Common - NODE_ENV: production - NEXT_PUBLIC_SELF_HOSTED: true - # URLs - SERVICE_FQDN_OPDASHBOARD: - # Set coolify FQDN domain - NEXT_PUBLIC_API_URL: $SERVICE_FQDN_OPAPI - NEXT_PUBLIC_DASHBOARD_URL: $SERVICE_FQDN_OPDASHBOARD - <<: *x-database + <<: *x-common healthcheck: - test: [ 'CMD-SHELL', 'curl -f http://localhost:3000/api/healthcheck || exit 1' ] + test: ['CMD-SHELL', 'curl -f http://localhost:3000/api/healthcheck || exit 1'] interval: 10s timeout: 5s retries: 5 op-worker: - image: lindesvard/openpanel-worker:${OP_WORKER_VERSION:-latest} + image: lindesvard/openpanel-worker:2 restart: always depends_on: op-api: condition: service_healthy environment: - # FQDN - SERVICE_FQDN_OPBULLBOARD: - # Common - NODE_ENV=production: - NEXT_PUBLIC_SELF_HOSTED: true - # Set coolify FQDN domain - NEXT_PUBLIC_API_URL: $SERVICE_FQDN_OPAPI - <<: *x-database + <<: *x-common healthcheck: - test: [ 'CMD-SHELL', 'curl -f http://localhost:3000/healthcheck || exit 1' ] + test: ['CMD-SHELL', 'curl -f http://localhost:3000/healthcheck || exit 1'] interval: 10s timeout: 5s retries: 5 - deploy: - mode: replicated - replicas: $OP_WORKER_REPLICAS volumes: op-db-data: op-kv-data: op-ch-data: op-ch-logs: - op-proxy-data: - op-proxy-config: diff --git a/blueprints/openpanel/template.toml b/blueprints/openpanel/template.toml index 55773508..2a93c33c 100644 --- a/blueprints/openpanel/template.toml +++ b/blueprints/openpanel/template.toml @@ -1,82 +1,91 @@ [variables] main_domain = "${domain}" -api_domain = "${domain}" -db_password = "${password}" +db_password = "${password:32}" cookie_secret = "${base64:32}" -redis_password = "${password}" +redis_password = "${password:32}" [config] +# ClickHouse config files - mounted as directories [[config.mounts]] -filePath = "clickhouse/clickhouse-config.xml" +filePath = "./clickhouse_config/op-config.xml" content = """ - - - warning - true - - 10 - - - - - - - - - - 0.0.0.0 - 0.0.0.0 - opch - - 0 - - - 1 - replica1 - openpanel_cluster - - + + + warning + true + + 10 + + + + + + + + + + 0.0.0.0 + 0.0.0.0 + opch + + 0 + + + 1 + replica1 + openpanel_cluster + + """ [[config.mounts]] -filePath = "clickhouse/clickhouse-user-config.xml" +filePath = "./clickhouse_users/op-user-config.xml" content = """ - - + + 0 0 - + """ [[config.mounts]] -filePath = "clickhouse/init-db.sql" +filePath = "./clickhouse_init/1_init-db.sql" content = """ CREATE DATABASE IF NOT EXISTS openpanel; """ [[config.domains]] serviceName = "op-dashboard" -port = 3_000 +port = 3000 host = "${main_domain}" [[config.domains]] serviceName = "op-api" -port = 3_000 -host = "${api_domain}" +port = 3000 +host = "${main_domain}" +path = "/api" +stripPath = true [config.env] -SERVICE_FQDN_OPDASHBOARD = "http://${main_domain}" -SERVICE_FQDN_OPAPI = "http://${api_domain}" -OPENPANEL_POSTGRES_DB = "openpanel-db" -SERVICE_USER_POSTGRES = "openpanel" -SERVICE_PASSWORD_POSTGRES = "${db_password}" -SERVICE_PASSWORD_REDIS = "${redis_password}" -SERVICE_BASE64_COOKIESECRET = "${cookie_secret}" -OP_WORKER_REPLICAS = "1" +DASHBOARD_URL = "http://${main_domain}" +API_URL = "http://${main_domain}/api" +# Database configuration +POSTGRES_DB = "openpanel" +POSTGRES_USER = "openpanel" +POSTGRES_PASSWORD = "${db_password}" +REDIS_PASSWORD = "${redis_password}" + +# Security +COOKIE_SECRET = "${cookie_secret}" + +# Registration settings +ALLOW_REGISTRATION = "true" +ALLOW_INVITATION = "true" + +# Email configuration (optional - configure for email notifications) +EMAIL_SENDER = "" RESEND_API_KEY = "" -OPENPANEL_ALLOW_REGISTRATION = "true" -OPENPANEL_ALLOW_INVITATION = "true" diff --git a/blueprints/prometheus/docker-compose.yml b/blueprints/prometheus/docker-compose.yml index e1016777..1896c876 100644 --- a/blueprints/prometheus/docker-compose.yml +++ b/blueprints/prometheus/docker-compose.yml @@ -9,6 +9,7 @@ services: - "--web.console.templates=/usr/share/prometheus/consoles" - "--web.enable-lifecycle" volumes: + - ../files/prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus volumes: prometheus-data: {} diff --git a/blueprints/prometheus/template.toml b/blueprints/prometheus/template.toml index 535663dc..2415f3fe 100644 --- a/blueprints/prometheus/template.toml +++ b/blueprints/prometheus/template.toml @@ -10,7 +10,10 @@ port = 9_090 host = "${main_domain}" [[config.mounts]] -filePath = "/etc/prometheus/prometheus.yml" +# Note: this relative path is resolved by Dokploy to the file mounted from +# ../files/prometheus.yml in docker-compose, and mapped inside the container +# to /etc/prometheus/prometheus.yml. +filePath = "prometheus.yml" serviceName = "prometheus" content = """ # Prometheus Configuration diff --git a/blueprints/pyrodactyl/docker-compose.yml b/blueprints/pyrodactyl/docker-compose.yml index ad0e42b7..2fde33d7 100644 --- a/blueprints/pyrodactyl/docker-compose.yml +++ b/blueprints/pyrodactyl/docker-compose.yml @@ -1,6 +1,6 @@ services: database: - image: mariadb:10.5 + image: mariadb:11 restart: always command: --default-authentication-plugin=mysql_native_password volumes: @@ -14,7 +14,7 @@ services: image: redis:alpine restart: always panel: - image: ghcr.io/pyrohost/pyrodactyl:main + image: ghcr.io/pyrodactyl-oss/pyrodactyl:latest restart: always links: - database @@ -35,15 +35,8 @@ services: DB_HOST: DB_PORT: DB_PASSWORD: ${MYSQL_PASSWORD} - RECAPTCHA_ENABLED: DB_CONNECTION: "mariadb" -networks: - default: - ipam: - config: - - subnet: 172.20.0.0/16 - volumes: pterodb: pterovar: diff --git a/blueprints/qbitwebui/docker-compose.yml b/blueprints/qbitwebui/docker-compose.yml new file mode 100644 index 00000000..3e805c3c --- /dev/null +++ b/blueprints/qbitwebui/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.8" + +services: + qbitwebui: + image: ghcr.io/maciejonos/qbitwebui:latest + restart: unless-stopped + environment: + # Required: Encryption key for storing credentials (min 32 chars) + - ENCRYPTION_KEY=${ENCRYPTION_KEY} + # Optional: Server port (default: 3000) + - PORT=${PORT:-3000} + # Optional: Database location (default: ./data/qbitwebui.db) + - DATABASE_PATH=${DATABASE_PATH:-/data/qbitwebui.db} + # Optional: Salt file location (default: ./data/.salt) + - SALT_PATH=${SALT_PATH:-/data/.salt} + # Optional: Allow self-signed certificates for qBittorrent instances (default: false) + # - ALLOW_SELF_SIGNED_CERTS=${ALLOW_SELF_SIGNED_CERTS:-false} + # Optional: Disable authentication/login (single-user mode) (default: false) + # - DISABLE_AUTH=${DISABLE_AUTH:-false} + # Optional: Disable new registrations, creates default admin account (default: false) + # - DISABLE_REGISTRATION=${DISABLE_REGISTRATION:-false} + # Optional: Enable file browser by setting downloads path + # - DOWNLOADS_PATH=/downloads + volumes: + - qbitwebui_data:/data + # Optional: Mount downloads directory for file browser feature + # Read-only mount (browse & download only): + # - /path/to/your/downloads:/downloads:ro + # Or read-write mount (enables delete/move/copy/rename): + # - /path/to/your/downloads:/downloads + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + +volumes: + qbitwebui_data: diff --git a/blueprints/qbitwebui/qbitwebui.png b/blueprints/qbitwebui/qbitwebui.png new file mode 100644 index 00000000..48052dff Binary files /dev/null and b/blueprints/qbitwebui/qbitwebui.png differ diff --git a/blueprints/qbitwebui/template.toml b/blueprints/qbitwebui/template.toml new file mode 100644 index 00000000..62151ba2 --- /dev/null +++ b/blueprints/qbitwebui/template.toml @@ -0,0 +1,16 @@ +[variables] +main_domain = "${domain}" +encryption_key = "${password:32}" + +[config] +[[config.domains]] +serviceName = "qbitwebui" +port = 3000 +host = "${main_domain}" +path = "/" + +[config.env] +ENCRYPTION_KEY = "${encryption_key}" +PORT = "3000" +DATABASE_PATH = "/data/qbitwebui.db" +SALT_PATH = "/data/.salt" diff --git a/blueprints/reactive-resume/docker-compose.yml b/blueprints/reactive-resume/docker-compose.yml new file mode 100644 index 00000000..21683022 --- /dev/null +++ b/blueprints/reactive-resume/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3.8" + +services: + postgres: + image: postgres:16-alpine + volumes: + - postgres_data:/var/lib/postgresql/data + environment: + POSTGRES_DB: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] + interval: 10s + timeout: 5s + retries: 5 + + minio: + image: minio/minio:latest + command: server /data + volumes: + - minio_data:/data + environment: + MINIO_ROOT_USER: ${MINIO_ROOT_USER} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} + + chrome: + image: ghcr.io/browserless/chromium:v2.18.0 + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + TIMEOUT: 10000 + CONCURRENT: 10 + TOKEN: ${CHROME_TOKEN} + EXIT_ON_HEALTH_FAILURE: "true" + PRE_REQUEST_HEALTH_CHECK: "true" + + app: + image: amruthpillai/reactive-resume:latest + depends_on: + - postgres + - minio + - chrome + environment: + PORT: 3000 + NODE_ENV: production + PUBLIC_URL: https://${APP_DOMAIN} + STORAGE_URL: https://${APP_DOMAIN}/default + CHROME_TOKEN: ${CHROME_TOKEN} + CHROME_URL: ws://chrome:3000 + DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres + ACCESS_TOKEN_SECRET: ${ACCESS_TOKEN_SECRET} + REFRESH_TOKEN_SECRET: ${REFRESH_TOKEN_SECRET} + MAIL_FROM: ${MAIL_FROM} + STORAGE_ENDPOINT: minio + STORAGE_PORT: 9000 + STORAGE_REGION: us-east-1 + STORAGE_BUCKET: default + STORAGE_ACCESS_KEY: ${MINIO_ROOT_USER} + STORAGE_SECRET_KEY: ${MINIO_ROOT_PASSWORD} + STORAGE_USE_SSL: "false" + STORAGE_SKIP_BUCKET_CHECK: "false" + + +volumes: + minio_data: + postgres_data: diff --git a/blueprints/reactive-resume/logo.svg b/blueprints/reactive-resume/logo.svg new file mode 100644 index 00000000..8e9ccb29 --- /dev/null +++ b/blueprints/reactive-resume/logo.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/blueprints/reactive-resume/template.toml b/blueprints/reactive-resume/template.toml new file mode 100644 index 00000000..e6452ee1 --- /dev/null +++ b/blueprints/reactive-resume/template.toml @@ -0,0 +1,33 @@ +[variables] +main_domain = "${domain}" +postgres_password = "${password:32}" +minio_user = "minioadmin" +minio_password = "${password:32}" +chrome_token = "${password:32}" +access_token_secret = "${password:64}" +refresh_token_secret = "${password:64}" +mail_from = "noreply@${main_domain}" + +[config] +env = [ + "APP_DOMAIN=${main_domain}", + "POSTGRES_PASSWORD=${postgres_password}", + "MINIO_ROOT_USER=${minio_user}", + "MINIO_ROOT_PASSWORD=${minio_password}", + "CHROME_TOKEN=${chrome_token}", + "ACCESS_TOKEN_SECRET=${access_token_secret}", + "REFRESH_TOKEN_SECRET=${refresh_token_secret}", + "MAIL_FROM=${mail_from}", +] +mounts = [] + +[[config.domains]] +serviceName = "app" +port = 3000 +host = "${main_domain}" + +[[config.domains]] +serviceName = "minio" +port = 9000 +host = "${main_domain}" +path = "/default" diff --git a/blueprints/searxng/docker-compose.yml b/blueprints/searxng/docker-compose.yml index 856490c6..721c077a 100644 --- a/blueprints/searxng/docker-compose.yml +++ b/blueprints/searxng/docker-compose.yml @@ -1,20 +1,18 @@ -version: "3.8" services: - redis: + valkey: image: valkey/valkey:8-alpine command: valkey-server --save 30 1 --loglevel warning restart: unless-stopped volumes: - - redis-data:/data + - valkey-data:/data searxng: image: searxng/searxng:latest restart: unless-stopped volumes: - - searxng-config:/etc/searxng + - ../files/searxng:/etc/searxng - searxng-data:/var/cache/searxng volumes: - redis-data: {} - searxng-config: {} + valkey-data: {} searxng-data: {} diff --git a/blueprints/searxng/template.toml b/blueprints/searxng/template.toml index 78f7bc68..092aca39 100644 --- a/blueprints/searxng/template.toml +++ b/blueprints/searxng/template.toml @@ -12,11 +12,15 @@ env = [ ] [[config.mounts]] -filePath = "/etc/searxng/settings.yml" +filePath = "/searxng/settings.yml" content = """ use_default_settings: true + server: secret_key: \"${secret_key}\" limiter: false image_proxy: false + +valkey: + url: valkey://valkey:6379/0 """ \ No newline at end of file diff --git a/blueprints/syncthing/docker-compose.yml b/blueprints/syncthing/docker-compose.yml new file mode 100644 index 00000000..e6083a7b --- /dev/null +++ b/blueprints/syncthing/docker-compose.yml @@ -0,0 +1,19 @@ +services: + syncthing: + image: lscr.io/linuxserver/syncthing:latest + restart: unless-stopped + expose: + - 8384 + - 22000 + - 21027/udp + volumes: + - syncthing_config:/config + - syncthing_data:/var/syncthing/Sync + environment: + - PUID=1000 + - PGID=1000 + - TZ=${timezone} + +volumes: + syncthing_config: + syncthing_data: diff --git a/blueprints/syncthing/syncthing.svg b/blueprints/syncthing/syncthing.svg new file mode 100644 index 00000000..de8850f5 --- /dev/null +++ b/blueprints/syncthing/syncthing.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/blueprints/syncthing/template.toml b/blueprints/syncthing/template.toml new file mode 100644 index 00000000..eda476e4 --- /dev/null +++ b/blueprints/syncthing/template.toml @@ -0,0 +1,9 @@ +[variables] +main_domain = "${domain}" +timezone = "America/Sao_Paulo" + +[config] +[[config.domains]] +serviceName = "syncthing" +port = 8384 +host = "${main_domain}" diff --git a/blueprints/tailscale-exitnode/template.toml b/blueprints/tailscale-exitnode/template.toml index eac3e68e..cc03571f 100644 --- a/blueprints/tailscale-exitnode/template.toml +++ b/blueprints/tailscale-exitnode/template.toml @@ -1,4 +1,4 @@ [config.env] TAILSCALE_HOSTNAME = "" -TAILSCALE_APIKEY = "" \ No newline at end of file +TAILSCALE_AUTHKEY = "" \ No newline at end of file diff --git a/blueprints/trailbase/docker-compose.yml b/blueprints/trailbase/docker-compose.yml new file mode 100644 index 00000000..a8067d86 --- /dev/null +++ b/blueprints/trailbase/docker-compose.yml @@ -0,0 +1,24 @@ +# IMPORTANT: The initial admin credentials will be printed in the logs after the container starts +# Access TrailBase Admin UI at: https://your-domain.com/_/admin (replace with your configured domain) + +version: "3.8" + +services: + trailbase: + image: trailbase/trailbase:latest + restart: unless-stopped + volumes: + - trailbase-data:/app/traildepot + # If you want to use a local directory instead, uncomment the line below and specify the path to your local + # directory. Make sure this directory is writable by the trailbase user (UID 1000) and the group (GID 1000) i.e. + # chown -R 1000:1000 /path/to/your/local/directory + # - /path/to/your/local/directory:/app/traildepot + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:4000/api/healthcheck"] + interval: 30s + timeout: 10s + retries: 3 + +volumes: + # comment the line below if you specified a local directory in the volumes section of the trailbase service + trailbase-data: {} diff --git a/blueprints/trailbase/logo.svg b/blueprints/trailbase/logo.svg new file mode 100644 index 00000000..d2e0b8b0 --- /dev/null +++ b/blueprints/trailbase/logo.svg @@ -0,0 +1,194 @@ + + + + diff --git a/blueprints/trailbase/template.toml b/blueprints/trailbase/template.toml new file mode 100644 index 00000000..dbfe2a65 --- /dev/null +++ b/blueprints/trailbase/template.toml @@ -0,0 +1,8 @@ +[variables] +main_domain = "${domain}" + +[config] +[[config.domains]] +serviceName = "trailbase" +port = 4000 +host = "${main_domain}" diff --git a/blueprints/umami/docker-compose.yml b/blueprints/umami/docker-compose.yml index b20524a7..6cd51601 100644 --- a/blueprints/umami/docker-compose.yml +++ b/blueprints/umami/docker-compose.yml @@ -1,6 +1,6 @@ services: umami: - image: ghcr.io/umami-software/umami:postgresql-v2.19.0 + image: ghcr.io/umami-software/umami:3.0.3 restart: always healthcheck: test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"] diff --git a/blueprints/zitadel/docker-compose.yml b/blueprints/zitadel/docker-compose.yml index 38746614..aaa457c3 100644 --- a/blueprints/zitadel/docker-compose.yml +++ b/blueprints/zitadel/docker-compose.yml @@ -33,6 +33,9 @@ services: ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_EMAIL_ADDRESS}" ZITADEL_FIRSTINSTANCE_ORG_HUMAN_FIRSTNAME: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_FIRSTNAME}" ZITADEL_FIRSTINSTANCE_ORG_HUMAN_LASTNAME: "${ZITADEL_FIRSTINSTANCE_ORG_HUMAN_LASTNAME}" + + # Default Instance Features + ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED: false depends_on: db: diff --git a/build-scripts/package-lock.json b/build-scripts/package-lock.json new file mode 100644 index 00000000..bb11b4e0 --- /dev/null +++ b/build-scripts/package-lock.json @@ -0,0 +1,615 @@ +{ + "name": "dokploy-templates-build-scripts", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dokploy-templates-build-scripts", + "version": "1.0.0", + "dependencies": { + "toml": "^3.0.0", + "yaml": "2.7.1" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "tsx": "^4.7.0", + "typescript": "^5.3.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/node": { + "version": "20.19.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", + "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", + "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/meta.json b/meta.json index 1e39e480..7e59e5a0 100644 --- a/meta.json +++ b/meta.json @@ -365,8 +365,8 @@ { "id": "appwrite", "name": "Appwrite", - "version": "1.6.1", - "description": "Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.\nUsing Appwrite, you can easily integrate your app with user authentication and multiple sign-in methods, a database for storing and querying users and team data, storage and file management, image manipulation, Cloud Functions, messaging, and more services.", + "version": "1.8.0", + "description": "Appwrite is an end-to-end platform for building Web, Mobile, Native, or Backend apps, packaged as a set of Docker microservices. It includes both a backend server and a fully integrated hosting solution for deploying static and server-side rendered frontends. Appwrite abstracts the complexity and repetitiveness required to build modern apps from scratch and allows you to build secure, full-stack applications faster.\nUsing Appwrite, you can easily integrate your app with user authentication and multiple sign-in methods, a database for storing and querying users and team data, storage and file management, image manipulation, Cloud Functions, messaging, and more services.", "links": { "github": "https://github.com/appwrite/appwrite", "website": "https://appwrite.io/", @@ -376,7 +376,9 @@ "tags": [ "database", "firebase", - "postgres" + "mariadb", + "hosting", + "self-hosted" ] }, { @@ -508,8 +510,8 @@ { "id": "autobase", "name": "Autobase", - "version": "2.3.0", - "description": "Autobase for PostgreSQL® is an open-source alternative to cloud-managed databases (DBaaS) such as Amazon RDS, Google Cloud SQL, Azure Database, and more.", + "version": "2.5.2", + "description": "Autobase for PostgreSQL® is an open-source alternative to cloud-managed databases (self-hosted DBaaS).", "links": { "github": "https://github.com/vitabaks/autobase", "website": "https://autobase.tech/", @@ -1315,6 +1317,24 @@ "tunnel" ] }, + { + "id": "cloudreve", + "name": "Cloudreve", + "version": "4.10.1", + "description": "Self-hosted file management and sharing system with multi-cloud storage support. Compatible with local, OneDrive, S3, and various cloud providers.", + "logo": "cloudreve.png", + "links": { + "github": "https://github.com/cloudreve/Cloudreve", + "website": "https://cloudreve.org", + "docs": "https://docs.cloudreve.org" + }, + "tags": [ + "storage", + "file-sharing", + "cloud", + "self-hosted" + ] + }, { "id": "cockpit", "name": "Cockpit", @@ -1748,7 +1768,7 @@ { "id": "discourse", "name": "Discourse", - "version": "3.3.2", + "version": "3.5.0", "description": "Discourse is a modern forum software for your community. Use it as a mailing list, discussion forum, or long-form chat room.", "logo": "discourse.svg", "links": { @@ -1850,6 +1870,25 @@ "grafana" ] }, + { + "id": "dolibarr", + "name": "Dolibarr", + "version": "21.0.0", + "description": "Dolibarr ERP & CRM is a modern software package that helps manage your organization's activities (contacts, quotes, invoices, orders, stocks, agenda, human resources, ecm, manufacturing).", + "logo": "logo.svg", + "links": { + "github": "https://github.com/Dolibarr/dolibarr", + "website": "https://www.dolibarr.org/", + "docs": "https://wiki.dolibarr.org/" + }, + "tags": [ + "erp", + "crm", + "business", + "management", + "invoicing" + ] + }, { "id": "domain-locker", "name": "Domain Locker", @@ -2033,6 +2072,23 @@ "simple" ] }, + { + "id": "easyappointments", + "name": "Easy!Appointments", + "version": "1.5.0", + "description": "Easy!Appointments is a highly customizable web application that allows customers to book appointments with you via a sophisticated web interface.", + "logo": "logo.png", + "links": { + "github": "https://github.com/alextselegidis/easyappointments", + "website": "https://easyappointments.org", + "docs": "https://easyappointments.org/docs" + }, + "tags": [ + "scheduling", + "appointments", + "booking" + ] + }, { "id": "elastic-search", "name": "Elasticsearch", @@ -2065,6 +2121,23 @@ "media system" ] }, + { + "id": "emqx", + "name": "EMQX", + "version": "6.0.1", + "description": "A scalable and reliable MQTT broker for AI, IoT, IIoT and connected vehicles", + "logo": "emqx.svg", + "links": { + "github": "https://github.com/emqx/emqx", + "website": "https://www.emqx.com", + "docs": "https://docs.emqx.com" + }, + "tags": [ + "broker", + "iot", + "mqtt" + ] + }, { "id": "enshrouded", "name": "Enshrouded", @@ -3080,6 +3153,23 @@ "events" ] }, + { + "id": "instantdb", + "name": "InstantDB", + "version": "latest", + "description": "InstantDB is a real-time database server that provides instant data synchronization and real-time updates for applications.", + "logo": "instant.svg", + "links": { + "github": "https://github.com/instantdb/instant/tree/main/server", + "website": "https://github.com/instantdb/instant", + "docs": "https://github.com/instantdb/instant" + }, + "tags": [ + "database", + "real-time", + "self-hosted" + ] + }, { "id": "invoiceshelf", "name": "InvoiceShelf", @@ -3146,6 +3236,25 @@ "media system" ] }, + { + "id": "jenkins", + "name": "jenkins", + "version": "latest", + "description": "Jenkins is a free, open-source automation server that helps developers build, test, and deploy software by automating repetitive tasks in the software delivery pipeline.", + "logo": "jenkins.svg", + "links": { + "github": "https://github.com/jenkinsci/jenkins", + "website": "https://www.jenkins.io/", + "docs": "https://www.jenkins.io/doc/" + }, + "tags": [ + "ci-cd", + "devops", + "automation", + "pipelines", + "open-source" + ] + }, { "id": "kaneo", "name": "Kaneo", @@ -3306,6 +3415,22 @@ "web" ] }, + { + "id": "komari-monitor", + "name": "Komari Monitor", + "version": "latest", + "description": "A lightweight, self-hosted server monitoring tool for tracking server performance.", + "logo": "komari-monitor.ico", + "links": { + "github": "https://github.com/komari-monitor/komari", + "website": "https://github.com/komari-monitor/komari", + "docs": "https://github.com/komari-monitor/komari#readme" + }, + "tags": [ + "monitoring", + "self-hosted" + ] + }, { "id": "kutt", "name": "Kutt", @@ -3337,6 +3462,22 @@ "ai" ] }, + { + "id": "lavalink", + "name": "Lavalink", + "version": "4.1.1", + "description": "Lavalink is an open source standalone audio sending node based on Lavaplayer.", + "logo": "lavalink.svg", + "links": { + "github": "https://github.com/lavalink-devs/Lavalink", + "website": "https://lavalink.dev/", + "docs": "https://lavalink.dev/getting-started/index.html" + }, + "tags": [ + "voice", + "discord" + ] + }, { "id": "letterfeed", "name": "Letterfeed", @@ -3596,6 +3737,24 @@ "os" ] }, + { + "id": "mage-ai", + "name": "Mage AI", + "version": "0.9.78", + "description": "Build, run, and manage data pipelines for integrating and transforming data.", + "logo": "mage-ai.svg", + "links": { + "github": "https://github.com/mage-ai/mage-ai", + "website": "https://mage.ai", + "docs": "https://docs.mage.ai" + }, + "tags": [ + "data", + "dbt", + "etl", + "pipelines" + ] + }, { "id": "mailpit", "name": "Mailpit", @@ -3628,6 +3787,24 @@ "self-hosted" ] }, + { + "id": "mautic", + "name": "Mautic", + "version": "5.1.1", + "description": "Mautic is the world's largest open-source marketing automation project. It allows you to automate the process of finding and nurturing contacts through landing pages and forms, sending email, text messages, web notifications, and tracking your contacts.", + "logo": "mautic.svg", + "links": { + "github": "https://github.com/mautic/mautic", + "website": "https://www.mautic.org/", + "docs": "https://docs.mautic.org/en" + }, + "tags": [ + "marketing", + "automation", + "email", + "crm" + ] + }, { "id": "maybe", "name": "Maybe", @@ -3782,6 +3959,24 @@ "media" ] }, + { + "id": "minepanel", + "name": "Minepanel", + "version": "1.7.1", + "description": "Web panel for managing Minecraft servers with Docker. Create, configure, start/stop, and monitor multiple instances from a modern UI.", + "logo": "minepanel.webp", + "links": { + "github": "https://github.com/Ketbome/minepanel", + "website": "https://minepanel.ketbome.lat", + "docs": "https://minepanel.ketbome.lat" + }, + "tags": [ + "gaming", + "minecraft", + "server-management", + "docker" + ] + }, { "id": "minio", "name": "Minio", @@ -3797,6 +3992,23 @@ "storage" ] }, + { + "id": "misaka-danmu-server", + "name": "Misaka Danmu Server", + "version": "latest", + "description": "A self-hosted danmaku (bullet comments) server for live streaming and video platforms.", + "logo": "misaka-danmu-server.png", + "links": { + "github": "https://github.com/l429609201/misaka_danmu_server", + "website": "https://github.com/l429609201/misaka_danmu_server", + "docs": "https://github.com/l429609201/misaka_danmu_server#readme" + }, + "tags": [ + "streaming", + "danmaku", + "live" + ] + }, { "id": "mixpost", "name": "Mixpost", @@ -4976,6 +5188,24 @@ "file-sharing" ] }, + { + "id": "qbitwebui", + "name": "qBittorrent Web UI", + "version": "latest", + "description": "A modern web interface for managing multiple qBittorrent instances. Built with React, Hono, and Bun.", + "logo": "qbitwebui.png", + "links": { + "github": "https://github.com/Maciejonos/qbitwebui", + "website": "https://github.com/Maciejonos/qbitwebui", + "docs": "https://github.com/Maciejonos/qbitwebui#readme" + }, + "tags": [ + "torrent", + "download", + "media", + "qbittorrent" + ] + }, { "id": "qdrant", "name": "Qdrant", @@ -5029,6 +5259,24 @@ "rabbitmq" ] }, + { + "id": "reactive-resume", + "name": "Reactive Resume", + "version": "latest", + "description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.", + "logo": "logo.svg", + "links": { + "github": "https://github.com/AmruthPillai/Reactive-Resume", + "website": "https://rxresu.me/", + "docs": "https://docs.rxresu.me/" + }, + "tags": [ + "resume", + "cv", + "productivity", + "document" + ] + }, { "id": "registry", "name": "Docker Registry", @@ -5571,6 +5819,23 @@ "surrealdb" ] }, + { + "id": "syncthing", + "name": "Syncthing", + "version": "latest", + "description": "Syncthing is a continuous file synchronization program that synchronizes files between two or more computers in real time.", + "logo": "syncthing.svg", + "links": { + "github": "https://github.com/syncthing/syncthing", + "website": "https://syncthing.net/", + "docs": "https://docs.syncthing.net/" + }, + "tags": [ + "file-sync", + "synchronization", + "backup" + ] + }, { "id": "tailscale-exitnode", "name": "Tailscale Exit nodes", @@ -5675,6 +5940,23 @@ "tor" ] }, + { + "id": "trailbase", + "name": "TrailBase", + "version": "latest", + "description": "TrailBase is a blazingly fast, open-source application server with type-safe APIs, built-in WebAssembly runtime, realtime, auth, and admin UI built on Rust, SQLite & Wasmtime.", + "logo": "logo.svg", + "links": { + "github": "https://github.com/trailbase/trailbase", + "website": "https://trailbase.io/", + "docs": "https://trailbase.io/getting-started/install" + }, + "tags": [ + "backend", + "database", + "api" + ] + }, { "id": "triggerdotdev", "name": "Trigger.dev", @@ -5792,7 +6074,7 @@ { "id": "umami", "name": "Umami", - "version": "v2.19.0", + "version": "v3.0.3", "description": "Umami is a simple, fast, privacy-focused alternative to Google Analytics.", "logo": "umami.png", "links": {