diff --git a/ct/glkvmcloud.sh b/ct/glkvmcloud.sh new file mode 100644 index 0000000000..9c5042dc30 --- /dev/null +++ b/ct/glkvmcloud.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env bash +_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/DevScripts/main" +_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func" +source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func") +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Romualdo Alcantara (romualdoag) +# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE +# Source: https://github.com/gl-inet/glkvm-cloud + +APP="GLKVM Cloud" +var_tags="${var_tags:-kvm;remote-access}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_arm64="${var_arm64:-yes}" +var_unprivileged="${var_unprivileged:-1}" + +export var_rttys_admin_name="${var_rttys_admin_name:-}" +export var_rttys_pass="${var_rttys_pass:-}" +export var_glkvm_access_ip="${var_glkvm_access_ip:-}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/glkvm-cloud ]]; then + msg_error "No GLKVM Cloud Installation Found!" + exit + fi + + if check_for_gh_tag "glkvm-cloud" "gl-inet/glkvm-cloud"; then + msg_info "Stopping Services" + systemctl stop glkvm-cloud glkvm-coturn + msg_ok "Stopped Services" + + CLEAN_INSTALL=1 fetch_and_deploy_gh_tag "glkvm-cloud" "gl-inet/glkvm-cloud" + + GO_VERSION="$(grep -m1 '^go ' /opt/glkvm-cloud/go.mod | awk '{print $2}')" setup_go + NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs + + msg_info "Building GLKVM Cloud interface" + cd /opt/glkvm-cloud/ui + $STD yarn install --frozen-lockfile + $STD yarn build + msg_ok "Built GLKVM Cloud interface" + + msg_info "Building GLKVM Cloud service" + cd /opt/glkvm-cloud + CGO_ENABLED=0 $STD go build -ldflags "-s -w" -o /opt/glkvm-cloud/rttys ./cmd/glkvm-cloud + rm -rf /opt/glkvm-cloud/ui/node_modules + $STD go clean -cache -modcache + msg_ok "Built GLKVM Cloud service" + + msg_info "Updating configuration" + if [[ ! -f /opt/glkvm-cloud-data/database/schema.sql ]]; then + cp /opt/glkvm-cloud/internal/store/sqlite/schema.sql /opt/glkvm-cloud-data/database/schema.sql + fi + source /opt/glkvm-cloud-data/.env + cat </etc/systemd/system/glkvm-cloud.service +[Unit] +Description=GLKVM Cloud +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/glkvm-cloud +Environment=RTTYS_CONF=/opt/glkvm-cloud-data/rttys.conf +EnvironmentFile=/opt/glkvm-cloud-data/.env +ExecStart=/opt/glkvm-cloud/rttys +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF + systemctl daemon-reload + cat </opt/glkvm-cloud-data/rttys.conf +token: ${RTTYS_TOKEN} +password: ${RTTYS_PASS} +admin-name: ${RTTYS_ADMIN_NAME} +webrtc-ip: ${GLKVM_ACCESS_IP} +webrtc-port: ${TURN_PORT} +webrtc-username: ${TURN_USER} +webrtc-password: ${TURN_PASS} +addr-dev: :${RTTYS_DEVICE_PORT} +addr-dev-mtls: :${RTTYS_DEVICE_MTLS_PORT} +legacy-token-access: ${RTTYS_LEGACY_TOKEN_ACCESS} +addr-user: :${RTTYS_WEBUI_PORT} +addr-http-proxy: :${RTTYS_HTTP_PROXY_PORT} +ldap-enabled: ${LDAP_ENABLED} +ldap-server: ${LDAP_SERVER} +ldap-port: ${LDAP_PORT} +ldap-use-tls: ${LDAP_USE_TLS} +ldap-bind-dn: ${LDAP_BIND_DN} +ldap-base-dn: ${LDAP_BASE_DN} +ldap-user-filter: ${LDAP_USER_FILTER} +ldap-allowed-groups: ${LDAP_ALLOWED_GROUPS} +ldap-allowed-users: ${LDAP_ALLOWED_USERS} +ldap-admin-group: ${LDAP_ADMIN_GROUP} +ldap-admin-users: ${LDAP_ADMIN_USERS} +oidc-enabled: ${OIDC_ENABLED} +oidc-primary-login: ${OIDC_PRIMARY_LOGIN} +oidc-generic-issuer: ${OIDC_ISSUER} +oidc-generic-client-id: ${OIDC_CLIENT_ID} +oidc-generic-auth-url: ${OIDC_AUTH_URL} +oidc-generic-token-url: ${OIDC_TOKEN_URL} +oidc-generic-redirect-url: ${OIDC_REDIRECT_URL} +oidc-generic-scopes: ${OIDC_SCOPES} +oidc-generic-allowed-users: ${OIDC_ALLOWED_USERS} +oidc-generic-allowed-subs: ${OIDC_ALLOWED_SUBS} +oidc-generic-allowed-usernames: ${OIDC_ALLOWED_USERNAMES} +oidc-generic-allowed-groups: ${OIDC_ALLOWED_GROUPS} +oidc-admin-group: ${OIDC_ADMIN_GROUP} +oidc-admin-users: ${OIDC_ADMIN_USERS} +selfhost-webui-url: ${SELFHOST_WEBUI_URL} +device-access-host: ${DEVICE_ACCESS_HOST} +EOF + cat </opt/glkvm-cloud-data/turnserver.conf +listening-port=${TURN_PORT} +lt-cred-mech +user=${TURN_USER}:${TURN_PASS} +realm=glkvm +no-multicast-peers +no-tls +no-dtls +external-ip=${GLKVM_ACCESS_IP} +EOF + msg_ok "Updated configuration" + + msg_info "Starting Services" + systemctl disable --now coturn 2>/dev/null || true + systemctl start glkvm-cloud glkvm-coturn + msg_ok "Started Services" + msg_ok "Updated successfully!" + fi + exit +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW}Access it using the following URL:${CL}" +echo -e "${GATEWAY}${BGN}https://${IP}${CL}" +echo -e "${INFO}${YW}Admin password: RTTYS_PASS in /opt/glkvm-cloud-data/.env${CL}" diff --git a/install/glkvmcloud-install.sh b/install/glkvmcloud-install.sh new file mode 100644 index 0000000000..e84927c145 --- /dev/null +++ b/install/glkvmcloud-install.sh @@ -0,0 +1,211 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: Romualdo Alcantara (romualdoag) +# License: MIT | https://github.com/community-scripts/DevScripts/raw/main/LICENSE +# Source: https://github.com/gl-inet/glkvm-cloud + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + build-essential \ + ca-certificates \ + coturn \ + curl \ + git \ + openssl \ + python3 \ + sqlite3 +msg_ok "Installed Dependencies" + +fetch_and_deploy_gh_tag "glkvm-cloud" "gl-inet/glkvm-cloud" + +GO_VERSION="$(grep -m1 '^go ' /opt/glkvm-cloud/go.mod | awk '{print $2}')" setup_go +NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs + +msg_info "Building GLKVM Cloud interface" +cd /opt/glkvm-cloud/ui +$STD yarn install --frozen-lockfile +$STD yarn build +msg_ok "Built GLKVM Cloud interface" + +msg_info "Building GLKVM Cloud service" +cd /opt/glkvm-cloud +CGO_ENABLED=0 $STD go build -ldflags "-s -w" -o /opt/glkvm-cloud/rttys ./cmd/glkvm-cloud +rm -rf /opt/glkvm-cloud/ui/node_modules +$STD go clean -cache -modcache +msg_ok "Built GLKVM Cloud service" + +msg_info "Configuring GLKVM Cloud" +mkdir -p /opt/glkvm-cloud-data/database /opt/glkvm-cloud-data/certificate +if [[ ! -f /opt/glkvm-cloud-data/database/schema.sql ]]; then + cp /opt/glkvm-cloud/internal/store/sqlite/schema.sql /opt/glkvm-cloud-data/database/schema.sql +fi +var_rttys_admin_name="${var_rttys_admin_name:-admin}" +var_rttys_pass="${var_rttys_pass:-$(random_password 32)}" +var_glkvm_access_ip="${var_glkvm_access_ip:-$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null || echo "$LOCAL_IP")}" +cat </opt/glkvm-cloud-data/.env +GLKVM_ACCESS_IP=${var_glkvm_access_ip} +RTTYS_TOKEN=$(random_password 32) +RTTYS_PASS=${var_rttys_pass} +RTTYS_ADMIN_NAME=${var_rttys_admin_name} +RTTYS_DEVICE_PORT=5912 +RTTYS_DEVICE_MTLS_PORT=5915 +RTTYS_LEGACY_TOKEN_ACCESS=true +RTTYS_WEBUI_PORT=443 +RTTYS_HTTP_PROXY_PORT=10443 +TURN_PORT=3478 +TURN_USER=$(random_password 16) +TURN_PASS=$(random_password 32) +REVERSE_PROXY_ENABLED=false +DEVICE_ACCESS_HOST= +SELFHOST_WEBUI_URL= +DEVICE_ENDPOINT_HOST= +WEB_UI_HOST= +LDAP_ENABLED=false +LDAP_SERVER= +LDAP_PORT=389 +LDAP_USE_TLS=false +LDAP_BIND_DN= +LDAP_BIND_PASSWORD= +LDAP_BASE_DN= +LDAP_USER_FILTER="(uid=%s)" +LDAP_ALLOWED_GROUPS= +LDAP_ALLOWED_USERS= +LDAP_ADMIN_GROUP= +LDAP_ADMIN_USERS= +OIDC_ENABLED=false +OIDC_PRIMARY_LOGIN=false +OIDC_ISSUER= +OIDC_CLIENT_ID= +OIDC_CLIENT_SECRET= +OIDC_AUTH_URL= +OIDC_TOKEN_URL= +OIDC_REDIRECT_URL= +OIDC_SCOPES="openid profile email" +OIDC_ALLOWED_USERS= +OIDC_ALLOWED_SUBS= +OIDC_ALLOWED_USERNAMES= +OIDC_ALLOWED_GROUPS= +OIDC_ADMIN_GROUP= +OIDC_ADMIN_USERS= +EOF +chmod 600 /opt/glkvm-cloud-data/.env +source /opt/glkvm-cloud-data/.env +cat </opt/glkvm-cloud-data/rttys.conf +token: ${RTTYS_TOKEN} +password: ${RTTYS_PASS} +admin-name: ${RTTYS_ADMIN_NAME} +webrtc-ip: ${GLKVM_ACCESS_IP} +webrtc-port: ${TURN_PORT} +webrtc-username: ${TURN_USER} +webrtc-password: ${TURN_PASS} +addr-dev: :${RTTYS_DEVICE_PORT} +addr-dev-mtls: :${RTTYS_DEVICE_MTLS_PORT} +legacy-token-access: ${RTTYS_LEGACY_TOKEN_ACCESS} +addr-user: :${RTTYS_WEBUI_PORT} +addr-http-proxy: :${RTTYS_HTTP_PROXY_PORT} +ldap-enabled: ${LDAP_ENABLED} +ldap-server: ${LDAP_SERVER} +ldap-port: ${LDAP_PORT} +ldap-use-tls: ${LDAP_USE_TLS} +ldap-bind-dn: ${LDAP_BIND_DN} +ldap-base-dn: ${LDAP_BASE_DN} +ldap-user-filter: ${LDAP_USER_FILTER} +ldap-allowed-groups: ${LDAP_ALLOWED_GROUPS} +ldap-allowed-users: ${LDAP_ALLOWED_USERS} +ldap-admin-group: ${LDAP_ADMIN_GROUP} +ldap-admin-users: ${LDAP_ADMIN_USERS} +oidc-enabled: ${OIDC_ENABLED} +oidc-primary-login: ${OIDC_PRIMARY_LOGIN} +oidc-generic-issuer: ${OIDC_ISSUER} +oidc-generic-client-id: ${OIDC_CLIENT_ID} +oidc-generic-auth-url: ${OIDC_AUTH_URL} +oidc-generic-token-url: ${OIDC_TOKEN_URL} +oidc-generic-redirect-url: ${OIDC_REDIRECT_URL} +oidc-generic-scopes: ${OIDC_SCOPES} +oidc-generic-allowed-users: ${OIDC_ALLOWED_USERS} +oidc-generic-allowed-subs: ${OIDC_ALLOWED_SUBS} +oidc-generic-allowed-usernames: ${OIDC_ALLOWED_USERNAMES} +oidc-generic-allowed-groups: ${OIDC_ALLOWED_GROUPS} +oidc-admin-group: ${OIDC_ADMIN_GROUP} +oidc-admin-users: ${OIDC_ADMIN_USERS} +selfhost-webui-url: ${SELFHOST_WEBUI_URL} +device-access-host: ${DEVICE_ACCESS_HOST} +EOF +cat </opt/glkvm-cloud-data/turnserver.conf +listening-port=${TURN_PORT} +lt-cred-mech +user=${TURN_USER}:${TURN_PASS} +realm=glkvm +no-multicast-peers +no-tls +no-dtls +external-ip=${GLKVM_ACCESS_IP} +EOF +ln -sfn /opt/glkvm-cloud-data/database /home/database +ln -sfn /opt/glkvm-cloud-data/certificate /home/certificate +msg_ok "Configured GLKVM Cloud" + +msg_info "Creating Services" +cat </etc/systemd/system/glkvm-cloud.service +[Unit] +Description=GLKVM Cloud +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/glkvm-cloud +Environment=RTTYS_CONF=/opt/glkvm-cloud-data/rttys.conf +EnvironmentFile=/opt/glkvm-cloud-data/.env +ExecStart=/opt/glkvm-cloud/rttys +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +cat </etc/systemd/system/glkvm-coturn.service +[Unit] +Description=GLKVM Cloud TURN server +After=network.target + +[Service] +Type=simple +User=root +ExecStart=/usr/bin/turnserver -c /opt/glkvm-cloud-data/turnserver.conf +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl disable --now coturn 2>/dev/null || true +systemctl enable -q --now glkvm-cloud glkvm-coturn +msg_ok "Created Services" + +msg_info "Verifying GLKVM Cloud" +sleep 8 +if [[ "$(systemctl show glkvm-cloud -p SubState --value)" != "running" ]]; then + journalctl -u glkvm-cloud --no-pager -n 10 >&2 || true + msg_error "GLKVM Cloud failed to start" + exit 1 +fi +if [[ "$(systemctl show glkvm-coturn -p SubState --value)" != "running" ]]; then + journalctl -u glkvm-coturn --no-pager -n 10 >&2 || true + msg_error "GLKVM TURN server failed to start" + exit 1 +fi +msg_ok "Verified GLKVM Cloud" + +motd_ssh +customize +cleanup_lxc diff --git a/json/glkvmcloud.json b/json/glkvmcloud.json new file mode 100644 index 0000000000..f503ed3102 --- /dev/null +++ b/json/glkvmcloud.json @@ -0,0 +1,76 @@ +{ + "name": "GLKVM Cloud", + "slug": "glkvmcloud", + "categories": [ + 6 + ], + "date_created": "2026-11-14", + "type": "ct", + "platforms": ["pve"], + "updateable": true, + "privileged": false, + "architectures": [ + "amd64", + "arm64" + ], + "interface_port": 443, + "documentation": "https://github.com/gl-inet/glkvm-cloud", + "website": "https://github.com/gl-inet/glkvm-cloud", + "repository": "https://github.com/gl-inet/glkvm-cloud", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/glkvmcloud.webp", + "description": "GLKVM Cloud lets individuals and small businesses manage GL.iNet KVM devices remotely from their own server. It supports access-code onboarding, in-browser remote control, batch commands, and LDAP/OIDC sign-in, keeping data and bandwidth under your control.", + "install_methods": [ + { + "type": "default", + "script": "ct/glkvmcloud.sh", + "config_path": "/opt/glkvm-cloud-data/.env", + "resources": { + "cpu": 2, + "ram": 2048, + "hdd": 8, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": "admin", + "password": null + }, + "app_vars": [ + { + "name": "var_rttys_admin_name", + "label": "Admin Username", + "type": "text", + "default": "admin", + "help": "Letters and digits only" + }, + { + "name": "var_rttys_pass", + "label": "Admin Password", + "type": "password", + "secret": true, + "help": "Generated randomly when left empty" + }, + { + "name": "var_glkvm_access_ip", + "label": "Server Access IP", + "type": "text", + "help": "Public IP by default; set the internal IP when devices are on the local network" + } + ], + "notes": [ + { + "text": "Opening the platform by IP shows a browser certificate warning because GLKVM Cloud generates its own certificate on first start. Use your own domain and certificate to remove it.", + "type": "warning" + }, + { + "text": "The admin password is stored as RTTYS_PASS in /opt/glkvm-cloud-data/.env inside the container.", + "type": "info" + }, + { + "text": "Allow ports 443, 10443, 5915 and 3478 (TCP and UDP) toward the container. KVM devices need firmware v1.11.0 or later for access-code onboarding.", + "type": "info" + } + ] +}