updated scripts
This commit is contained in:
+44
-15
@@ -28,10 +28,8 @@ sudo ./docker-setup.sh \
|
||||
--cf-token "your-cloudflare-api-token" \
|
||||
--customer "customer-1"
|
||||
|
||||
# Hub mode — download pre-configured controller.yaml from Felhom Hub
|
||||
# Hub mode — one-liner: all infra settings (domain, email, CF tokens) come from Hub
|
||||
sudo ./docker-setup.sh \
|
||||
--domain example.com \
|
||||
--email admin@example.com \
|
||||
--hub-customer "customer-1" \
|
||||
--hub-password "retrieval-password-from-hub"
|
||||
```
|
||||
@@ -94,26 +92,33 @@ The script supports three mutually exclusive TLS modes:
|
||||
- Generates 10-year wildcard cert with custom CA
|
||||
- CA cert copied to user home for manual device import
|
||||
|
||||
### Hub download mode
|
||||
### Hub mode
|
||||
|
||||
When both `--hub-customer` and `--hub-password` are provided, the script downloads a
|
||||
pre-configured `controller.yaml` from the Felhom Hub instead of running the interactive wizard:
|
||||
pre-configured `controller.yaml` from the Felhom Hub **before any infra setup begins**,
|
||||
then extracts the stored values to auto-configure everything — no additional flags needed:
|
||||
|
||||
```
|
||||
GET https://hub.felhom.eu/api/v1/config/{customer_id}
|
||||
Header: X-Retrieval-Password: {password}
|
||||
```
|
||||
|
||||
On success:
|
||||
- Saves downloaded YAML as `controller.yaml` (permissions 600)
|
||||
- Extracts domain, email, CF tokens for use by subsequent setup steps (Traefik, Cloudflare Tunnel)
|
||||
- Skips the interactive wizard entirely
|
||||
The downloaded config is parsed early in the run and populates:
|
||||
|
||||
On failure:
|
||||
- Logs a warning with HTTP status code
|
||||
- Falls back to the interactive wizard
|
||||
| Extracted field | Used for |
|
||||
|-----------------|----------|
|
||||
| `customer.domain` | Traefik routing, TLS cert SANs, DNS display |
|
||||
| `customer.email` | Let's Encrypt ACME registration |
|
||||
| `infrastructure.cf_api_token` | Traefik DNS-01 TLS challenge |
|
||||
| `infrastructure.cf_tunnel_token` | Cloudflare Tunnel connector |
|
||||
|
||||
Hub credentials are created in the Hub web UI at `https://hub.felhom.eu/configs`.
|
||||
CLI flags always take precedence — passing `--domain` overrides the hub value.
|
||||
|
||||
On failure (wrong credentials, network error):
|
||||
- Script exits immediately with the HTTP status code and the failing URL
|
||||
- Nothing is installed
|
||||
|
||||
Hub credentials are found in the Hub web UI under the customer's **Credentials** section.
|
||||
|
||||
### Configuration wizard
|
||||
|
||||
@@ -220,8 +225,8 @@ sudo ./felhom-wipe.sh --level full --yes
|
||||
|-------|-----------------|
|
||||
| `soft` | Controller state files only: `settings.json`, `metrics.db`, `setup-state.json`, `update-state.json`, `session-data.json`, `snapshot-history.json` |
|
||||
| `controller` | Soft + all non-infra Docker containers, all Docker volumes (except `portainer_data`), all stack directories (skips protected stacks by default) |
|
||||
| `full` | `controller`-level cleanup + `felhom-data/` on all storage drives (appdata, backups). Also removes old-style `appdata/` and `backups/` directories for pre-v0.26.0 compatibility. Infra containers (including felhom-controller) are **preserved**; controller is restarted after cleanup. |
|
||||
| `nuclear` | Full + all infra containers (controller, traefik, cloudflared, portainer), DR markers (`.felhom-infra-backup/` on all drives), `docker system prune -af --volumes`, and all infra config directories (`/opt/docker/felhom-controller/`, `/opt/docker/traefik/`, `/opt/docker/cloudflared/`, `/opt/docker/stacks/`) |
|
||||
| `full` | `controller`-level cleanup + `felhom-data/` on all storage drives (appdata, backups). Also removes old-style `appdata/` and `backups/` directories for pre-v0.26.0 compatibility. Removes `/mnt/.felhom-scan/` (stale DR scan dir). Infra containers (including felhom-controller) are **preserved**; controller is restarted after cleanup. |
|
||||
| `nuclear` | Full + all infra containers (controller, traefik, cloudflared, portainer), DR markers (`.felhom-infra-backup/` on all drives), raw helper mounts (`/mnt/.felhom-raw/` — unmount bind+raw, strip fstab entries), `/mnt/.felhom-scan/`, `docker system prune -af --volumes`, and all infra config directories (`/opt/docker/felhom-controller/`, `/opt/docker/traefik/`, `/opt/docker/cloudflared/`, `/opt/docker/stacks/`) |
|
||||
|
||||
### CLI options
|
||||
|
||||
@@ -237,11 +242,35 @@ sudo ./felhom-wipe.sh --level full --yes
|
||||
- Reads registered storage paths from `settings.json`
|
||||
- Also scans `/mnt/*/` for `felhom-data/` or legacy `appdata/` directories not in the registry
|
||||
|
||||
### Raw helper mounts
|
||||
|
||||
The attach wizard creates a two-level mount structure for pre-formatted drives:
|
||||
|
||||
```
|
||||
/dev/sdb1 (physical partition)
|
||||
└─ /mnt/.felhom-raw/hdd_1/ ← raw mount (persists in fstab, backs the bind)
|
||||
└─ felhom_data/
|
||||
└─ /mnt/hdd_1/ ← bind mount (what apps actually use)
|
||||
```
|
||||
|
||||
Both `fstab` entries survive reboots. On `nuclear` wipe, the script:
|
||||
1. Unmounts bind mounts (e.g. `/mnt/hdd_1`) first
|
||||
2. Unmounts raw mounts (e.g. `/mnt/.felhom-raw/hdd_1`)
|
||||
3. Strips both `fstab` entries
|
||||
4. Removes the now-empty `/mnt/.felhom-raw/` directory
|
||||
|
||||
The physical data on the drive partition is **not touched** — only the mount point
|
||||
directories (empty after unmounting) are removed.
|
||||
|
||||
`/mnt/.felhom-scan/` is a separate ephemeral directory used only during the DR setup
|
||||
wizard to temporarily inspect drives. It is cleaned up from `full` level onwards.
|
||||
|
||||
### What is preserved
|
||||
|
||||
- OS and system files
|
||||
- Infrastructure containers and config (unless `nuclear`)
|
||||
- User files: `Dokumentumok/`, `media/`, other non-felhom directories on drives
|
||||
- Drive data — raw mounts are unmounted but partition contents are untouched
|
||||
- DR markers on drives (unless `nuclear`)
|
||||
|
||||
### Safety
|
||||
|
||||
+106
-21
@@ -144,6 +144,11 @@ CUSTOMER_ID=""
|
||||
CF_TUNNEL_TOKEN=""
|
||||
HUB_CUSTOMER=""
|
||||
HUB_PASSWORD=""
|
||||
HUB_CONFIG_TMP="" # path to downloaded hub config temp file (set by apply_hub_config)
|
||||
DOMAIN_FROM_CLI=false
|
||||
EMAIL_FROM_CLI=false
|
||||
CF_TOKEN_FROM_CLI=false
|
||||
CF_TUNNEL_FROM_CLI=false
|
||||
|
||||
# Directories
|
||||
DOCKER_DATA_DIR="/opt/docker"
|
||||
@@ -302,13 +307,13 @@ parse_args() {
|
||||
INTERFACE="$2"; shift 2 ;;
|
||||
--domain)
|
||||
require_arg "$1" "${2:-}"
|
||||
BASE_DOMAIN="$2"; shift 2 ;;
|
||||
BASE_DOMAIN="$2"; DOMAIN_FROM_CLI=true; shift 2 ;;
|
||||
--email)
|
||||
require_arg "$1" "${2:-}"
|
||||
ACME_EMAIL="$2"; shift 2 ;;
|
||||
ACME_EMAIL="$2"; EMAIL_FROM_CLI=true; shift 2 ;;
|
||||
--cf-token)
|
||||
require_arg "$1" "${2:-}"
|
||||
CF_DNS_API_TOKEN="$2"; shift 2 ;;
|
||||
CF_DNS_API_TOKEN="$2"; CF_TOKEN_FROM_CLI=true; shift 2 ;;
|
||||
--traefik-password)
|
||||
require_arg "$1" "${2:-}"
|
||||
TRAEFIK_PASSWORD="$2"; shift 2 ;;
|
||||
@@ -317,7 +322,7 @@ parse_args() {
|
||||
CUSTOMER_ID="$2"; shift 2 ;;
|
||||
--cf-tunnel-token)
|
||||
require_arg "$1" "${2:-}"
|
||||
CF_TUNNEL_TOKEN="$2"; shift 2 ;;
|
||||
CF_TUNNEL_TOKEN="$2"; CF_TUNNEL_FROM_CLI=true; shift 2 ;;
|
||||
--hub-customer)
|
||||
require_arg "$1" "${2:-}"
|
||||
HUB_CUSTOMER="$2"; shift 2 ;;
|
||||
@@ -1461,6 +1466,88 @@ EOF
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# YAML helper: extract a single string value from a section+key
|
||||
# Usage: yaml_get <file> <top-level-section> <key>
|
||||
# Handles both quoted ("value") and unquoted values.
|
||||
#-------------------------------------------------------------------------------
|
||||
yaml_get() {
|
||||
local file="$1" section="$2" key="$3"
|
||||
awk -v s="${section}:" -v k=" ${key}:" '
|
||||
/^[[:alpha:]]/ { in_s = ($0 == s) }
|
||||
in_s && index($0, k) == 1 {
|
||||
sub(/^[^:]*: */, ""); gsub(/^"|"$/, ""); print; exit
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Hub mode: download controller.yaml early and extract infra vars
|
||||
# Called from main() before Traefik/infra setup so BASE_DOMAIN etc. are ready.
|
||||
#-------------------------------------------------------------------------------
|
||||
apply_hub_config() {
|
||||
[[ -z "$HUB_CUSTOMER" ]] && return
|
||||
|
||||
log_info "Fetching configuration from Felhom Hub (customer: ${HUB_CUSTOMER})..."
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
echo -e "${CYAN}[DRY-RUN]${NC} Would fetch: https://hub.felhom.eu/api/v1/config/${HUB_CUSTOMER}"
|
||||
echo -e "${CYAN}[DRY-RUN]${NC} Would apply domain, email, CF tokens from hub config"
|
||||
# Set plausible placeholders so the plan display is meaningful
|
||||
[[ "$DOMAIN_FROM_CLI" == false ]] && BASE_DOMAIN="<hub-domain>"
|
||||
[[ "$EMAIL_FROM_CLI" == false ]] && ACME_EMAIL="<hub-email>"
|
||||
[[ "$CF_TOKEN_FROM_CLI" == false ]] && CF_DNS_API_TOKEN="<hub-cf-token>"
|
||||
[[ "$CF_TUNNEL_FROM_CLI" == false ]] && CF_TUNNEL_TOKEN="<hub-cf-tunnel-token>"
|
||||
return
|
||||
fi
|
||||
|
||||
HUB_CONFIG_TMP=$(mktemp /tmp/felhom-hub-config-XXXXXX.yaml)
|
||||
|
||||
local hub_url="https://hub.felhom.eu/api/v1/config/${HUB_CUSTOMER}"
|
||||
local http_code
|
||||
http_code=$(curl -fsSL \
|
||||
-H "X-Retrieval-Password: ${HUB_PASSWORD}" \
|
||||
-o "${HUB_CONFIG_TMP}" \
|
||||
-w "%{http_code}" \
|
||||
"${hub_url}" 2>&1) || true
|
||||
|
||||
if [[ "$http_code" != "200" ]]; then
|
||||
rm -f "${HUB_CONFIG_TMP}"
|
||||
HUB_CONFIG_TMP=""
|
||||
log_error "Failed to fetch config from Felhom Hub (HTTP ${http_code})"
|
||||
log_error "URL: ${hub_url}"
|
||||
log_error "Check the customer ID and retrieval password, then re-run."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Hub config fetched successfully"
|
||||
|
||||
# Extract values from hub YAML
|
||||
local hub_domain hub_email hub_cf_token hub_tunnel_token
|
||||
hub_domain=$(yaml_get "${HUB_CONFIG_TMP}" "customer" "domain")
|
||||
hub_email=$(yaml_get "${HUB_CONFIG_TMP}" "customer" "email")
|
||||
hub_cf_token=$(yaml_get "${HUB_CONFIG_TMP}" "infrastructure" "cf_api_token")
|
||||
hub_tunnel_token=$(yaml_get "${HUB_CONFIG_TMP}" "infrastructure" "cf_tunnel_token")
|
||||
|
||||
# Apply to script vars — CLI flags always take precedence
|
||||
if [[ "$DOMAIN_FROM_CLI" == false && -n "$hub_domain" ]]; then
|
||||
BASE_DOMAIN="$hub_domain"
|
||||
log_info " domain: ${BASE_DOMAIN} (from Hub)"
|
||||
fi
|
||||
if [[ "$EMAIL_FROM_CLI" == false && -n "$hub_email" ]]; then
|
||||
ACME_EMAIL="$hub_email"
|
||||
log_info " email: ${ACME_EMAIL} (from Hub)"
|
||||
fi
|
||||
if [[ "$CF_TOKEN_FROM_CLI" == false && -n "$hub_cf_token" ]]; then
|
||||
CF_DNS_API_TOKEN="$hub_cf_token"
|
||||
log_info " cf_api_token: ${CF_DNS_API_TOKEN:0:6}... (from Hub)"
|
||||
fi
|
||||
if [[ "$CF_TUNNEL_FROM_CLI" == false && -n "$hub_tunnel_token" ]]; then
|
||||
CF_TUNNEL_TOKEN="$hub_tunnel_token"
|
||||
log_info " cf_tunnel_token: ${CF_TUNNEL_TOKEN:0:6}... (from Hub)"
|
||||
fi
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Generate minimal controller.yaml — full configuration via web UI setup wizard
|
||||
#-------------------------------------------------------------------------------
|
||||
@@ -1474,30 +1561,24 @@ generate_minimal_config() {
|
||||
mkdir -p "${CONTROLLER_DIR}"
|
||||
|
||||
if [[ -n "$HUB_CUSTOMER" ]]; then
|
||||
log_step "${step_num}/$(get_total_steps) - Downloading controller.yaml from Felhom Hub..."
|
||||
log_step "${step_num}/$(get_total_steps) - Installing controller.yaml from Felhom Hub..."
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
echo -e "${CYAN}[DRY-RUN]${NC} Would download controller.yaml from https://hub.felhom.eu/api/v1/config/${HUB_CUSTOMER}"
|
||||
echo -e "${CYAN}[DRY-RUN]${NC} Would install hub controller.yaml to ${CONTROLLER_DIR}/controller.yaml"
|
||||
return
|
||||
fi
|
||||
|
||||
local hub_url="https://hub.felhom.eu/api/v1/config/${HUB_CUSTOMER}"
|
||||
local http_code
|
||||
http_code=$(curl -fsSL \
|
||||
-H "X-Retrieval-Password: ${HUB_PASSWORD}" \
|
||||
-o "${CONTROLLER_DIR}/controller.yaml" \
|
||||
-w "%{http_code}" \
|
||||
"${hub_url}" 2>&1) || true
|
||||
|
||||
if [[ "$http_code" == "200" ]]; then
|
||||
chmod 600 "${CONTROLLER_DIR}/controller.yaml"
|
||||
log_success "controller.yaml downloaded from Felhom Hub (customer: ${HUB_CUSTOMER})"
|
||||
# Config was already downloaded by apply_hub_config() early in main()
|
||||
if [[ -n "$HUB_CONFIG_TMP" && -f "$HUB_CONFIG_TMP" ]]; then
|
||||
mv "${HUB_CONFIG_TMP}" "${CONTROLLER_DIR}/controller.yaml"
|
||||
HUB_CONFIG_TMP=""
|
||||
else
|
||||
log_error "Failed to download controller.yaml from Hub (HTTP ${http_code})"
|
||||
log_error "URL: ${hub_url}"
|
||||
log_error "Check the customer ID and retrieval password, then re-run."
|
||||
log_error "Hub config temp file not found — apply_hub_config() may not have run"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod 600 "${CONTROLLER_DIR}/controller.yaml"
|
||||
log_success "controller.yaml installed from Felhom Hub (customer: ${HUB_CUSTOMER})"
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -1734,7 +1815,11 @@ main() {
|
||||
if [[ "$DEBUG_MODE" == true ]]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
|
||||
# Hub mode: download config early so BASE_DOMAIN, ACME_EMAIL, CF tokens are
|
||||
# available before Traefik and other infra steps run
|
||||
apply_hub_config
|
||||
|
||||
print_banner
|
||||
check_debian
|
||||
|
||||
|
||||
@@ -209,6 +209,16 @@ print_plan() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$LEVEL" == "full" || "$LEVEL" == "nuclear" ]]; then
|
||||
echo ""
|
||||
echo -e "${CYAN}Mount cleanup:${NC}"
|
||||
if [ -d /mnt/.felhom-scan ]; then
|
||||
echo -e " ${YELLOW}DELETE${NC} /mnt/.felhom-scan/ (stale scan dir)"
|
||||
else
|
||||
echo -e " ${GREEN}(no .felhom-scan dir)${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$LEVEL" == "full" || "$LEVEL" == "nuclear" ]]; then
|
||||
echo ""
|
||||
echo -e "${CYAN}Storage data:${NC}"
|
||||
@@ -239,6 +249,21 @@ print_plan() {
|
||||
echo -e " ${RED}DELETE${NC} Cloudflared container"
|
||||
echo -e " ${RED}DELETE${NC} Portainer container + volume"
|
||||
echo -e " ${RED}DELETE${NC} .felhom-infra-backup/ (DR markers on all drives)"
|
||||
if [ -d /mnt/.felhom-raw ]; then
|
||||
echo -e " ${RED}UNMOUNT+DELETE${NC} /mnt/.felhom-raw/ (raw helper mounts + fstab entries)"
|
||||
# Show each raw mount and its bind target
|
||||
for rmp in /mnt/.felhom-raw/*/; do
|
||||
[ -d "$rmp" ] || continue
|
||||
local label; label=$(basename "$rmp")
|
||||
local bind_target
|
||||
bind_target=$(grep -E "^/mnt/\.felhom-raw/${label}/" /etc/fstab 2>/dev/null | awk '{print $2}' | head -1 || true)
|
||||
if [ -n "$bind_target" ]; then
|
||||
echo -e " ${RED}umount${NC} ${bind_target} (bind) → ${rmp} (raw)"
|
||||
else
|
||||
echo -e " ${RED}umount${NC} ${rmp} (raw, no bind found)"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo -e " ${RED}DELETE${NC} All Docker data (docker system prune -af --volumes)"
|
||||
echo -e " ${RED}DELETE${NC} $COMPOSE_DIR/ (controller compose + .env)"
|
||||
local infra_root; infra_root=$(dirname "$COMPOSE_DIR")
|
||||
@@ -264,6 +289,57 @@ print_plan() {
|
||||
echo ""
|
||||
}
|
||||
|
||||
# --- Mount Cleanup Helpers ---
|
||||
|
||||
# cleanup_scan_dir: remove /mnt/.felhom-scan/ (ephemeral DR scan staging dir).
|
||||
# Always empty after normal operation; safe to rm -rf unconditionally.
|
||||
cleanup_scan_dir() {
|
||||
if [ -d /mnt/.felhom-scan ]; then
|
||||
rm -rf /mnt/.felhom-scan && info " Removed: /mnt/.felhom-scan/"
|
||||
fi
|
||||
}
|
||||
|
||||
# cleanup_raw_mounts: unmount bind mounts, unmount raw helper mounts, strip
|
||||
# /etc/fstab entries, then remove the now-empty /mnt/.felhom-raw/ directory.
|
||||
#
|
||||
# Raw mounts are created by the attach wizard (two-level: raw partition mount +
|
||||
# bind mount from subfolder). Both fstab entries must be removed so they don't
|
||||
# cause errors on next boot. Order: bind umount first, then raw umount.
|
||||
cleanup_raw_mounts() {
|
||||
[ -d /mnt/.felhom-raw ] || return
|
||||
|
||||
info "Cleaning up raw helper mounts (/mnt/.felhom-raw/)..."
|
||||
|
||||
# 1. Unmount bind mounts whose source is inside .felhom-raw (field 1 matches)
|
||||
if [ -f /etc/fstab ]; then
|
||||
local bind_targets
|
||||
bind_targets=$(grep -E '^/mnt/\.felhom-raw/' /etc/fstab | awk '{print $2}' || true)
|
||||
for mp in $bind_targets; do
|
||||
if mountpoint -q "$mp" 2>/dev/null; then
|
||||
umount -l "$mp" 2>/dev/null && info " Unmounted bind: $mp" \
|
||||
|| warn " Could not unmount bind: $mp"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 2. Unmount raw partition mounts (field 2 matches /mnt/.felhom-raw/*)
|
||||
for mp in /mnt/.felhom-raw/*/; do
|
||||
[ -d "$mp" ] || continue
|
||||
if mountpoint -q "$mp" 2>/dev/null; then
|
||||
umount -l "$mp" 2>/dev/null && info " Unmounted raw: $mp" \
|
||||
|| warn " Could not unmount raw: $mp"
|
||||
fi
|
||||
done
|
||||
|
||||
# 3. Strip all .felhom-raw entries from fstab (both raw and bind lines)
|
||||
if [ -f /etc/fstab ] && grep -q '\.felhom-raw' /etc/fstab 2>/dev/null; then
|
||||
sed -i '\|\.felhom-raw|d' /etc/fstab && info " Removed .felhom-raw entries from /etc/fstab"
|
||||
fi
|
||||
|
||||
# 4. Remove directory — safe now that mounts are gone
|
||||
rm -rf /mnt/.felhom-raw && info " Removed: /mnt/.felhom-raw/"
|
||||
}
|
||||
|
||||
# --- Wipe Functions ---
|
||||
|
||||
do_soft_wipe() {
|
||||
@@ -336,6 +412,9 @@ do_full_wipe() {
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove stale scan dir (ephemeral DR staging — always safe to remove)
|
||||
cleanup_scan_dir
|
||||
|
||||
# Restart controller after all cleanup is done
|
||||
info "Restarting controller..."
|
||||
docker restart felhom-controller 2>/dev/null || warn "Could not restart controller"
|
||||
@@ -358,6 +437,10 @@ do_nuclear_wipe() {
|
||||
fi
|
||||
done
|
||||
|
||||
# Unmount raw helper mounts, strip fstab entries, remove dirs
|
||||
# (scan dir already removed by do_full_wipe above)
|
||||
cleanup_raw_mounts
|
||||
|
||||
# Remove all Docker data
|
||||
warn "Pruning all Docker data..."
|
||||
docker system prune -af --volumes 2>/dev/null || warn "Docker prune failed"
|
||||
|
||||
Reference in New Issue
Block a user