diff --git a/blueprints/cloudflared/template.toml b/blueprints/cloudflared/template.toml index 7d2557cc3..2b4d52397 100644 --- a/blueprints/cloudflared/template.toml +++ b/blueprints/cloudflared/template.toml @@ -1,6 +1,7 @@ variables = {} [config] +isolated = false domains = [] mounts = [] diff --git a/blueprints/convex/docker-compose.yml b/blueprints/convex/docker-compose.yml index 7a7f39874..624271e30 100644 --- a/blueprints/convex/docker-compose.yml +++ b/blueprints/convex/docker-compose.yml @@ -1,9 +1,9 @@ services: backend: - image: ghcr.io/get-convex/convex-backend:33cef775a8a6228cbacee4a09ac2c4073d62ed13 - ports: - - "${PORT:-3210}:3210" - - "${SITE_PROXY_PORT:-3211}:3211" + image: ghcr.io/get-convex/convex-backend:5cdea511cd6527a95dd24152ea0d3c3bb2ab379f + expose: + - "3210" + - "3211" volumes: - data:/convex/data environment: @@ -14,7 +14,7 @@ services: - CONVEX_CLOUD_ORIGIN=${CONVEX_CLOUD_ORIGIN:-http://127.0.0.1:3210} - CONVEX_SITE_ORIGIN=${CONVEX_SITE_ORIGIN:-http://127.0.0.1:3211} - DATABASE_URL=${DATABASE_URL:-} - - DISABLE_BEACON=${DISABLE_BEACON:-} + - DISABLE_BEACON=${DISABLE_BEACON:-FALSE} - REDACT_LOGS_TO_CLIENT=${REDACT_LOGS_TO_CLIENT:-} - RUST_LOG=${RUST_LOG:-info} - RUST_BACKTRACE=${RUST_BACKTRACE:-} @@ -24,9 +24,9 @@ services: start_period: 5s dashboard: - image: ghcr.io/get-convex/convex-dashboard:33cef775a8a6228cbacee4a09ac2c4073d62ed13 - ports: - - "${DASHBOARD_PORT:-6791}:6791" + image: ghcr.io/get-convex/convex-dashboard:5cdea511cd6527a95dd24152ea0d3c3bb2ab379f + expose: + - "6791" environment: - NEXT_PUBLIC_DEPLOYMENT_URL=${NEXT_PUBLIC_DEPLOYMENT_URL:-http://127.0.0.1:3210} depends_on: diff --git a/blueprints/cut/cut.svg b/blueprints/cut/cut.svg new file mode 100644 index 000000000..c0604eac2 --- /dev/null +++ b/blueprints/cut/cut.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/blueprints/cut/docker-compose.yml b/blueprints/cut/docker-compose.yml new file mode 100644 index 000000000..b31578d10 --- /dev/null +++ b/blueprints/cut/docker-compose.yml @@ -0,0 +1,37 @@ +services: + cut: + image: ghcr.io/mendylanda/cut:latest + restart: unless-stopped + depends_on: + redis: + condition: service_healthy + environment: + # Injected by Dokploy from template.toml (generated strong password). + - ADMIN_PASSWORD=${ADMIN_PASSWORD} + # Bundled Redis below, private to the project network. + - REDIS_URL=redis://redis:6379 + # Expose the container port only; Dokploy maps the domain to it. + ports: + - 3000 + healthcheck: + test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/"] + interval: 10s + timeout: 5s + retries: 10 + + redis: + image: redis:7-alpine + restart: unless-stopped + # appendonly = durable across restarts; noeviction because this is Cut's + # primary datastore, not a cache (don't drop links under memory pressure). + command: redis-server --appendonly yes --maxmemory-policy noeviction + volumes: + - redis-data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 10 + +volumes: + redis-data: diff --git a/blueprints/cut/template.toml b/blueprints/cut/template.toml new file mode 100644 index 000000000..83de686c5 --- /dev/null +++ b/blueprints/cut/template.toml @@ -0,0 +1,14 @@ +[variables] +main_domain = "${domain}" +admin_password = "${password:24}" + +[config] +env = [ + "ADMIN_PASSWORD=${admin_password}", +] +mounts = [] + +[[config.domains]] +serviceName = "cut" +port = 3000 +host = "${main_domain}" diff --git a/blueprints/cyberchef/cyberchef.png b/blueprints/cyberchef/cyberchef.png new file mode 100644 index 000000000..4a3dfc32c Binary files /dev/null and b/blueprints/cyberchef/cyberchef.png differ diff --git a/blueprints/cyberchef/cyberchef.svg b/blueprints/cyberchef/cyberchef.svg deleted file mode 100644 index 84258252d..000000000 Binary files a/blueprints/cyberchef/cyberchef.svg and /dev/null differ diff --git a/blueprints/evolutionapi/docker-compose.yml b/blueprints/evolutionapi/docker-compose.yml index 5807ff824..16f125318 100644 --- a/blueprints/evolutionapi/docker-compose.yml +++ b/blueprints/evolutionapi/docker-compose.yml @@ -1,6 +1,6 @@ services: evolution-api: - image: atendai/evolution-api:v2.1.2 + image: evoapicloud/evolution-api:latest restart: always volumes: - evolution-instances:/evolution/instances diff --git a/blueprints/frappe-lending/docker-compose.yml b/blueprints/frappe-lending/docker-compose.yml new file mode 100644 index 000000000..60972a3b3 --- /dev/null +++ b/blueprints/frappe-lending/docker-compose.yml @@ -0,0 +1,550 @@ +x-custom-image: &custom_image + image: ${IMAGE_NAME:-frappe/erpnext}:${VERSION:-v15} + pull_policy: ${PULL_POLICY:-always} + deploy: + restart_policy: + condition: always + +services: + backend: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + echo "Waiting for site to be ready..."; + export start=`date +%s`; + while [ ! -f "sites/sites.txt" ] || [ ! -d "sites/${SITE_NAME}" ] || [ ! -f "sites/${SITE_NAME}/site_config.json" ]; do + echo "Waiting for site ${SITE_NAME} to be created and ready..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for site to be ready"; + echo "Checking sites directory:"; + ls -la sites/ || echo "sites directory not found"; + echo "Checking sites.txt:"; + cat sites/sites.txt 2>/dev/null || echo "sites.txt not found"; + break; + fi + done; + if [ -f "sites/sites.txt" ] && [ -d "sites/${SITE_NAME}" ] && [ -f "sites/${SITE_NAME}/site_config.json" ]; then + echo "Site ${SITE_NAME} is ready!"; + echo "sites.txt contents:"; + cat sites/sites.txt; + echo "Verifying site is accessible via bench..."; + bench --site ${SITE_NAME} list-apps > /dev/null 2>&1 && echo "Site is accessible via bench" || echo "Warning: Site accessibility check via bench failed"; + echo "Site directory structure:"; + ls -la sites/${SITE_NAME}/ | head -10; + if [ -n "${MAIN_DOMAIN}" ]; then + echo "Updating host_name and SSL settings to https://${MAIN_DOMAIN} (ensuring correct domain for emails)..."; + bench --site ${SITE_NAME} set-config host_name "https://${MAIN_DOMAIN}" || echo "Warning: Could not update host_name"; + bench --site ${SITE_NAME} set-config host_url "https://${MAIN_DOMAIN}" || echo "Warning: Could not update host_url"; + bench --site ${SITE_NAME} set-config use_ssl 1 || echo "Warning: Could not set use_ssl"; + echo "Verifying configuration..."; + bench --site ${SITE_NAME} get-config host_name 2>/dev/null || echo "Could not read host_name (this is OK if site is not fully initialized)"; + echo "Clearing cache to apply new domain settings..."; + bench --site ${SITE_NAME} clear-cache || echo "Warning: Could not clear cache"; + bench --site ${SITE_NAME} clear-website-cache || echo "Warning: Could not clear website cache"; + fi; + else + echo "Warning: Site may not be fully ready, but starting backend anyway"; + fi; + echo "Starting bench serve (production-ready)"; + export PYTHONUNBUFFERED=1; + bench serve --port 8000 2>&1 | awk '!/127\.0\.0\.1.*400/ {print}' || bench serve --port 8000; + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + environment: + SITE_NAME: ${SITE_NAME} + FRAPPE_SITE_NAME_HEADER: "" + MAIN_DOMAIN: ${MAIN_DOMAIN} + depends_on: + configurator: + condition: service_completed_successfully + required: true + create-site: + condition: service_completed_successfully + required: true + healthcheck: + test: + - CMD + - wait-for-it + - '0.0.0.0:8000' + interval: 2s + timeout: 10s + retries: 30 + + frontend: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + echo "Starting Nginx with port_in_redirect fix..."; + nginx-entrypoint.sh & + NGINX_PID=$!; + sleep 3; + if [ -f /etc/nginx/conf.d/frappe.conf ]; then + if ! grep -q "port_in_redirect off" /etc/nginx/conf.d/frappe.conf; then + echo "Applying port_in_redirect fix to prevent :8080 in URLs..."; + sed -i 's/listen 8080;/listen 8080;\n port_in_redirect off;\n absolute_redirect off;/' /etc/nginx/conf.d/frappe.conf; + echo "Nginx config updated - reloading..."; + sleep 1; + nginx -s reload 2>/dev/null || echo "Nginx will use updated config on next reload"; + else + echo "Nginx config already has port_in_redirect settings"; + fi + else + echo "Warning: frappe.conf not found yet, will check again"; + sleep 2; + if [ -f /etc/nginx/conf.d/frappe.conf ]; then + if ! grep -q "port_in_redirect off" /etc/nginx/conf.d/frappe.conf; then + sed -i 's/listen 8080;/listen 8080;\n port_in_redirect off;\n absolute_redirect off;/' /etc/nginx/conf.d/frappe.conf; + nginx -s reload 2>/dev/null || true; + fi + fi + fi; + wait $NGINX_PID + depends_on: + backend: + condition: service_started + required: true + websocket: + condition: service_started + required: true + environment: + BACKEND: backend:8000 + FRAPPE_SITE_NAME_HEADER: "" + SOCKETIO: websocket:9000 + UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1 + UPSTREAM_REAL_IP_HEADER: X-Forwarded-For + UPSTREAM_REAL_IP_RECURSIVE: "off" + USE_X_FORWARDED_HOST: "1" + PROXY_FIX: "1" + X_FORWARDED_PROTO: "https" + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + healthcheck: + test: + - CMD-SHELL + - curl -fsS http://127.0.0.1:8080/login || exit 1 + interval: 30s + timeout: 5s + retries: 3 + + queue-default: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench worker --queue default + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + + queue-long: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench worker --queue long + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + + queue-short: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench worker --queue short + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + + scheduler: + <<: *custom_image + entrypoint: ["bash", "-c"] + command: + - > + cd /home/frappe/frappe-bench; + export start=`date +%s`; + while [ ! -d "apps/lending" ]; do + echo "Waiting for apps to be available..."; + sleep 2; + if (( `date +%s`-start > 300 )); then + echo "Timeout waiting for apps"; + break; + fi; + done; + if [ -d "apps/lending" ] && ! ./env/bin/pip show lending > /dev/null 2>&1; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending"; + fi; + exec bench schedule + healthcheck: + test: + - CMD + - wait-for-it + - 'redis-queue:6379' + interval: 2s + timeout: 10s + retries: 30 + depends_on: + configurator: + condition: service_completed_successfully + required: true + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + websocket: + <<: *custom_image + healthcheck: + test: + - CMD + - wait-for-it + - '0.0.0.0:9000' + interval: 2s + timeout: 10s + retries: 30 + command: + - node + - /home/frappe/frappe-bench/apps/frappe/socketio.js + depends_on: + configurator: + condition: service_completed_successfully + required: true + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + configurator: + <<: *custom_image + deploy: + mode: replicated + replicas: ${CONFIGURE:-0} + restart_policy: + condition: none + entrypoint: ["bash", "-c"] + command: + - > + [[ $${REGENERATE_APPS_TXT} == "1" ]] && ls -1 apps > sites/apps.txt; + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && exit 0; + bench set-config -g db_host $$DB_HOST; + bench set-config -gp db_port $$DB_PORT; + bench set-config -g redis_cache "redis://$$REDIS_CACHE"; + bench set-config -g redis_queue "redis://$$REDIS_QUEUE"; + bench set-config -g redis_socketio "redis://$$REDIS_QUEUE"; + bench set-config -gp socketio_port $$SOCKETIO_PORT; + environment: + DB_HOST: "${DB_HOST:-db}" + DB_PORT: "3306" + REDIS_CACHE: redis-cache:6379 + REDIS_QUEUE: redis-queue:6379 + SOCKETIO_PORT: "9000" + REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}" + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + create-site: + <<: *custom_image + deploy: + mode: replicated + replicas: ${CREATE_SITE:-0} + restart_policy: + condition: none + entrypoint: ["bash", "-c"] + command: + - > + wait-for-it -t 120 $$DB_HOST:$$DB_PORT; + wait-for-it -t 120 redis-cache:6379; + wait-for-it -t 120 redis-queue:6379; + export start=`date +%s`; + until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \ + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \ + [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]]; + do + echo "Waiting for sites/common_site_config.json to be created"; + sleep 5; + if (( `date +%s`-start > 120 )); then + echo "could not find sites/common_site_config.json with required keys"; + exit 1 + fi + done; + echo "sites/common_site_config.json found"; + cd /home/frappe/frappe-bench; + if [ -d "sites/${SITE_NAME}" ] && [ -f "sites/${SITE_NAME}/site_config.json" ]; then + echo "Site ${SITE_NAME} already exists, skipping creation"; + bench use $${SITE_NAME} || echo "Warning: Could not set current site"; + echo "$${SITE_NAME}" > sites/sites.txt || echo "Warning: Could not update sites.txt"; + bench set-config -g default_site $${SITE_NAME} || echo "Warning: Could not set default site"; + if [ -n "$${ADMIN_PASSWORD}" ]; then + echo "Updating admin password for existing site..."; + bench --site $${SITE_NAME} set-admin-password $${ADMIN_PASSWORD} || echo "Warning: Could not update admin password (may need to be done manually)"; + fi; + if [ -n "$${MAIN_DOMAIN}" ]; then + echo "Setting host_name and SSL settings to https://${MAIN_DOMAIN} (with HTTPS)..."; + bench --site $${SITE_NAME} set-config host_name "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_name"; + bench --site $${SITE_NAME} set-config host_url "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_url"; + bench --site $${SITE_NAME} set-config use_ssl 1 || echo "Warning: Could not set use_ssl"; + echo "Clearing cache to apply new domain settings..."; + bench --site $${SITE_NAME} clear-cache || echo "Warning: Could not clear cache"; + bench --site $${SITE_NAME} clear-website-cache || echo "Warning: Could not clear website cache"; + fi; + echo "Verifying existing site is accessible..."; + bench --site $${SITE_NAME} list-apps > /dev/null 2>&1 && echo "Existing site is accessible and working" || echo "Warning: Site accessibility check failed"; + exit 0; + fi; + if [ ! -d "apps/lending" ]; then + echo "Cloning lending app..."; + git clone https://github.com/frappe/lending.git apps/lending || echo "Failed to clone lending app"; + fi; + if [ -d "apps/lending" ]; then + echo "Installing lending app in Python environment..."; + ./env/bin/pip install -e apps/lending || echo "Failed to install lending app"; + fi; + echo "Regenerating apps.txt to include all apps..."; + ls -1 apps > sites/apps.txt || (echo "frappe" > sites/apps.txt && echo "lending" >> sites/apps.txt); + echo "apps.txt contents:"; + cat sites/apps.txt; + bench set-mariadb-host $${DB_HOST:-db}; + bench new-site --mariadb-user-host-login-scope='%' --admin-password=$${ADMIN_PASSWORD} --db-root-username=root --db-root-password=$${DB_ROOT_PASSWORD} $${INSTALL_APP_ARGS} $${SITE_NAME}; + if [ ! -d "sites/${SITE_NAME}" ]; then + echo "ERROR: Site ${SITE_NAME} was not created successfully"; + exit 1; + fi; + echo "Site ${SITE_NAME} created successfully"; + bench use $${SITE_NAME}; + echo "Current site set to: $${SITE_NAME}"; + if [ -d "apps/lending" ]; then + echo "Installing lending app on site..."; + bench --site $${SITE_NAME} install-app lending || echo "Lending app may already be installed or failed to install"; + fi; + echo "Building assets for all apps (this ensures lending JS is available)..."; + bench build --apps lending || echo "Asset build completed"; + echo "Clearing all caches..."; + bench --site $${SITE_NAME} clear-cache || echo "Cache cleared"; + bench --site $${SITE_NAME} clear-website-cache || echo "Website cache cleared"; + echo "Creating sites.txt for site resolution..."; + echo "$${SITE_NAME}" > sites/sites.txt || echo "Warning: Could not create sites.txt"; + echo "Site registered in sites.txt:"; + cat sites/sites.txt || echo "sites.txt not found"; + echo "Verifying site directory and config exist..."; + if [ -d "sites/${SITE_NAME}" ] && [ -f "sites/${SITE_NAME}/site_config.json" ]; then + echo "Site directory and config verified successfully"; + else + echo "Warning: Site directory or config file missing"; + ls -la sites/${SITE_NAME}/ 2>/dev/null || echo "Site directory listing failed"; + fi; + echo "Setting default site in common_site_config.json..."; + bench set-config -g default_site $${SITE_NAME} || echo "Warning: Could not set default site"; + if [ -n "$${MAIN_DOMAIN}" ]; then + echo "Setting host_name and SSL settings to https://${MAIN_DOMAIN} (with HTTPS)..."; + bench --site $${SITE_NAME} set-config host_name "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_name"; + bench --site $${SITE_NAME} set-config host_url "https://$${MAIN_DOMAIN}" || echo "Warning: Could not set host_url"; + bench --site $${SITE_NAME} set-config use_ssl 1 || echo "Warning: Could not set use_ssl"; + echo "Clearing cache to apply new domain settings..."; + bench --site $${SITE_NAME} clear-cache || echo "Warning: Could not clear cache"; + bench --site $${SITE_NAME} clear-website-cache || echo "Warning: Could not clear website cache"; + fi; + echo "Verifying site is accessible..."; + bench --site $${SITE_NAME} list-apps > /dev/null 2>&1 && echo "Site is accessible and working" || echo "Warning: Site accessibility check failed"; + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + environment: + SITE_NAME: ${SITE_NAME} + MAIN_DOMAIN: ${main_domain} + ADMIN_PASSWORD: ${ADMIN_PASSWORD} + DB_HOST: ${DB_HOST:-db} + DB_PORT: "${DB_PORT:-3306}" + DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} + INSTALL_APP_ARGS: ${INSTALL_APP_ARGS} + + migration: + <<: *custom_image + deploy: + mode: replicated + replicas: ${MIGRATE:-0} + restart_policy: + condition: none + entrypoint: ["bash", "-c"] + command: + - > + curl -f http://${SITE_NAME}:8080/api/method/ping || echo "Site busy" && exit 0; + bench --site all set-config -p maintenance_mode 1; + bench --site all set-config -p pause_scheduler 1; + bench --site all migrate; + bench --site all set-config -p maintenance_mode 0; + bench --site all set-config -p pause_scheduler 0; + volumes: + - sites:/home/frappe/frappe-bench/sites + - apps:/home/frappe/frappe-bench/apps + + db: + image: mariadb:10.6 + deploy: + mode: replicated + replicas: ${ENABLE_DB:-0} + restart_policy: + condition: always + healthcheck: + test: mysqladmin ping -h localhost --password=${DB_ROOT_PASSWORD} + interval: 1s + retries: 20 + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --skip-character-set-client-handshake + - --skip-innodb-read-only-compressed + environment: + - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} + - MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD} + volumes: + - db-data:/var/lib/mysql + + redis-cache: + deploy: + restart_policy: + condition: always + image: redis:6.2-alpine + volumes: + - redis-cache-data:/data + healthcheck: + test: + - CMD + - redis-cli + - ping + interval: 5s + timeout: 5s + retries: 3 + + redis-queue: + deploy: + restart_policy: + condition: always + image: redis:6.2-alpine + volumes: + - redis-queue-data:/data + healthcheck: + test: + - CMD + - redis-cli + - ping + interval: 5s + timeout: 5s + retries: 3 + + redis-socketio: + deploy: + restart_policy: + condition: always + image: redis:6.2-alpine + volumes: + - redis-socketio-data:/data + healthcheck: + test: + - CMD + - redis-cli + - ping + interval: 5s + timeout: 5s + retries: 3 + +volumes: + db-data: + redis-cache-data: + redis-queue-data: + redis-socketio-data: + sites: + driver_opts: + type: "${SITE_VOLUME_TYPE}" + o: "${SITE_VOLUME_OPTS}" + device: "${SITE_VOLUME_DEV}" + apps: + diff --git a/blueprints/frappe-lending/frappe-lending.png b/blueprints/frappe-lending/frappe-lending.png new file mode 100644 index 000000000..e94e65a6e Binary files /dev/null and b/blueprints/frappe-lending/frappe-lending.png differ diff --git a/blueprints/frappe-lending/template.toml b/blueprints/frappe-lending/template.toml new file mode 100644 index 000000000..716129601 --- /dev/null +++ b/blueprints/frappe-lending/template.toml @@ -0,0 +1,29 @@ +[variables] +main_domain = "${domain}" +site_name = "frappe.lending" +db_root_password = "${password:32}" +admin_password = "${password:32}" + +[config] +env = [ + "SITE_NAME=${site_name}", + "ADMIN_PASSWORD=${admin_password}", + "DB_ROOT_PASSWORD=${db_root_password}", + "MIGRATE=1", + "ENABLE_DB=1", + "DB_HOST=db", + "CREATE_SITE=1", + "CONFIGURE=1", + "REGENERATE_APPS_TXT=1", + "INSTALL_APP_ARGS=--install-app erpnext --install-app lending", + "IMAGE_NAME=frappe/erpnext", + "VERSION=latest", + "FRAPPE_SITE_NAME_HEADER=", + "MAIN_DOMAIN=${main_domain}", +] +mounts = [] + +[[config.domains]] +serviceName = "frontend" +port = 8_080 +host = "${main_domain}" diff --git a/blueprints/go2rtc/docker-compose.yml b/blueprints/go2rtc/docker-compose.yml new file mode 100644 index 000000000..947c0feb1 --- /dev/null +++ b/blueprints/go2rtc/docker-compose.yml @@ -0,0 +1,24 @@ +version: "3.8" + +services: + go2rtc: + image: alexxit/go2rtc:1.9.14 + restart: unless-stopped + + # To use a local webcam, add the device to the service: + # devices: + # - /dev/video0:/dev/video0 # Adjust path if your device is at /dev/video1, etc. + + expose: + - 1984 # Web UI + - 8554 # RTSP + - 8555 # WebRTC + + environment: + - TZ=${TZ} + + volumes: + - go2rtc-config:/config + +volumes: + go2rtc-config: {} diff --git a/blueprints/go2rtc/go2rtc.png b/blueprints/go2rtc/go2rtc.png new file mode 100644 index 000000000..a9a81a3c1 Binary files /dev/null and b/blueprints/go2rtc/go2rtc.png differ diff --git a/blueprints/go2rtc/template.toml b/blueprints/go2rtc/template.toml new file mode 100644 index 000000000..f650f2fc4 --- /dev/null +++ b/blueprints/go2rtc/template.toml @@ -0,0 +1,13 @@ +[variables] +main_domain = "${domain}" + +[config] +[[config.domains]] +serviceName = "go2rtc" +port = 1984 +host = "${main_domain}" + +env = [ + "TZ=${TZ}" +] + diff --git a/blueprints/grafana/docker-compose.yml b/blueprints/grafana/docker-compose.yml index 9d913c17f..d7ec99a0b 100644 --- a/blueprints/grafana/docker-compose.yml +++ b/blueprints/grafana/docker-compose.yml @@ -1,7 +1,7 @@ version: "3.8" services: grafana: - image: grafana/grafana-enterprise:9.5.20 + image: grafana/grafana-enterprise:12.4 restart: unless-stopped volumes: - grafana-storage:/var/lib/grafana diff --git a/blueprints/imgproxy/docker-compose.yml b/blueprints/imgproxy/docker-compose.yml new file mode 100644 index 000000000..e9bc86a17 --- /dev/null +++ b/blueprints/imgproxy/docker-compose.yml @@ -0,0 +1,76 @@ +version: "3.8" +services: + imgproxy: + image: darthsim/imgproxy:v3.30.1 + restart: unless-stopped + environment: + IMGPROXY_KEY: ${IMGPROXY_KEY} + IMGPROXY_SALT: ${IMGPROXY_SALT} + IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION:-true} + IMGPROXY_ENFORCE_WEBP: ${IMGPROXY_ENFORCE_WEBP:-true} + IMGPROXY_TTL: ${IMGPROXY_TTL:-30600} + IMGPROXY_DEVELOPMENT_ERRORS_MODE: ${IMGPROXY_DEVELOPMENT_ERRORS_MODE:-false} + IMGPROXY_READ_TIMEOUT: ${IMGPROXY_READ_TIMEOUT:-10} + IMGPROXY_WRITE_TIMEOUT: ${IMGPROXY_WRITE_TIMEOUT:-10} + IMGPROXY_KEEP_ALIVE_TIMEOUT: ${IMGPROXY_KEEP_ALIVE_TIMEOUT:-10} + IMGPROXY_DOWNLOAD_TIMEOUT: ${IMGPROXY_DOWNLOAD_TIMEOUT:-5} + IMGPROXY_CONCURRENCY: ${IMGPROXY_CONCURRENCY:-} + IMGPROXY_MAX_CLIENTS: ${IMGPROXY_MAX_CLIENTS:-10} + IMGPROXY_SO_REUSEPORT: ${IMGPROXY_SO_REUSEPORT:-} + IMGPROXY_USER_AGENT: ${IMGPROXY_USER_AGENT:-} + IMGPROXY_USE_ETAG: ${IMGPROXY_USE_ETAG:-true} + IMGPROXY_QUALITY: ${IMGPROXY_QUALITY:-80} + IMGPROXY_ALLOWED_SOURCES: ${IMGPROXY_ALLOWED_SOURCES} + IMGPROXY_ALLOW_ORIGIN: ${IMGPROXY_ALLOW_ORIGIN:-*} + IMGPROXY_MAX_SRC_FILE_SIZE: ${IMGPROXY_MAX_SRC_FILE_SIZE:-20971520} + IMGPROXY_MAX_SRC_RESOLUTION: ${IMGPROXY_MAX_SRC_RESOLUTION:-50} + IMGPROXY_LOG_LEVEL: ${IMGPROXY_LOG_LEVEL:-error} + + nginx: + image: nginx:1.28.2-alpine + restart: unless-stopped + expose: + - 80 + environment: + NGINX_CACHE_LEVELS: ${NGINX_CACHE_LEVELS:-1:2} + NGINX_CACHE_KEYS_ZONE_SIZE: ${NGINX_CACHE_KEYS_ZONE_SIZE:-32m} + NGINX_CACHE_MAX_SIZE: ${NGINX_CACHE_MAX_SIZE:-500m} + NGINX_CACHE_INACTIVE: ${NGINX_CACHE_INACTIVE:-30d} + NGINX_CACHE_USE_TEMP_PATH: ${NGINX_CACHE_USE_TEMP_PATH:-off} + NGINX_CACHE_EXPIRES: ${NGINX_CACHE_EXPIRES:-30d} + depends_on: + - imgproxy + volumes: + - nginx-cache:/tmp/cache + command: + - /bin/sh + - -c + - | + cat < /etc/nginx/conf.d/default.conf + proxy_cache_path /tmp/cache levels=$${NGINX_CACHE_LEVELS} keys_zone=my_cache:$${NGINX_CACHE_KEYS_ZONE_SIZE} max_size=$${NGINX_CACHE_MAX_SIZE} inactive=$${NGINX_CACHE_INACTIVE} use_temp_path=$${NGINX_CACHE_USE_TEMP_PATH}; + + server { + listen 80 default_server; + listen [::]:80 default_server; + + location / { + expires $${NGINX_CACHE_EXPIRES}; + access_log off; + set \$$handle_webp 0; + if (\$$http_accept ~* "image/webp") { + set \$$handle_webp 1; + } + proxy_cache my_cache; + proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; + proxy_cache_background_update on; + proxy_cache_lock on; + proxy_cache_key "\$$scheme\$$host\$$uri\$$handle_webp"; + server_tokens off; + proxy_pass http://imgproxy:8080; + } + } + EOF + exec nginx -g 'daemon off;' + +volumes: + nginx-cache: diff --git a/blueprints/imgproxy/imgproxy.png b/blueprints/imgproxy/imgproxy.png new file mode 100644 index 000000000..cb26b97bb Binary files /dev/null and b/blueprints/imgproxy/imgproxy.png differ diff --git a/blueprints/imgproxy/template.toml b/blueprints/imgproxy/template.toml new file mode 100644 index 000000000..50b2dd791 --- /dev/null +++ b/blueprints/imgproxy/template.toml @@ -0,0 +1,56 @@ +[variables] +main_domain = "${domain}" +imgproxy_key = "${hash:128}" +imgproxy_salt = "${hash:128}" +imgproxy_allowed_sources = "http://${main_domain},https://${main_domain}" +imgproxy_quality = "80" +imgproxy_ttl = "30600" +imgproxy_max_src_file_size = "20971520" +imgproxy_max_src_resolution = "50" +imgproxy_log_level = "error" +imgproxy_max_clients = "10" +imgproxy_allow_origin = "*" +imgproxy_enable_webp_detection = "true" +imgproxy_enforce_webp = "true" +imgproxy_use_etag = "true" +nginx_cache_levels = "1:2" +nginx_cache_keys_zone_size = "32m" +nginx_cache_max_size = "500m" +nginx_cache_inactive = "30d" +nginx_cache_use_temp_path = "off" +nginx_cache_expires = "30d" + +[config] +[[config.domains]] +serviceName = "nginx" +port = 80 +host = "${main_domain}" + +[config.env] +IMGPROXY_KEY = "${imgproxy_key}" +IMGPROXY_SALT = "${imgproxy_salt}" +IMGPROXY_ENABLE_WEBP_DETECTION = "${imgproxy_enable_webp_detection}" +IMGPROXY_ENFORCE_WEBP = "${imgproxy_enforce_webp}" +IMGPROXY_TTL = "${imgproxy_ttl}" +IMGPROXY_DEVELOPMENT_ERRORS_MODE = "false" +IMGPROXY_READ_TIMEOUT = "10" +IMGPROXY_WRITE_TIMEOUT = "10" +IMGPROXY_KEEP_ALIVE_TIMEOUT = "10" +IMGPROXY_DOWNLOAD_TIMEOUT = "5" +IMGPROXY_CONCURRENCY = "" +IMGPROXY_MAX_CLIENTS = "${imgproxy_max_clients}" +IMGPROXY_SO_REUSEPORT = "" +IMGPROXY_USER_AGENT = "" +IMGPROXY_USE_ETAG = "${imgproxy_use_etag}" +IMGPROXY_QUALITY = "${imgproxy_quality}" +IMGPROXY_ALLOWED_SOURCES = "${imgproxy_allowed_sources}" +IMGPROXY_ALLOW_ORIGIN = "${imgproxy_allow_origin}" +IMGPROXY_MAX_SRC_FILE_SIZE = "${imgproxy_max_src_file_size}" +IMGPROXY_MAX_SRC_RESOLUTION = "${imgproxy_max_src_resolution}" +IMGPROXY_LOG_LEVEL = "${imgproxy_log_level}" +NGINX_CACHE_LEVELS = "${nginx_cache_levels}" +NGINX_CACHE_KEYS_ZONE_SIZE = "${nginx_cache_keys_zone_size}" +NGINX_CACHE_MAX_SIZE = "${nginx_cache_max_size}" +NGINX_CACHE_INACTIVE = "${nginx_cache_inactive}" +NGINX_CACHE_USE_TEMP_PATH = "${nginx_cache_use_temp_path}" +NGINX_CACHE_EXPIRES = "${nginx_cache_expires}" diff --git a/blueprints/mediafetch/docker-compose.yml b/blueprints/mediafetch/docker-compose.yml new file mode 100644 index 000000000..f0c690cd1 --- /dev/null +++ b/blueprints/mediafetch/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3.8" +services: + mediafetch: + image: lukedunsmoto/mediafetch:latest + restart: unless-stopped + expose: + - "3002" + volumes: + - mediafetch_data:/data/downloads + environment: + - PORT=3002 + - BASIC_AUTH_USER=${BASIC_AUTH_USER} + - BASIC_AUTH_PASS=${BASIC_AUTH_PASS} + - PUBLIC_BASE_URL=https://${DOMAIN} + - OUTPUT_DIR=/data/downloads + +volumes: + mediafetch_data: \ No newline at end of file diff --git a/blueprints/mediafetch/mediafetch.svg b/blueprints/mediafetch/mediafetch.svg new file mode 100644 index 000000000..e11cedb76 --- /dev/null +++ b/blueprints/mediafetch/mediafetch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/blueprints/mediafetch/template.toml b/blueprints/mediafetch/template.toml new file mode 100644 index 000000000..07672d4ec --- /dev/null +++ b/blueprints/mediafetch/template.toml @@ -0,0 +1,15 @@ +[variables] +BASIC_AUTH_USER = "admin" +BASIC_AUTH_PASS = "${password:12}" + +[config] +[[config.domains]] +name = "Domain" +variable = "DOMAIN" +serviceName = "mediafetch" +port = 3002 + +[[config.mounts]] +name = "Downloads" +filePath = "/data/downloads" +content = "mediafetch" \ No newline at end of file diff --git a/blueprints/meilisearch/docker-compose.yml b/blueprints/meilisearch/docker-compose.yml index ae5ebcb1a..db87310f2 100644 --- a/blueprints/meilisearch/docker-compose.yml +++ b/blueprints/meilisearch/docker-compose.yml @@ -2,12 +2,11 @@ version: "3.8" services: meilisearch: - image: getmeili/meilisearch:v1.8.3 + image: getmeili/meilisearch:v1.35.1 volumes: - meili_data:/meili_data environment: MEILI_MASTER_KEY: ${MEILI_MASTER_KEY} - MEILI_ENV: ${MEILI_ENV} volumes: meili_data: diff --git a/blueprints/meilisearch/template.toml b/blueprints/meilisearch/template.toml index b1bdb5f93..5b1b94ebf 100644 --- a/blueprints/meilisearch/template.toml +++ b/blueprints/meilisearch/template.toml @@ -11,5 +11,4 @@ port = 7_700 host = "${main_domain}" [config.env] -MEILI_ENV = "development" -MEILI_MASTER_KEY = "${master_key}" +MEILI_MASTER_KEY = "${master_key}" \ No newline at end of file diff --git a/blueprints/nextcloud-aio/docker-compose.yml b/blueprints/nextcloud-aio/docker-compose.yml index f262b1575..9cec8542c 100644 --- a/blueprints/nextcloud-aio/docker-compose.yml +++ b/blueprints/nextcloud-aio/docker-compose.yml @@ -1,32 +1,34 @@ services: nextcloud: - image: nextcloud:32.0.5 + image: nextcloud:stable restart: always - - ports: - - 80 volumes: - nextcloud_data:/var/www/html + - ../files/fix-nextcloud.sh:/usr/local/bin/fix-nextcloud.sh:ro environment: - - NEXTCLOUD_TRUSTED_DOMAINS=${NEXTCLOUD_DOMAIN} - MYSQL_HOST=nextcloud_db - MYSQL_DATABASE=nextcloud - MYSQL_USER=nextcloud - - MYSQL_PASSWORD=${MYSQL_SECRET_PASSWORD} - - OVERWRITEPROTOCOL=https + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + depends_on: + - nextcloud_db + - nextcloud_redis nextcloud_db: - image: mariadb + image: mariadb:10.11 restart: always - volumes: - nextcloud_db_data:/var/lib/mysql environment: - - MYSQL_ROOT_PASSWORD=${MYSQL_SECRET_PASSWORD_ROOT} + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE=nextcloud - MYSQL_USER=nextcloud - - MYSQL_PASSWORD=${MYSQL_SECRET_PASSWORD} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + + nextcloud_redis: + image: redis:alpine + restart: always volumes: nextcloud_data: - nextcloud_db_data: + nextcloud_db_data: \ No newline at end of file diff --git a/blueprints/nextcloud-aio/nextcloud-aio.svg b/blueprints/nextcloud-aio/nextcloud-aio.svg deleted file mode 100644 index 54e6056fa..000000000 --- a/blueprints/nextcloud-aio/nextcloud-aio.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/blueprints/nextcloud-aio/nextcloud.png b/blueprints/nextcloud-aio/nextcloud.png new file mode 100644 index 000000000..119d58b7e Binary files /dev/null and b/blueprints/nextcloud-aio/nextcloud.png differ diff --git a/blueprints/nextcloud-aio/template.toml b/blueprints/nextcloud-aio/template.toml index 30be77a1a..d45c89bee 100644 --- a/blueprints/nextcloud-aio/template.toml +++ b/blueprints/nextcloud-aio/template.toml @@ -1,17 +1,171 @@ [variables] -main_domain = "${domain}" -db_password = "${password}" -db_root_password = "${password}" + domain_name = "${domain}" + db_password = "${password:32}" + db_root_password = "${password:32}" + region = "DE" [config] -mounts = [] + env = [ + "MYSQL_PASSWORD=${db_password}", + "MYSQL_ROOT_PASSWORD=${db_root_password}", + "DEFAULT_PHONE_REGION=${region}", + "NEXTCLOUD_DOMAIN=${domain_name}", + "OVERWRITEPROTOCOL=https", + "TRUSTED_PROXIES=10.0.0.0/8 172.16.0.0/12", + "REDIS_HOST=nextcloud_redis", + "MYSQL_DATABASE=nextcloud", + "MYSQL_USER=nextcloud" + ] -[[config.domains]] -serviceName = "nextcloud" -port = 80 -host = "${main_domain}" + [[config.domains]] + serviceName = "nextcloud" + port = 80 + host = "${domain_name}" -[config.env] -NEXTCLOUD_DOMAIN = "${main_domain}" -MYSQL_SECRET_PASSWORD = "${db_password}" -MYSQL_SECRET_PASSWORD_ROOT = "${db_root_password}" + [[config.mounts]] + filePath = "fix-nextcloud.sh" + content = """#!/bin/sh +# +# Nextcloud Optimization Script +# ============================== +# This script applies production-ready optimizations to Nextcloud. +# +# MANUAL EXECUTION REQUIRED +# ------------------------- +# After Nextcloud completes its initial setup (create admin account, etc.), +# run this script manually: +# +# Option 1 (From Dokploy UI): +# 1. Go to your Nextcloud service in Dokploy +# 2. Open the Terminal tab +# 3. Run: su -s /bin/sh www-data -c "/bin/sh /usr/local/bin/fix-nextcloud.sh" +# +# Option 2 (From command line): +# docker exec -u www-data /bin/sh /usr/local/bin/fix-nextcloud.sh +# +# Optimizations include: +# - Trusted proxy configuration for reverse proxy support +# - HTTPS protocol override +# - Regional settings (phone region, maintenance window) +# - Performance optimizations (database repair, missing indices) +# - Redis caching configuration (APCu, distributed, locking) +# +# The script is idempotent - it creates a marker file to prevent re-running. +# To re-run manually: delete /var/www/html/data/.nextcloud-optimized and restart container +# + +MARKER_FILE="/var/www/html/data/.nextcloud-optimized" +OCC="php /var/www/html/occ" + +# Check if already run +if [ -f "$MARKER_FILE" ]; then + echo "Optimizations already applied (marker file exists)." + exit 0 +fi + +echo "==========================================" +echo " Nextcloud Optimization Script" +echo "==========================================" +echo "" + +# Check if running as www-data +CURRENT_USER=$(whoami) +if [ "$CURRENT_USER" = "www-data" ]; then + RUN_AS_WWWDATA="" +else + RUN_AS_WWWDATA="su -s /bin/sh www-data -c" +fi + +# Function to run occ command with error handling +run_occ() { + description="$1" + shift + printf " - %s... " "$description" + if [ -z "$RUN_AS_WWWDATA" ]; then + # Already running as www-data + if $OCC "$@" >/dev/null 2>&1; then + echo "✓" + return 0 + else + echo "✗ (failed, but continuing)" + return 1 + fi + else + # Need to switch to www-data + if $RUN_AS_WWWDATA "$OCC $*" >/dev/null 2>&1; then + echo "✓" + return 0 + else + echo "✗ (failed, but continuing)" + return 1 + fi + fi +} + +# Test database connectivity +echo "[1/5] Testing database connectivity..." +if [ -z "$RUN_AS_WWWDATA" ]; then + if $OCC status >/dev/null 2>&1; then + echo " ✓ Database is accessible" + else + echo " ✗ Database not accessible" + exit 1 + fi +else + if $RUN_AS_WWWDATA "$OCC status" >/dev/null 2>&1; then + echo " ✓ Database is accessible" + else + echo " ✗ Database not accessible" + exit 1 + fi +fi + +# Configure trusted proxies +echo "[2/5] Configuring trusted proxies..." +run_occ "Set trusted proxy 10.0.0.0/8" config:system:set trusted_proxies 0 --value='10.0.0.0/8' +run_occ "Set trusted proxy 172.16.0.0/12" config:system:set trusted_proxies 1 --value='172.16.0.0/12' +run_occ "Set trusted proxy 192.168.0.0/16" config:system:set trusted_proxies 2 --value='192.168.0.0/16' +run_occ "Set HTTPS protocol override" config:system:set overwriteprotocol --value='https' + +# Configure regional settings +echo "[3/5] Configuring regional settings..." +run_occ "Set phone region to DE" config:system:set default_phone_region --value='DE' +run_occ "Set maintenance window start" config:system:set maintenance_window_start --value=1 --type=integer + +# Run performance optimizations +echo "[4/5] Running performance optimizations..." +echo " - Running maintenance repair (this may take a while)..." +if [ -z "$RUN_AS_WWWDATA" ]; then + if $OCC maintenance:repair --include-expensive 2>&1 | grep -q "No repair steps available"; then + echo " ✓ No repairs needed" + else + echo " ✓ Repair completed" + fi +else + if $RUN_AS_WWWDATA "$OCC maintenance:repair --include-expensive" 2>&1 | grep -q "No repair steps available"; then + echo " ✓ No repairs needed" + else + echo " ✓ Repair completed" + fi +fi +run_occ "Add missing database indices" db:add-missing-indices + +# Configure Redis caching +echo "[5/5] Configuring Redis caching..." +run_occ "Set APCu for local cache" config:system:set memcache.local --value='\\OC\\Memcache\\APCu' +run_occ "Set Redis for distributed cache" config:system:set memcache.distributed --value='\\OC\\Memcache\\Redis' +run_occ "Set Redis for locking" config:system:set memcache.locking --value='\\OC\\Memcache\\Redis' +run_occ "Set Redis host" config:system:set redis host --value='nextcloud_redis' +run_occ "Set Redis port" config:system:set redis port --value=6379 --type=integer + +# Create marker file +touch "$MARKER_FILE" + +echo "" +echo "==========================================" +echo " Optimization Complete!" +echo "==========================================" +echo "All optimizations have been applied." +echo "Marker file created at: $MARKER_FILE" +echo "" +""" \ No newline at end of file diff --git a/blueprints/notifuse/docker-compose.yml b/blueprints/notifuse/docker-compose.yml index 7a33cd4d3..764cfc6c5 100644 --- a/blueprints/notifuse/docker-compose.yml +++ b/blueprints/notifuse/docker-compose.yml @@ -3,11 +3,11 @@ services: image: postgres:17-alpine restart: unless-stopped volumes: - - db-data:/var/lib/postgresql/data + - db_data:/var/lib/postgresql/data environment: - - POSTGRES_DB=postgres - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres + POSTGRES_DB: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s @@ -21,38 +21,36 @@ services: - db environment: # Root user configuration - - ROOT_EMAIL=${ROOT_EMAIL} + ROOT_EMAIL: ${ROOT_EMAIL} # API configuration - - API_ENDPOINT=${API_ENDPOINT} + API_ENDPOINT: ${API_ENDPOINT} # Database configuration - - DB_HOST=db - - DB_PORT=5432 - - DB_USER=postgres - - DB_PASSWORD=postgres - - DB_PREFIX=notifuse - - DB_NAME=notifuse_system - - DB_SSLMODE=disable + DB_HOST: db + DB_PORT: 5432 + DB_USER: postgres + DB_PASSWORD: postgres + DB_PREFIX: notifuse + DB_NAME: postgres + DB_SSLMODE: disable - # PASETO keys for authentication - # Default keys for testing - GENERATE YOUR OWN for production at https://paseto.notifuse.com/ - - PASETO_PRIVATE_KEY=${PASETO_PRIVATE_KEY} - - PASETO_PUBLIC_KEY=${PASETO_PUBLIC_KEY} - - # SMTP configuration - - SMTP_HOST=${SMTP_HOST} - - SMTP_PORT=${SMTP_PORT} - - SMTP_USERNAME=${SMTP_USERNAME} - - SMTP_PASSWORD=${SMTP_PASSWORD} - - SMTP_FROM_EMAIL=${SMTP_FROM_EMAIL} - - SMTP_FROM_NAME=${SMTP_FROM_NAME} + # Secret key for authentication (auto-generated) + SECRET_KEY: ${SECRET_KEY} # Server configuration - - SERVER_PORT=8080 - - SERVER_HOST=0.0.0.0 - - ENVIRONMENT=production + SERVER_PORT: 8080 + SERVER_HOST: 0.0.0.0 + ENVIRONMENT: production + volumes: + - notifuse_data:/app/data + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 10s volumes: - db-data: - driver: local + db_data: {} + notifuse_data: {} diff --git a/blueprints/notifuse/template.toml b/blueprints/notifuse/template.toml index ec619010c..6100203f5 100644 --- a/blueprints/notifuse/template.toml +++ b/blueprints/notifuse/template.toml @@ -1,7 +1,6 @@ [variables] main_domain = "${domain}" -paseto_private_key = "d04zCk3Fa45oOjDWHpAvc1AZxnLdGffOnNWK+Jt2yXf37+FTfuMMHb8flcfPMqLluRR3rvhbr555r6j1DEigrA==" -paseto_public_key = "9+/hU37jDB2/H5XHzzKi5bkUd674W6+eea+o9QxIoKw=" +secret_key = "${base64:64}" [config] [[config.domains]] @@ -12,18 +11,4 @@ host = "${main_domain}" [config.env] ROOT_EMAIL = "${email}" API_ENDPOINT = "https://${main_domain}" - -# PASETO keys for authentication -# Default keys for testing - GENERATE YOUR OWN for production at https://paseto.notifuse.com/ -PASETO_PRIVATE_KEY = "${paseto_private_key}" -PASETO_PUBLIC_KEY = "${paseto_public_key}" - -# SMTP Configuration (users need to configure these) -SMTP_HOST = "smtp.gmail.com" -SMTP_PORT = "587" -SMTP_USERNAME = "your-email@gmail.com" -SMTP_PASSWORD = "your-smtp-password" -SMTP_FROM_EMAIL = "noreply@yourdomain.com" -SMTP_FROM_NAME = "Notifuse" - -[[config.mounts]] +SECRET_KEY = "${secret_key}" diff --git a/blueprints/plunk/docker-compose.yml b/blueprints/plunk/docker-compose.yml index 914001cf6..9991d8554 100644 --- a/blueprints/plunk/docker-compose.yml +++ b/blueprints/plunk/docker-compose.yml @@ -1,58 +1,166 @@ -# IMPORTANT: Plunk requires HTTPS to work properly -# go to the "Domains" tab and enable HTTPS for your domain +# Plunk Self-Hosting Docker Compose for Dokploy +# This setup runs all Plunk services with nginx reverse proxy +# +# IMPORTANT: This template requires multiple subdomains: +# - api.yourdomain.com -> API Server +# - app.yourdomain.com -> Web Dashboard +# - www.yourdomain.com -> Landing Page +# - docs.yourdomain.com -> Documentation +# - minio.yourdomain.com -> Minio Console (optional) +# +# All domains will be automatically configured in Dokploy services: - plunk: - image: driaug/plunk - expose: - - "3000" - depends_on: - db: - condition: service_healthy - redis: - condition: service_started - environment: - REDIS_URL: ${REDIS_URL} - DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB} - JWT_SECRET: ${JWT_SECRET} - AWS_REGION: ${AWS_REGION} - AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} - AWS_SES_CONFIGURATION_SET: ${AWS_SES_CONFIGURATION_SET} - APP_URI: ${APP_URI} - NEXT_PUBLIC_API_URI: ${APP_URI}/api - API_URI: ${APP_URI}/api - DISABLE_SIGNUPS: ${DISABLE_SIGNUPS} - entrypoint: ["/app/entry.sh"] - restart: unless-stopped + # ============================================ + # Infrastructure Services + # ============================================ - db: - image: postgres:alpine + postgres: + image: postgres:16-alpine + restart: unless-stopped environment: - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_DB: plunk + POSTGRES_USER: plunk + POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] + test: ["CMD-SHELL", "pg_isready -U plunk"] interval: 10s + timeout: 5s retries: 5 - timeout: 10s - restart: unless-stopped - expose: - - 5432 redis: - image: redis:alpine + image: redis:7-alpine restart: unless-stopped - expose: - - 6379 + command: redis-server --appendonly yes volumes: - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + + minio: + image: minio/minio:latest + restart: unless-stopped + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: ${MINIO_ROOT_USER} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} + volumes: + - minio_data:/data + ports: + - 9000 + - 9001 + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 30s + timeout: 20s + retries: 3 + + # ============================================ + # Plunk Application + # ============================================ + + plunk: + image: ghcr.io/useplunk/plunk:latest + restart: unless-stopped + environment: + # Service mode - runs all services in one container + SERVICE: all + NODE_ENV: production + + # Database + DATABASE_URL: postgresql://plunk:${DB_PASSWORD}@postgres:5432/plunk + DIRECT_DATABASE_URL: postgresql://plunk:${DB_PASSWORD}@postgres:5432/plunk + + # Redis + REDIS_URL: ${REDIS_URL} + + # Security + JWT_SECRET: ${JWT_SECRET} + + # Nginx configuration + NGINX_PORT: ${NGINX_PORT} + + # Domain configuration (subdomain-based routing) + API_DOMAIN: ${API_DOMAIN} + DASHBOARD_DOMAIN: ${DASHBOARD_DOMAIN} + LANDING_DOMAIN: ${LANDING_DOMAIN} + WIKI_DOMAIN: ${WIKI_DOMAIN} + USE_HTTPS: ${USE_HTTPS} + + # AWS SES (for sending emails) - REQUIRED + AWS_SES_REGION: ${AWS_SES_REGION} + AWS_SES_ACCESS_KEY_ID: ${AWS_SES_ACCESS_KEY_ID} + AWS_SES_SECRET_ACCESS_KEY: ${AWS_SES_SECRET_ACCESS_KEY} + SES_CONFIGURATION_SET: ${SES_CONFIGURATION_SET} + SES_CONFIGURATION_SET_NO_TRACKING: ${SES_CONFIGURATION_SET_NO_TRACKING} + + # Optional: OAuth + GITHUB_OAUTH_CLIENT: ${GITHUB_OAUTH_CLIENT} + GITHUB_OAUTH_SECRET: ${GITHUB_OAUTH_SECRET} + GOOGLE_OAUTH_CLIENT: ${GOOGLE_OAUTH_CLIENT} + GOOGLE_OAUTH_SECRET: ${GOOGLE_OAUTH_SECRET} + + # Optional: Stripe + STRIPE_SK: ${STRIPE_SK} + STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET} + STRIPE_PRICE_ONBOARDING: ${STRIPE_PRICE_ONBOARDING} + STRIPE_PRICE_EMAIL_USAGE: ${STRIPE_PRICE_EMAIL_USAGE} + STRIPE_METER_EVENT_NAME: ${STRIPE_METER_EVENT_NAME} + + # S3-compatible storage (Minio) + S3_ENDPOINT: ${S3_ENDPOINT} + S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID} + S3_ACCESS_KEY_SECRET: ${S3_ACCESS_KEY_SECRET} + S3_BUCKET: ${S3_BUCKET} + S3_PUBLIC_URL: ${S3_PUBLIC_URL} + S3_FORCE_PATH_STYLE: ${S3_FORCE_PATH_STYLE} + + # SMTP Server (for sending emails via SMTP) + SMTP_DOMAIN: ${SMTP_DOMAIN} + PORT_SECURE: ${PORT_SECURE} + PORT_SUBMISSION: ${PORT_SUBMISSION} + + # Internal + PLUNK_API_KEY: ${PLUNK_API_KEY} + PLUNK_FROM_ADDRESS: ${PLUNK_FROM_ADDRESS} + + volumes: + # Mount Traefik certificates for SSL + - /etc/dokploy/traefik/dynamic/acme.json:/certs/acme.json:ro + + ports: + # Main nginx port (handles all subdomain routing) + - 80 + # SMTP ports (for email relay) + - 465 + - 587 + + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + minio: + condition: service_healthy + + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:80/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s volumes: postgres_data: driver: local redis_data: - driver: local \ No newline at end of file + driver: local + minio_data: + driver: local + plunk_data: + driver: local diff --git a/blueprints/plunk/template.toml b/blueprints/plunk/template.toml index 831f2c472..ce92c1fe0 100644 --- a/blueprints/plunk/template.toml +++ b/blueprints/plunk/template.toml @@ -1,30 +1,120 @@ [variables] -main_domain = "${domain}" -postgres_user = "plunk" -postgres_db = "plunk" +# Generate unique domains for each service +api_domain = "${domain}" +dashboard_domain = "${domain}" +landing_domain = "${domain}" +wiki_domain = "${domain}" +minio_domain = "${domain}" + +# Database credentials +postgres_password = "${password:32}" + +# Security +jwt_secret = "${password:64}" + +# Minio credentials +minio_root_user = "plunk" +minio_root_password = "${password:32}" [config] isolated = true +# API Domain +[[config.domains]] +serviceName = "plunk" +port = 80 +host = "${api_domain}" +path = "/" + +# Dashboard Domain +[[config.domains]] +serviceName = "plunk" +port = 80 +host = "${dashboard_domain}" +path = "/" + +# Landing Page Domain +[[config.domains]] +serviceName = "plunk" +port = 80 +host = "${landing_domain}" +path = "/" + +# Documentation Domain [[config.domains]] serviceName = "plunk" -port = 3000 -host = "${main_domain}" +port = 80 +host = "${wiki_domain}" +path = "/" + +# Minio Console Domain (optional) +[[config.domains]] +serviceName = "minio" +port = 9001 +host = "${minio_domain}" path = "/" [config.env] -POSTGRES_USER = "${postgres_user}" -POSTGRES_DB = "${postgres_db}" -POSTGRES_PASSWORD = "${password:32}" +# Database +DB_PASSWORD = "${postgres_password}" +# Redis REDIS_URL = "redis://redis:6379" -JWT_SECRET = "${password:64}" -APP_URI = "https://${main_domain}" +# Security +JWT_SECRET = "${jwt_secret}" + +# Nginx configuration +NGINX_PORT = "80" + +# Domain configuration (subdomain-based routing) +API_DOMAIN = "${api_domain}" +DASHBOARD_DOMAIN = "${dashboard_domain}" +LANDING_DOMAIN = "${landing_domain}" +WIKI_DOMAIN = "${wiki_domain}" +USE_HTTPS = "true" + +# AWS SES (Required - users must configure these for email to work) +AWS_SES_REGION = "us-east-1" +AWS_SES_ACCESS_KEY_ID = "" +AWS_SES_SECRET_ACCESS_KEY = "" +SES_CONFIGURATION_SET = "" + +# S3-compatible storage (Minio) +MINIO_ROOT_USER = "${minio_root_user}" +MINIO_ROOT_PASSWORD = "${minio_root_password}" +S3_ENDPOINT = "http://minio:9000" +S3_ACCESS_KEY_ID = "${minio_root_user}" +S3_ACCESS_KEY_SECRET = "${minio_root_password}" +S3_BUCKET = "uploads" +S3_PUBLIC_URL = "https://${minio_domain}/uploads" +S3_FORCE_PATH_STYLE = "true" + +# Minio ports +MINIO_API_PORT = "9000" +MINIO_CONSOLE_PORT = "9001" + +# SMTP Server ports +PORT_SECURE = "465" +PORT_SUBMISSION = "587" + +# Notifications (ntfy.sh) +NTFY_URL = "http://ntfy/plunk-notifications" + +# Optional: OAuth (leave empty if not using) +GITHUB_OAUTH_CLIENT = "" +GITHUB_OAUTH_SECRET = "" +GOOGLE_OAUTH_CLIENT = "" +GOOGLE_OAUTH_SECRET = "" -AWS_REGION = "" -AWS_ACCESS_KEY_ID = "" -AWS_SECRET_ACCESS_KEY = "" -AWS_SES_CONFIGURATION_SET = "" +# Optional: Stripe (leave empty if not using) +STRIPE_SK = "" +STRIPE_WEBHOOK_SECRET = "" +STRIPE_PRICE_ONBOARDING = "" +STRIPE_PRICE_EMAIL_USAGE = "" +STRIPE_METER_EVENT_NAME = "emails" -DISABLE_SIGNUPS = "False" \ No newline at end of file +# Internal +PLUNK_API_KEY = "" +PLUNK_FROM_ADDRESS = "" +SMTP_DOMAIN = "" \ No newline at end of file diff --git a/blueprints/tuwunel/docker-compose.yml b/blueprints/tuwunel/docker-compose.yml new file mode 100644 index 000000000..039ba0929 --- /dev/null +++ b/blueprints/tuwunel/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3.8" +services: + tuwunel: + image: ghcr.io/matrix-construct/tuwunel:v1.5.0 + restart: always + environment: + - TUWUNEL_SERVER_NAME=${TUWUNEL_SERVER_NAME:-matrix.local} + - TUWUNEL_ALLOW_REGISTRATION=${TUWUNEL_ALLOW_REGISTRATION:-false} + - TUWUNEL_REGISTRATION_TOKEN=${TUWUNEL_REGISTRATION_TOKEN} + - TUWUNEL_ADDRESS=${TUWUNEL_ADDRESS:-0.0.0.0} + - TUWUNEL_PORT=${TUWUNEL_PORT:-6167} + volumes: + - tuwunel-data:/var/lib/tuwunel/ + expose: + - 6167 + +volumes: + tuwunel-data: diff --git a/blueprints/tuwunel/template.toml b/blueprints/tuwunel/template.toml new file mode 100644 index 000000000..80dae5d5a --- /dev/null +++ b/blueprints/tuwunel/template.toml @@ -0,0 +1,15 @@ +[variables] +main_domain = "${domain}" +registration_token = "${password:32}" + +[config] +env = [ + "TUWUNEL_SERVER_NAME=${main_domain}", + "TUWUNEL_REGISTRATION_TOKEN=${registration_token}" +] +mounts = [] + +[[config.domains]] +serviceName = "tuwunel" +port = 6167 +host = "${main_domain}" diff --git a/blueprints/tuwunel/tuwunel.svg b/blueprints/tuwunel/tuwunel.svg new file mode 100644 index 000000000..79ec68b47 --- /dev/null +++ b/blueprints/tuwunel/tuwunel.svg @@ -0,0 +1,4 @@ + + + T + diff --git a/blueprints/unleash/docker-compose.yml b/blueprints/unleash/docker-compose.yml new file mode 100644 index 000000000..dc34db8d0 --- /dev/null +++ b/blueprints/unleash/docker-compose.yml @@ -0,0 +1,49 @@ +# The default users credentials are: +# Login: admin +# Password: unleash4all +# It is highly recommended to change the password after first login. +# More info: https://github.com/Unleash/unleash?tab=readme-ov-file#unleash-open-source +version: "3.8" + +services: + unleash: + image: unleashorg/unleash-server:7.4.0 + restart: unless-stopped + environment: + DATABASE_URL: "postgres://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}" + DATABASE_SSL: "false" + LOG_LEVEL: "warn" + depends_on: + db: + condition: service_healthy + healthcheck: + test: wget --no-verbose --tries=1 --spider http://localhost:4242/health || exit 1 + interval: 1s + timeout: 1m + retries: 5 + start_period: 15s + db: + image: postgres:15 + restart: unless-stopped + environment: + POSTGRES_DB: "${DB_NAME}" + POSTGRES_USER: "${DB_USER}" + POSTGRES_PASSWORD: "${DB_PASSWORD}" + volumes: + - db_data:/var/lib/postgresql/data + healthcheck: + test: + [ + "CMD", + "pg_isready", + "--username=${DB_USER}", + "--host=127.0.0.1", + "--port=5432", + ] + interval: 2s + timeout: 1m + retries: 5 + start_period: 10s + +volumes: + db_data: diff --git a/blueprints/unleash/template.toml b/blueprints/unleash/template.toml new file mode 100644 index 000000000..f57ef9757 --- /dev/null +++ b/blueprints/unleash/template.toml @@ -0,0 +1,17 @@ +[variables] +main_domain = "${domain}" +db_name = "unleash" +db_user = "unleash" +db_password = "${password:32}" + +[config] +env = [ + "DB_NAME=${db_name}", + "DB_USER=${db_user}", + "DB_PASSWORD=${db_password}" +] + +[[config.domains]] +serviceName = "unleash" +port = 4242 +host = "${main_domain}" \ No newline at end of file diff --git a/blueprints/unleash/unleash.png b/blueprints/unleash/unleash.png new file mode 100644 index 000000000..9b6b5b8dc Binary files /dev/null and b/blueprints/unleash/unleash.png differ diff --git a/blueprints/verdaccio/docker-compose.yml b/blueprints/verdaccio/docker-compose.yml new file mode 100644 index 000000000..091f3d156 --- /dev/null +++ b/blueprints/verdaccio/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3.8" + +services: + verdaccio: + image: verdaccio/verdaccio:6 + environment: + - VERDACCIO_PORT=4873 + ports: + - 4873 + volumes: + - verdaccio_storage:/verdaccio/storage + - verdaccio_plugins:/verdaccio/plugins + - ../files/conf:/verdaccio/conf + +volumes: + verdaccio_storage: + verdaccio_plugins: \ No newline at end of file diff --git a/blueprints/verdaccio/template.toml b/blueprints/verdaccio/template.toml new file mode 100644 index 000000000..996bbd547 --- /dev/null +++ b/blueprints/verdaccio/template.toml @@ -0,0 +1,259 @@ +[variables] +main_domain = "${domain}" + +[config] +[[config.domains]] +serviceName = "verdaccio" +port = 4873 +host = "${main_domain}" + +[[config.mounts]] +filePath = "/conf/config.yaml" +content = """ +# +# This is the default configuration file. It allows all users to do anything, +# please read carefully the documentation and best practices to +# improve security. +# +# Look here for more config file examples: +# https://github.com/verdaccio/verdaccio/blob/master/docker-examples/README.md +# +# Read about the best practices +# https://verdaccio.org/docs/best + +# Path to a directory with all packages +storage: /verdaccio/storage/data + +# Path to a directory with plugins to include, the plugins folder has the higher priority for loading plugins +# Disable this folder to avoid warnings if is not used +plugins: /verdaccio/plugins + +# Web UI settings +# https://verdaccio.org/docs/webui +web: + title: Verdaccio + # Disable complete web UI + # enabled: false + # Custom colors for header background and font + # primaryColor: "#4b5e40" + # Custom logos and favicon + # logo: ./path/to/logo.png + # logoDark: ./path/to/logoDark.png + # favicon: ./path/to/favicon.ico + # Disable gravatar support + # gravatar: false + # By default, packages are ordered ascending + # sort_packages: asc | desc + # Convert your UI to the dark side + # darkMode: true + # html_cache: true + # By default, all features are displayed + # login: true + # showInfo: true + # showSettings: true + # In combination with darkMode you can force specific theme + # showThemeSwitch: true + # showFooter: true + # showSearch: true + # showRaw: true + # showDownloadTarball: true + # showUplinks: true + # + # HTML tags injected before ends + # metaScripts: + # - '' + # - '' + # - '' + # + # HTML tags injected as first child in + # scriptsBodyBefore: + # - '
html before webpack scripts
' + # + # HTML tags injected as last child in + # scriptsBodyAfter: + # - '' + # + # Public path for template manifest scripts (only manifest) + # publicPath: http://somedomain.org/ + +# Settings for authentication plugin +# https://verdaccio.org/docs/configuration#authentication +auth: + htpasswd: + file: /verdaccio/storage/htpasswd + # Maximum amount of users allowed to register, defaults to "+inf". + # You can set this to -1 to disable registration. + max_users: 1 + +# A list of other known repositories we can talk to +# https://verdaccio.org/docs/configuration#uplinks +uplinks: + npmjs: + url: https://registry.npmjs.org/ + +# Learn how to protect your packages +# https://verdaccio.org/docs/protect-your-dependencies/ +# https://verdaccio.org/docs/configuration#packages +packages: + '@*/*': + # scoped packages + access: $all + publish: $authenticated + unpublish: $authenticated + proxy: npmjs + + '**': + # allow all users (including non-authenticated users) to read and + # publish all packages + # + # you can specify usernames/groupnames (depending on your auth plugin) + # and three keywords: "$all", "$anonymous", "$authenticated" + access: $all + + # allow all known users to publish/unpublish packages + # (anyone can register by default, remember?) + publish: $authenticated + unpublish: $authenticated + + # if package is not available locally, proxy requests to 'npmjs' registry + proxy: npmjs + +# To improve your security configuration and avoid dependency confusion +# consider removing the proxy property for private packages +# https://verdaccio.org/docs/best#remove-proxy-to-increase-security-at-private-packages + +# https://verdaccio.org/docs/configuration#server +# You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections. +# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout. +# WORKAROUND: Through given configuration you can workaround following issue https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enough. +server: + keepAliveTimeout: 60 + # The pluginPrefix replaces the default plugins prefix which is `verdaccio`. Please don't include `-`. If `something` is provided + # the resolved package will be `something-xxxx`. + # pluginPrefix: something + # A regex for the password validation /.{3}$/ (3 characters min) + # An example to limit to 10 characters minimum + # passwordValidationRegex: /.{10}$/ + # Allow `req.ip` to resolve properly when Verdaccio is behind a proxy or load-balancer + # https://expressjs.com/en/guide/behind-proxies.html + # trustProxy: '127.0.0.1' + +# https://verdaccio.org/docs/configuration#offline-publish +# publish: +# allow_offline: false +# check_owners: false +# keep_readmes: 'latest' | 'tagged' | 'all' + +# Define public URL of registry in combination with VERDACCIO_PUBLIC_URL environment variable +# https://verdaccio.org/docs/configuration#url-prefix +# url_prefix: /verdaccio/ +# +# Examples: +# VERDACCIO_PUBLIC_URL='https://somedomain.org' +# url_prefix: '/my_prefix' +# // url -> https://somedomain.org/my_prefix/ +# +# VERDACCIO_PUBLIC_URL='https://somedomain.org' +# url_prefix: '/' +# // url -> https://somedomain.org/ +# +# VERDACCIO_PUBLIC_URL='https://somedomain.org/first_prefix' +# url_prefix: '/second_prefix' +# // url -> https://somedomain.org/second_prefix/ + +# Security settings +# https://verdaccio.org/docs/configuration#security +# security: +# api: +# legacy: true +# jwt: +# sign: +# expiresIn: 29d +# verify: +# someProp: [value] +# web: +# sign: +# expiresIn: 1h # 1 hour by default +# verify: +# someProp: [value] + +# https://verdaccio.org/docs/configuration#user-rate-limit +# userRateLimit: +# windowMs: 50000 +# max: 1000 + +# https://verdaccio.org/docs/configuration#max-body-size +# max_body_size: 10mb + +# https://verdaccio.org/docs/configuration#listen-port +# listen: +# - localhost:4873 # default value +# - http://localhost:4873 # same thing +# - 0.0.0.0:4873 # listen on all addresses (INADDR_ANY) +# - https://example.org:4873 # if you want to use https +# - "[::1]:4873" # ipv6 +# - unix:/tmp/verdaccio.sock # unix socket + +# The HTTPS configuration is useful if you do not consider use a HTTP Proxy +# https://verdaccio.org/docs/configuration#https +# https: +# key: ./path/verdaccio-key.pem +# cert: ./path/verdaccio-cert.pem +# ca: ./path/verdaccio-csr.pem + +# https://verdaccio.org/docs/configuration#proxy +# http_proxy: http://something.local/ +# https_proxy: https://something.local/ +# no_proxy: localhost,127.0.0.1,server.local + +# https://verdaccio.org/docs/configuration#notifications +# notify: +# method: 'POST' +# headers: '[{ "Content-Type": "application/json" }]' +# endpoint: 'https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken' +# content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}' + +# Settings for middleware plugins +# https://verdaccio.org/docs/plugins#middleware-configuration +middlewares: + audit: + enabled: true + # timeout: 10000 + +# Log settings +# https://verdaccio.org/docs/logger +# Redaction: https://getpino.io/#/docs/redaction +# Synchronous logging: https://getpino.io/#/docs/asynchronous +log: + type: stdout + format: pretty + level: http +# redact: +# paths: ['req.header.authorization','req.header.cookie','req.remoteAddress','req.remotePort','ip','remoteIP','user','msg'] +# censor: '' +# sync: true + +# Feature flags (experimental settings that can be changed or removed in the future) +# https://verdaccio.org/docs/configuration#experiments +# experiments: +# # Support for npm token command +# token: false +# # Enable tarball URL redirect for hosting tarball with a different server. +# # The tarball_url_redirect can be a template string +# tarball_url_redirect: 'https://mycdn.com/verdaccio/${packageName}/${filename}' +# # The tarball_url_redirect can be a function, takes packageName and filename and returns the url, +# # when working with a js configuration file +# tarball_url_redirect(packageName, filename) { +# const signedUrl = // generate a signed url +# return signedUrl; +# } +# Renamed from "experiments" to "flags" in next major release +# flags: +# changePassword: true +# searchRemote: true + +# Translate your registry, API and web UI +# List of the available translations https://github.com/verdaccio/verdaccio/blob/master/packages/plugins/ui-theme/src/i18n/ABOUT_TRANSLATIONS.md +i18n: + web: en-US +""" \ No newline at end of file diff --git a/blueprints/verdaccio/verdaccio.svg b/blueprints/verdaccio/verdaccio.svg new file mode 100644 index 000000000..a9e07b295 --- /dev/null +++ b/blueprints/verdaccio/verdaccio.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/meta.json b/meta.json index 42cdf342c..c4632a56a 100644 --- a/meta.json +++ b/meta.json @@ -1680,12 +1680,28 @@ "self-hosted" ] }, + { + "id": "cut", + "name": "Cut", + "version": "0.1.0", + "description": "A tiny, self-hosted URL shortener — short links that are entirely yours, with per-link passwords, expiries, and click limits.", + "logo": "cut.svg", + "links": { + "github": "https://github.com/MendyLanda/cut", + "website": "https://github.com/MendyLanda/cut", + "docs": "https://github.com/MendyLanda/cut#readme" + }, + "tags": [ + "url-shortener", + "links" + ] + }, { "id": "cyberchef", "name": "CyberChef", "version": "latest", "description": "CyberChef is a web application for encryption, encoding, compression, and data analysis, developed by GCHQ.", - "logo": "cyberchef.svg", + "logo": "cyberchef.png", "links": { "github": "https://github.com/gchq/CyberChef", "website": "https://gchq.github.io/CyberChef/", @@ -2543,6 +2559,26 @@ "performace" ] }, + { + "id": "frappe-lending", + "name": "Frappe Lending", + "version": "latest", + "description": "A comprehensive loan management system built on Frappe Framework. 100% open source and customizable for managing loans, repayments, and lending operations.", + "logo": "frappe-lending.png", + "links": { + "github": "https://github.com/frappe/lending", + "docs": "https://docs.frappe.io/lending", + "website": "https://frappe.io" + }, + "tags": [ + "lending", + "finance", + "loans", + "payments", + "accounting", + "self-hosted" + ] + }, { "id": "freescout", "name": "FreeScout", @@ -2810,6 +2846,24 @@ "api" ] }, + { + "id": "go2rtc", + "name": "go2rtc", + "version": "latest", + "description": "Ultimate camera streaming application with support for dozens formats and protocols.", + "logo": "go2rtc.png", + "links": { + "github": "https://github.com/AlexxIT/go2rtc", + "website": "https://go2rtc.org/", + "docs": "https://go2rtc.org/" + }, + "tags": [ + "streaming", + "webrtc", + "video", + "home assistant" + ] + }, { "id": "gotenberg", "name": "Gotenberg", @@ -2831,7 +2885,7 @@ { "id": "grafana", "name": "Grafana", - "version": "9.5.20", + "version": "12.4", "description": "Grafana is an open source platform for data visualization and monitoring.", "logo": "grafana.svg", "links": { @@ -3099,6 +3153,25 @@ "group-finances" ] }, + { + "id": "imgproxy", + "name": "imgproxy", + "version": "v3.30.1", + "description": "imgproxy is a fast and secure image processing server, fronted by nginx with built-in response caching for repeated transformations.", + "logo": "imgproxy.png", + "links": { + "github": "https://github.com/imgproxy/imgproxy", + "website": "https://imgproxy.net/", + "docs": "https://docs.imgproxy.net/" + }, + "tags": [ + "images", + "media", + "proxy", + "cdn", + "caching" + ] + }, { "id": "immich", "name": "Immich", @@ -3929,10 +4002,27 @@ "self-hosted" ] }, + { + "id": "mediafetch", + "name": "MediaFetch", + "version": "1.1.1", + "description": "A tiny, self-hosted web wrapper for yt-dlp to download video and audio. Optional basic auth.", + "logo": "mediafetch.svg", + "links": { + "github": "https://github.com/lukedunsmoto/mediafetch", + "website": "https://www.lukedunsmore.com/mediafetch", + "docs": "https://docs.lukedunsmore.com/docs/self-hosted/mediafetch/" + }, + "tags": [ + "utilities", + "media", + "downloader" + ] + }, { "id": "meilisearch", "name": "Meilisearch", - "version": "v1.8.3", + "version": "v1.35.1", "description": "Meilisearch is a free and open-source search engine that allows you to easily add search functionality to your web applications.", "logo": "meilisearch.png", "links": { @@ -4294,10 +4384,10 @@ }, { "id": "nextcloud-aio", - "name": "Nextcloud All in One", - "version": "30.0.2", - "description": "Nextcloud (AIO) is a self-hosted file storage and sync platform with powerful collaboration capabilities. It integrates Files, Talk, Groupware, Office, Assistant and more into a single platform for remote work and data protection.", - "logo": "nextcloud-aio.svg", + "name": "Nextcloud", + "version": "stable", + "description": "Nextcloud is a self-hosted file storage and sync platform with powerful collaboration capabilities. It integrates Files, Talk, Groupware, Office, Assistant and more into a single platform for remote work and data protection.", + "logo": "nextcloud.png", "links": { "github": "https://github.com/nextcloud/docker", "website": "https://nextcloud.com/", @@ -5879,6 +5969,24 @@ "open-source" ] }, + { + "id": "strapi", + "name": "Strapi", + "version": "v5.33.0", + "description": "Open-source headless CMS to build powerful APIs with built-in content management.", + "logo": "strapi.svg", + "links": { + "github": "https://github.com/strapi/strapi", + "discord": "https://discord.com/invite/strapi", + "docs": "https://docs.strapi.io", + "website": "https://strapi.io" + }, + "tags": [ + "headless", + "cms", + "content-management" + ] + }, { "id": "streamflow", "name": "StreamFlow", @@ -5898,24 +6006,6 @@ "media" ] }, - { - "id": "strapi", - "name": "Strapi", - "version": "v5.33.0", - "description": "Open-source headless CMS to build powerful APIs with built-in content management.", - "logo": "strapi.svg", - "links": { - "github": "https://github.com/strapi/strapi", - "discord": "https://discord.com/invite/strapi", - "docs": "https://docs.strapi.io", - "website": "https://strapi.io" - }, - "tags": [ - "headless", - "cms", - "content-management" - ] - }, { "id": "supabase", "name": "SupaBase", @@ -6173,6 +6263,24 @@ "e-ink" ] }, + { + "id": "tuwunel", + "name": "Tuwunel", + "version": "v1.5.0", + "description": "High performance Matrix homeserver written in Rust. Official successor to conduwuit - a scalable, low-cost, enterprise-ready alternative to Synapse.", + "logo": "tuwunel.svg", + "links": { + "github": "https://github.com/matrix-construct/tuwunel", + "website": "https://tuwunel.chat", + "docs": "https://matrix-construct.github.io/tuwunel/" + }, + "tags": [ + "matrix", + "chat", + "messaging", + "rust" + ] + }, { "id": "twenty", "name": "Twenty CRM", @@ -6270,6 +6378,24 @@ "networking" ] }, + { + "id": "unleash", + "name": "Unleash", + "version": "7.4.0", + "description": "Open-source feature management platform", + "logo": "unleash.png", + "links": { + "github": "https://github.com/unleash/unleash", + "website": "https://www.getunleash.io/", + "docs": "https://docs.getunleash.io/" + }, + "tags": [ + "feature-flag", + "feature-management", + "feature-toggle", + "remote-configuration" + ] + }, { "id": "upsnap", "name": "Upsnap", @@ -6372,6 +6498,23 @@ "open-source" ] }, + { + "id": "verdaccio", + "name": "Verdaccio", + "version": "6", + "description": "A lightweight Node.js private proxy registry", + "logo": "verdaccio.svg", + "links": { + "github": "https://github.com/verdaccio/verdaccio", + "website": "https://www.verdaccio.org/", + "docs": "https://www.verdaccio.org/docs/what-is-verdaccio" + }, + "tags": [ + "node.js", + "package-repository", + "npm" + ] + }, { "id": "vikunja", "name": "Vikunja",