#!/usr/bin/env bash # Copyright (c) 2021-2025 community-scripts ORG # Author: GitHub Copilot # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://github.com/hcengineering/huly-selfhost source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" color verb_ip6 catch_errors setting_up_container network_check update_os msg_info "Installing Dependencies" $STD apt-get update $STD apt-get install -y curl git ca-certificates gnupg nginx lsb-release msg_ok "Installed Dependencies" msg_info "Installing MongoDB" # Install MongoDB natively $STD curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg --dearmor -o /etc/apt/keyrings/mongodb-server-7.0.gpg $STD echo "deb [ arch=amd64,arm64 signed-by=/etc/apt/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/debian $(lsb_release -cs)/mongodb-org/7.0 main" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list $STD apt-get update $STD apt-get install -y mongodb-org $STD systemctl enable --now mongod msg_ok "Installed MongoDB" msg_info "Installing Node.js" # Install Node.js for running Huly services NODE_VERSION=20 install_node_and_modules $STD npm install -g web-push msg_ok "Installed Node.js" msg_info "Installing Docker temporarily (for extraction)" # We need Docker temporarily to extract Huly applications $STD mkdir -p /etc/apt/keyrings $STD curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg $STD echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list >/dev/null $STD apt-get update $STD apt-get install -y docker-ce docker-ce-cli containerd.io $STD systemctl start docker msg_ok "Installed Docker temporarily" msg_info "Configuring native Huly setup" # Get server IP SERVER_IP=$(hostname -I | awk '{print $1}') # Generate VAPID keys for push notifications VAPID_OUTPUT=$(web-push generate-vapid-keys) PUBLIC_KEY=$(echo "$VAPID_OUTPUT" | grep "Public Key:" | cut -d ":" -f2 | tr -d ' ') PRIVATE_KEY=$(echo "$VAPID_OUTPUT" | grep "Private Key:" | cut -d ":" -f2 | tr -d ' ') # Create MongoDB database and user for Huly $STD mongosh --eval " use huly; db.createUser({ user: 'huly', pwd: 'hulypassword123', roles: [{role: 'readWrite', db: 'huly'}] }); " # Save configuration and VAPID keys mkdir -p /opt/huly-selfhost { echo "# Huly Native Configuration" echo "SERVER_IP=$SERVER_IP" echo "MONGO_URL=mongodb://huly:hulypassword123@localhost:27017/huly" echo "MINIO_ENDPOINT=localhost:9000" echo "MINIO_ACCESS_KEY=minioadmin" echo "MINIO_SECRET_KEY=minioadmin" echo "" echo "# VAPID Keys for Push Notifications" echo "VAPID_PUBLIC_KEY=$PUBLIC_KEY" echo "VAPID_PRIVATE_KEY=$PRIVATE_KEY" echo "" echo "# Service Ports" echo "FRONT_PORT=3000" echo "ACCOUNT_PORT=3001" echo "TRANSACTOR_PORT=3002" echo "COLLABORATOR_PORT=3078" echo "REKONI_PORT=4004" } >/opt/huly-selfhost/native.conf msg_ok "Configured Huly" msg_info "Extracting Huly applications from Docker images" # Create directories for Huly components mkdir -p /opt/huly/{front,account,transactor,collaborator,rekoni,elastic,minio} # Extract Frontend $STD docker create --name huly-front hardcoreeng/front:latest $STD docker cp huly-front:/usr/src/app/. /opt/huly/front/ $STD docker rm huly-front # Extract Account Service $STD docker create --name huly-account hardcoreeng/account:latest $STD docker cp huly-account:/usr/src/app/. /opt/huly/account/ $STD docker rm huly-account # Extract Transactor $STD docker create --name huly-transactor hardcoreeng/transactor:latest $STD docker cp huly-transactor:/usr/src/app/. /opt/huly/transactor/ $STD docker rm huly-transactor # Extract Collaborator (for document collaboration) $STD docker create --name huly-collaborator hardcoreeng/collaborator:latest $STD docker cp huly-collaborator:/usr/src/app/. /opt/huly/collaborator/ $STD docker rm huly-collaborator # Extract Rekoni (for file indexing) $STD docker create --name huly-rekoni hardcoreeng/rekoni:latest $STD docker cp huly-rekoni:/usr/src/app/. /opt/huly/rekoni/ $STD docker rm huly-rekoni msg_ok "Extracted Huly applications" msg_info "Installing MinIO for object storage" # Download MinIO binary MINIO_VERSION="RELEASE.2024-06-13T22-53-53Z" $STD curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/archive/minio.${MINIO_VERSION}" -o /usr/local/bin/minio $STD chmod +x /usr/local/bin/minio # Create MinIO user and directories useradd -r -s /bin/false minio || true mkdir -p /opt/minio/data /etc/minio chown -R minio:minio /opt/minio /etc/minio # Create MinIO configuration cat </etc/minio/minio.conf MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=minioadmin MINIO_VOLUMES="/opt/minio/data" MINIO_OPTS="--console-address :9001" EOF msg_ok "Installed MinIO" msg_info "Removing Docker" # Stop and remove Docker since we only needed it for extraction $STD systemctl stop docker $STD apt-get remove -y docker-ce docker-ce-cli containerd.io $STD rm -rf /var/lib/docker $STD rm -f /etc/apt/sources.list.d/docker.list /etc/apt/keyrings/docker.gpg msg_ok "Removed Docker" msg_info "Configuring nginx" # Remove default nginx site $STD rm -f /etc/nginx/sites-enabled/default # Create nginx configuration for native Huly cat </etc/nginx/sites-available/huly.conf server { listen 80 default_server; listen [::]:80 default_server; server_name _; # Frontend location / { proxy_pass http://127.0.0.1:3000; 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_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; } # Account service location /account/ { proxy_pass http://127.0.0.1:3001/; 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; } # MinIO (file storage) location /files/ { proxy_pass http://127.0.0.1:9000/; 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; } } EOF $STD ln -sf /etc/nginx/sites-available/huly.conf /etc/nginx/sites-enabled/huly.conf # Test and reload nginx if nginx -t >/dev/null 2>&1; then $STD nginx -s reload else msg_error "nginx configuration test failed" fi msg_ok "nginx configured" msg_info "Creating systemd services for Huly components" # MinIO service cat </etc/systemd/system/minio.service [Unit] Description=MinIO Object Storage Documentation=https://docs.min.io Wants=network-online.target After=network-online.target AssertFileIsExecutable=/usr/local/bin/minio [Service] WorkingDirectory=/opt/minio User=minio Group=minio EnvironmentFile=/etc/minio/minio.conf ExecStartPre=/bin/bash -c "if [ -z \"\${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/minio/minio.conf\"; exit 1; fi" ExecStart=/usr/local/bin/minio server \$MINIO_OPTS \$MINIO_VOLUMES Restart=always LimitNOFILE=65536 TasksMax=infinity TimeoutStopSec=infinity SendSIGKILL=no [Install] WantedBy=multi-user.target EOF # Frontend service cat </etc/systemd/system/huly-front.service [Unit] Description=Huly Frontend Service After=network.target [Service] Type=simple WorkingDirectory=/opt/huly/front ExecStart=/usr/bin/node dist/bundle.js Restart=always User=root Environment=PORT=3000 Environment=NODE_ENV=production Environment=ACCOUNTS_URL=http://localhost:3001 Environment=UPLOAD_URL=http://localhost:8086/files Environment=ELASTIC_URL=http://localhost:9200 Environment=GMAIL_URL=http://localhost:8087 Environment=CALENDAR_URL=http://localhost:8095 Environment=REKONI_URL=http://localhost:4004 [Install] WantedBy=multi-user.target EOF # Account service cat </etc/systemd/system/huly-account.service [Unit] Description=Huly Account Service After=network.target mongod.service Requires=mongod.service [Service] Type=simple WorkingDirectory=/opt/huly/account ExecStart=/usr/bin/node bundle.js Restart=always User=root Environment=PORT=3001 Environment=MONGO_URL=mongodb://huly:hulypassword123@localhost:27017/huly Environment=TRANSACTOR_URL=ws://localhost:3002 Environment=SECRET=secret [Install] WantedBy=multi-user.target EOF # Transactor service cat </etc/systemd/system/huly-transactor.service [Unit] Description=Huly Transactor Service After=network.target mongod.service minio.service Requires=mongod.service minio.service [Service] Type=simple WorkingDirectory=/opt/huly/transactor ExecStart=/usr/bin/node bundle.js Restart=always User=root Environment=PORT=3002 Environment=MONGO_URL=mongodb://huly:hulypassword123@localhost:27017/huly Environment=STORAGE_CONFIG=minio|minio?accessKey=minioadmin&secretKey=minioadmin Environment=SECRET=secret Environment=ACCOUNTS_URL=http://localhost:3001 Environment=REKONI_URL=http://localhost:4004 [Install] WantedBy=multi-user.target EOF # Collaborator service cat </etc/systemd/system/huly-collaborator.service [Unit] Description=Huly Collaborator Service After=network.target mongod.service Requires=mongod.service [Service] Type=simple WorkingDirectory=/opt/huly/collaborator ExecStart=/usr/bin/node dist/bundle.js Restart=always User=root Environment=PORT=3078 Environment=MONGO_URL=mongodb://huly:hulypassword123@localhost:27017/huly Environment=SECRET=secret [Install] WantedBy=multi-user.target EOF # Rekoni service (file processing) cat </etc/systemd/system/huly-rekoni.service [Unit] Description=Huly Rekoni Service After=network.target [Service] Type=simple WorkingDirectory=/opt/huly/rekoni ExecStart=/usr/bin/node bundle.js Restart=always User=root Environment=PORT=4004 Environment=SECRET=secret [Install] WantedBy=multi-user.target EOF # Enable and start all services systemctl daemon-reload systemctl enable --now minio huly-front huly-account huly-transactor huly-collaborator huly-rekoni msg_ok "Created and started Huly services" motd_ssh customize msg_info "Cleaning up" $STD apt-get -y autoremove $STD apt-get -y autoclean msg_ok "Cleaned" echo -e "${INFO}${YW} Huly native installation completed successfully!${CL}" echo -e "${INFO}${YW} Access URL: http://$SERVER_IP${CL}" echo -e "${INFO}${YW} Services may take a few minutes to fully start.${CL}" echo -e "" echo -e "${INFO}${YW} Service Status Commands:${CL}" echo -e "${INFO}${YW} • Check all services: systemctl status minio huly-front huly-account huly-transactor${CL}" echo -e "${INFO}${YW} • View frontend logs: journalctl -f -u huly-front${CL}" echo -e "${INFO}${YW} • View account logs: journalctl -f -u huly-account${CL}" echo -e "${INFO}${YW} • MinIO Console: http://$SERVER_IP:9001 (minioadmin/minioadmin)${CL}" echo -e "" echo -e "${INFO}${YW} Configuration saved to: /opt/huly-selfhost/native.conf${CL}" echo -e "${INFO}${YW} VAPID keys included in configuration for push notifications${CL}"