diff --git a/apps/dokploy/public/templates/huly.svg b/apps/dokploy/public/templates/huly.svg new file mode 100644 index 00000000..55a98587 --- /dev/null +++ b/apps/dokploy/public/templates/huly.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/dokploy/templates/huly/docker-compose.yml b/apps/dokploy/templates/huly/docker-compose.yml new file mode 100644 index 00000000..b054d56a --- /dev/null +++ b/apps/dokploy/templates/huly/docker-compose.yml @@ -0,0 +1,184 @@ +name: ${DOCKER_NAME} +version: "3" +services: + nginx: + networks: + - dokploy-network + image: "nginx:1.21.3" + ports: + - 80 + volumes: + - ../files/volumes/nginx/.huly.nginx:/etc/nginx/conf.d/default.conf + restart: unless-stopped + + mongodb: + networks: + - dokploy-network + image: "mongo:7-jammy" + environment: + - PUID=1000 + - PGID=1000 + volumes: + - db:/data/db + restart: unless-stopped + + minio: + networks: + - dokploy-network + image: "minio/minio" + command: server /data --address ":9000" --console-address ":9001" + volumes: + - files:/data + restart: unless-stopped + + elastic: + networks: + - dokploy-network + image: "elasticsearch:7.14.2" + command: | + /bin/sh -c "./bin/elasticsearch-plugin list | grep -q ingest-attachment || yes | ./bin/elasticsearch-plugin install --silent ingest-attachment; + /usr/local/bin/docker-entrypoint.sh eswrapper" + volumes: + - elastic:/usr/share/elasticsearch/data + environment: + - ELASTICSEARCH_PORT_NUMBER=9200 + - BITNAMI_DEBUG=true + - discovery.type=single-node + - ES_JAVA_OPTS=-Xms1024m -Xmx1024m + - http.cors.enabled=true + - http.cors.allow-origin=http://localhost:8082 + healthcheck: + interval: 20s + retries: 10 + test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"' + restart: unless-stopped + + rekoni: + networks: + - dokploy-network + image: hardcoreeng/rekoni-service:${HULY_VERSION} + environment: + - SECRET=${SECRET} + deploy: + resources: + limits: + memory: 500M + restart: unless-stopped + + transactor: + networks: + - dokploy-network + image: hardcoreeng/transactor:${HULY_VERSION} + environment: + - SERVER_PORT=3333 + - SERVER_SECRET=${SECRET} + - SERVER_CURSOR_MAXTIMEMS=30000 + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - FRONT_URL=http://localhost:8087 + - ACCOUNTS_URL=http://account:3000 + - FULLTEXT_URL=http://fulltext:4700 + - STATS_URL=http://stats:4900 + - LAST_NAME_FIRST=${LAST_NAME_FIRST:-true} + restart: unless-stopped + + collaborator: + networks: + - dokploy-network + image: hardcoreeng/collaborator:${HULY_VERSION} + environment: + - COLLABORATOR_PORT=3078 + - SECRET=${SECRET} + - ACCOUNTS_URL=http://account:3000 + - DB_URL=mongodb://mongodb:27017 + - STATS_URL=http://stats:4900 + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + restart: unless-stopped + + account: + networks: + - dokploy-network + image: hardcoreeng/account:${HULY_VERSION} + environment: + - SERVER_PORT=3000 + - SERVER_SECRET=${SECRET} + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - TRANSACTOR_URL=ws://transactor:3333;ws${SECURE:+s}://${HOST_ADDRESS}/_transactor + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - FRONT_URL=http://front:8080 + - STATS_URL=http://stats:4900 + - MODEL_ENABLED=* + - ACCOUNTS_URL=http://localhost:3000 + - ACCOUNT_PORT=3000 + restart: unless-stopped + + workspace: + networks: + - dokploy-network + image: hardcoreeng/workspace:${HULY_VERSION} + environment: + - SERVER_SECRET=${SECRET} + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - TRANSACTOR_URL=ws://transactor:3333;ws${SECURE:+s}://${HOST_ADDRESS}/_transactor + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - MODEL_ENABLED=* + - ACCOUNTS_URL=http://account:3000 + - STATS_URL=http://stats:4900 + restart: unless-stopped + + front: + networks: + - dokploy-network + image: hardcoreeng/front:${HULY_VERSION} + environment: + - SERVER_PORT=8080 + - SERVER_SECRET=${SECRET} + - LOVE_ENDPOINT=http${SECURE:+s}://${HOST_ADDRESS}/_love + - ACCOUNTS_URL=http${SECURE:+s}://${HOST_ADDRESS}/_accounts + - REKONI_URL=http${SECURE:+s}://${HOST_ADDRESS}/_rekoni + - CALENDAR_URL=http${SECURE:+s}://${HOST_ADDRESS}/_calendar + - GMAIL_URL=http${SECURE:+s}://${HOST_ADDRESS}/_gmail + - TELEGRAM_URL=http${SECURE:+s}://${HOST_ADDRESS}/_telegram + - STATS_URL=http${SECURE:+s}://${HOST_ADDRESS}/_stats + - UPLOAD_URL=/files + - ELASTIC_URL=http://elastic:9200 + - COLLABORATOR_URL=ws${SECURE:+s}://${HOST_ADDRESS}/_collaborator + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - DB_URL=mongodb://mongodb:27017 + - MONGO_URL=mongodb://mongodb:27017 + - TITLE=${TITLE:-Huly Self Host} + - DEFAULT_LANGUAGE=${DEFAULT_LANGUAGE:-en} + - LAST_NAME_FIRST=${LAST_NAME_FIRST:-true} + - DESKTOP_UPDATES_CHANNEL=selfhost + restart: unless-stopped + + fulltext: + networks: + - dokploy-network + image: hardcoreeng/fulltext:${HULY_VERSION} + environment: + - SERVER_SECRET=${SECRET} + - DB_URL=mongodb://mongodb:27017 + - FULLTEXT_DB_URL=http://elastic:9200 + - ELASTIC_INDEX_NAME=huly_storage_index + - STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin + - REKONI_URL=http://rekoni:4004 + - ACCOUNTS_URL=http://account:3000 + - STATS_URL=http://stats:4900 + restart: unless-stopped + + stats: + networks: + - dokploy-network + image: hardcoreeng/stats:${HULY_VERSION} + environment: + - PORT=4900 + - SERVER_SECRET=${SECRET} + restart: unless-stopped +volumes: + db: + elastic: + files: diff --git a/apps/dokploy/templates/huly/index.ts b/apps/dokploy/templates/huly/index.ts new file mode 100644 index 00000000..deb5c7db --- /dev/null +++ b/apps/dokploy/templates/huly/index.ts @@ -0,0 +1,152 @@ +import { + type DomainSchema, + type Schema, + type Template, + generateBase64, + generateRandomDomain, +} from "../utils"; + +export function generate(schema: Schema): Template { + const mainDomain = generateRandomDomain(schema); + const hulySecret = generateBase64(64); + const domains: DomainSchema[] = [ + { + host: generateRandomDomain(schema), + port: 80, + serviceName: "nginx", + }, + ]; + + const envs = [ + "HULY_VERSION=v0.6.377", + "DOCKER_NAME=huly", + "", + "# The address of the host or server from which you will access your Huly instance.", + "# This can be a domain name (e.g., huly.example.com) or an IP address (e.g., 192.168.1.1).", + `HOST_ADDRESS=${mainDomain}`, + "", + "# Set this variable to 'true' to enable SSL (HTTPS/WSS). ", + "# Leave it empty to use non-SSL (HTTP/WS).", + "SECURE=", + "", + "# Specify the IP address to bind to; leave blank to bind to all interfaces (0.0.0.0).", + "# Do not use IP:PORT format in HTTP_BIND or HTTP_PORT.", + "HTTP_PORT=80", + "HTTP_BIND=", + "", + "# Huly specific variables", + "TITLE=Huly", + "DEFAULT_LANGUAGE=en", + "LAST_NAME_FIRST=true", + "", + "# The following configs are auto-generated by the setup script. ", + "# Please do not manually overwrite.", + "", + "# Run with --secret to regenerate.", + `SECRET=${hulySecret}`, + ]; + + const mounts: Template["mounts"] = [ + { + filePath: "/volumes/nginx/.huly.nginx", + content: `server { + listen 80; + server_name _; + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://front:8080; + } + + location /_accounts { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + rewrite ^/_accounts(/.*)$ $1 break; + proxy_pass http://account:3000/; + } + + #location /_love { + # proxy_set_header Host $host; + # proxy_set_header X-Real-IP $remote_addr; + # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # proxy_set_header X-Forwarded-Proto $scheme; + + # proxy_http_version 1.1; + # proxy_set_header Upgrade $http_upgrade; + # proxy_set_header Connection "upgrade"; + # rewrite ^/_love(/.*)$ $1 break; + # proxy_pass http://love:8096/; + #} + + location /_collaborator { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + rewrite ^/_collaborator(/.*)$ $1 break; + proxy_pass http://collaborator:3078/; + } + + location /_transactor { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + rewrite ^/_transactor(/.*)$ $1 break; + proxy_pass http://transactor:3333/; + } + + location ~ ^/eyJ { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_pass http://transactor:3333; + } + + location /_rekoni { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + rewrite ^/_rekoni(/.*)$ $1 break; + proxy_pass http://rekoni:4004/; + } + + location /_stats { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + rewrite ^/_stats(/.*)$ $1 break; + proxy_pass http://stats:4900/; + } +}`, + }, + ]; + + return { + domains, + envs, + mounts, + }; +} diff --git a/apps/dokploy/templates/templates.ts b/apps/dokploy/templates/templates.ts index 86aa9ae8..5c8b6c8f 100644 --- a/apps/dokploy/templates/templates.ts +++ b/apps/dokploy/templates/templates.ts @@ -1062,4 +1062,19 @@ export const templates: TemplateData[] = [ tags: ["identity", "auth"], load: () => import("./logto/index").then((m) => m.generate), }, + { + id: "huly", + name: "Huly", + version: "0.6.377", + description: + "Huly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)", + logo: "huly.svg", + links: { + github: "https://github.com/hcengineering/huly-selfhost", + website: "https://huly.io/", + docs: "https://docs.huly.io/", + }, + tags: ["project-management", "community", "discussion"], + load: () => import("./huly/index").then((m) => m.generate), + }, ];