From 415d2dce94f96a6bb7d1dca0278fbfa07fa37ec6 Mon Sep 17 00:00:00 2001 From: "push-app-to-main[bot]" <203845782+push-app-to-main[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 13:20:07 +0000 Subject: [PATCH] Add safebucket (ct) --- ct/headers/safebucket | 6 + ct/safebucket.sh | 69 ++++++++++ install/safebucket-install.sh | 233 ++++++++++++++++++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 ct/headers/safebucket create mode 100644 ct/safebucket.sh create mode 100644 install/safebucket-install.sh diff --git a/ct/headers/safebucket b/ct/headers/safebucket new file mode 100644 index 000000000..b2864f67b --- /dev/null +++ b/ct/headers/safebucket @@ -0,0 +1,6 @@ + _____ ____ __ __ __ + / ___/____ _/ __/__ / /_ __ _______/ /_____ / /_ + \__ \/ __ `/ /_/ _ \/ __ \/ / / / ___/ //_/ _ \/ __/ + ___/ / /_/ / __/ __/ /_/ / /_/ / /__/ ,< / __/ /_ +/____/\__,_/_/ \___/_.___/\__,_/\___/_/|_|\___/\__/ + diff --git a/ct/safebucket.sh b/ct/safebucket.sh new file mode 100644 index 000000000..999e5bc99 --- /dev/null +++ b/ct/safebucket.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/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: renizmy +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/safebucket/safebucket + +APP="Safebucket" +var_tags="${var_tags:-files;sharing}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-1024}" +var_disk="${var_disk:-10}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +#var_arm64="${var_arm64:-no}" # unset = ask the user; set yes/no only when verified +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -f /opt/safebucket/safebucket ]]; then + msg_error "No ${APP} Installation Found!" + exit 1 + fi + + if check_for_gh_release "safebucket" "safebucket/safebucket"; then + local ARCH + ARCH=$(arch_resolve) + + msg_info "Stopping Service" + systemctl stop safebucket + msg_ok "Stopped Service" + + create_backup /opt/safebucket/config.yaml /opt/safebucket/data/ + + fetch_and_deploy_gh_release "safebucket" "safebucket/safebucket" "singlefile" "latest" "/opt/safebucket" "safebucket-linux-${ARCH}" + + restore_backup + + msg_info "Configuring Safebucket" + chown -R safebucket:safebucket /opt/safebucket + msg_ok "Configured Safebucket" + + msg_info "Starting Service" + systemctl start safebucket + msg_ok "Started Service" + msg_ok "Updated successfully!" + fi + cleanup_lxc + 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 "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}" diff --git a/install/safebucket-install.sh b/install/safebucket-install.sh new file mode 100644 index 000000000..471230bbf --- /dev/null +++ b/install/safebucket-install.sh @@ -0,0 +1,233 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: renizmy +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/safebucket/safebucket + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +ARCH=$(arch_resolve) +GARAGE_ARCH=$(arch_resolve "x86_64-unknown-linux-musl" "aarch64-unknown-linux-musl") + +msg_info "Installing Dependencies" +$STD apt install -y \ + awscli +msg_ok "Installed Dependencies" + +msg_info "Installing Garage" +useradd --system --no-create-home --shell /usr/sbin/nologin garage 2>/dev/null || true +GARAGE_VERSION=$(curl -fsSL https://api.github.com/repos/deuxfleurs-org/garage/tags | + jq -r '.[].name | select(test("^v[0-9]+\\.[0-9]+\\.[0-9]+$"))' | sort -V | tail -n1) +if [[ -z "$GARAGE_VERSION" ]]; then + msg_error "Could not determine latest stable Garage version" + exit 1 +fi +curl -fsSL "https://garagehq.deuxfleurs.fr/_releases/${GARAGE_VERSION}/${GARAGE_ARCH}/garage" -o /usr/local/bin/garage +chmod +x /usr/local/bin/garage +mkdir -p /opt/garage/{data,meta} +RPC_SECRET=$(openssl rand -hex 32) +ADMIN_TOKEN=$(openssl rand -base64 32) +cat </opt/garage/garage.toml +metadata_dir = "/opt/garage/meta" +data_dir = "/opt/garage/data" +db_engine = "lmdb" +replication_factor = 1 + +rpc_bind_addr = "[::]:3901" +rpc_public_addr = "127.0.0.1:3901" +rpc_secret = "${RPC_SECRET}" + +[s3_api] +s3_region = "garage" +api_bind_addr = "[::]:3900" +root_domain = ".s3.garage.localhost" + +[admin] +api_bind_addr = "[::]:3903" +admin_token = "${ADMIN_TOKEN}" +EOF +chmod 600 /opt/garage/garage.toml +chown -R garage:garage /opt/garage +cat </etc/systemd/system/garage.service +[Unit] +Description=Garage Object Storage +After=network.target + +[Service] +Type=simple +User=garage +Group=garage +WorkingDirectory=/opt/garage +ExecStart=/usr/local/bin/garage -c /opt/garage/garage.toml server +Restart=on-failure +RestartSec=5 +LimitNOFILE=65536 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now garage +msg_ok "Installed Garage" + +msg_info "Configuring Garage Bucket" +RETRIES=0 +until garage -c /opt/garage/garage.toml status &>/dev/null; do + RETRIES=$((RETRIES + 1)) + if [[ $RETRIES -ge 60 ]]; then + msg_error "Garage did not become ready within 60 seconds" + exit 1 + fi + sleep 1 +done +NODE_ID=$(garage -c /opt/garage/garage.toml status 2>/dev/null | awk '/^[0-9a-f]/{print $1; exit}') +if [[ -z "$NODE_ID" ]]; then + msg_error "Could not determine Garage node ID from cluster status" + exit 1 +fi +GARAGE_CAPACITY="${GARAGE_CAPACITY:-$(df -BG --output=avail /opt/garage | awk 'NR==2{gsub(/G/,"",$1); v=$1-1; print (v<1?1:v)"G"}')}" +$STD garage -c /opt/garage/garage.toml layout assign -z dc1 -c "${GARAGE_CAPACITY}" "${NODE_ID}" +$STD garage -c /opt/garage/garage.toml layout apply --version 1 +GARAGE_KEY_INFO=$(garage -c /opt/garage/garage.toml key create safebucket-key) +GARAGE_ACCESS_KEY=$(echo "$GARAGE_KEY_INFO" | awk '/Key ID:/{print $3}') +GARAGE_SECRET_KEY=$(echo "$GARAGE_KEY_INFO" | awk '/Secret key:/{print $3}') +$STD garage -c /opt/garage/garage.toml bucket create safebucket +$STD garage -c /opt/garage/garage.toml bucket allow --read --write --owner safebucket --key safebucket-key +msg_ok "Configured Garage Bucket" + +msg_info "Applying CORS Policy to Bucket" +export AWS_ACCESS_KEY_ID="${GARAGE_ACCESS_KEY}" +export AWS_SECRET_ACCESS_KEY="${GARAGE_SECRET_KEY}" +export AWS_DEFAULT_REGION="garage" +if aws s3api put-bucket-cors \ + --bucket safebucket \ + --endpoint-url "http://127.0.0.1:3900" \ + --cors-configuration '{"CORSRules":[{"AllowedHeaders":["*"],"AllowedMethods":["GET","PUT","POST","DELETE","HEAD"],"AllowedOrigins":["http://'"${LOCAL_IP}"':8080"],"ExposeHeaders":["ETag"]}]}' &>/dev/null; then + msg_ok "Applied CORS Policy to Bucket" +else + msg_warn "Could not apply CORS policy automatically; direct browser uploads may fail until CORS is configured manually" +fi +unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION + +msg_info "Installing Safebucket" +fetch_and_deploy_gh_release "safebucket" "safebucket/safebucket" "singlefile" "latest" "/opt/safebucket" "safebucket-linux-${ARCH}" +msg_ok "Installed Safebucket" + +msg_info "Configuring Safebucket" +useradd --system --no-create-home --shell /usr/sbin/nologin safebucket 2>/dev/null || true +mkdir -p /opt/safebucket/data/{notifications,activity} +TOKEN_SECRET=$(openssl rand -base64 32) +MFA_KEY=$(openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | cut -c1-32) +ADMIN_PASSWORD=$(openssl rand -hex 12) +cat </opt/safebucket/config.yaml +app: + profile: default + log_level: info + api_url: http://${LOCAL_IP}:8080 + web_url: http://${LOCAL_IP}:8080 + allowed_origins: + - http://${LOCAL_IP}:8080 + port: 8080 + token_secret: "${TOKEN_SECRET}" + mfa_encryption_key: "${MFA_KEY}" + mfa_required: false + admin_email: admin@safebucket.io + admin_password: "${ADMIN_PASSWORD}" + trash_retention_days: 7 + max_upload_size: 5368709120 + trusted_proxies: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + - 127.0.0.0/8 + - ::1/128 + - fc00::/7 + static_files: + enabled: true + +database: + type: sqlite + sqlite: + path: /opt/safebucket/data/safebucket.db + +cache: + type: memory + +storage: + type: s3 + s3: + bucket_name: safebucket + endpoint: 127.0.0.1:3900 + external_endpoint: http://${LOCAL_IP}:3900 + access_key: ${GARAGE_ACCESS_KEY} + secret_key: ${GARAGE_SECRET_KEY} + region: garage + force_path_style: true + use_tls: false + +events: + type: memory + queues: + notifications: + name: safebucket-notifications + object_deletion: + name: safebucket-object-deletion + bucket_events: + name: safebucket-bucket-events + +notifier: + type: filesystem + filesystem: + directory: /opt/safebucket/data/notifications + +activity: + type: filesystem + filesystem: + directory: /opt/safebucket/data/activity + +auth: + providers: + local: + name: local + type: local + sharing: + allowed: true + domains: [] +EOF +chmod 600 /opt/safebucket/config.yaml +chown -R safebucket:safebucket /opt/safebucket +msg_ok "Configured Safebucket" + +msg_info "Creating Service" +cat </etc/systemd/system/safebucket.service +[Unit] +Description=Safebucket File Sharing Platform +After=network-online.target garage.service +Wants=network-online.target +Requires=garage.service + +[Service] +Type=simple +User=safebucket +Group=safebucket +WorkingDirectory=/opt/safebucket +Environment=CONFIG_FILE_PATH=/opt/safebucket/config.yaml +ExecStart=/opt/safebucket/safebucket +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now safebucket +msg_ok "Created Service" + +motd_ssh +customize +cleanup_lxc