trek: seed default admin, fix install and hooks

Seed a default admin account and harden the installer; update symlink behavior and LXC hook argument handling.

- Install: downgrade Node setup to 22, write ADMIN_EMAIL/ADMIN_PASSWORD into /opt/trek/server/.env for initial boot, chmod the file, wait for app health, then remove plaintext creds from the env and print the default admin credentials. Remove previous DB patching script and credentials file generation. Add health-check failure handling.
- ct/trek.sh: check for /opt/trek instead of ~/.trek, run npm ci without --production, and recreate server data/uploads by removing any existing dirs and creating explicit symlinks.
- Installer: mirror symlink strategy used in the container (rm then ln -s) and ensure generated ENCRYPTION_KEY note; add ADMIN_EMAIL default.
- json: set default username to admin@trek.local, update notes about seeded admin, ENCRYPTION_KEY storage, and APP_URL recommendation.
- tools/pve/lxc-prehook.sh: fix append_unique_line_in_ct to pass positional arguments into the bash -c snippet safely (avoid parent-shell expansion).

These changes ensure a reproducible default admin creation flow without leaving plaintext credentials, improve symlink handling, and fix a bug in the LXC prehook.
This commit is contained in:
CanbiZ (MickLesk)
2026-04-24 09:52:03 +02:00
parent f20af5295d
commit 89095f3d5d
6 changed files with 191 additions and 32 deletions

View File

@@ -24,7 +24,7 @@ function update_script() {
check_container_storage
check_container_resources
if [[ ! -f ~/.trek ]]; then
if [[ ! -d /opt/trek ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
@@ -53,13 +53,14 @@ function update_script() {
msg_info "Installing Server Dependencies"
cd /opt/trek/server
$STD npm ci --production
$STD npm ci
msg_ok "Installed Server Dependencies"
mv /opt/trek-data.bak /opt/trek/data
mv /opt/trek-uploads.bak /opt/trek/uploads
ln -sf /opt/trek/data /opt/trek/server/data
ln -sf /opt/trek/uploads /opt/trek/server/uploads
rm -rf /opt/trek/server/data /opt/trek/server/uploads
ln -s /opt/trek/data /opt/trek/server/data
ln -s /opt/trek/uploads /opt/trek/server/uploads
cp /opt/trek.env.bak /opt/trek/server/.env
rm -f /opt/trek.env.bak

View File

@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
$STD apt install -y build-essential
msg_ok "Installed Dependencies"
NODE_VERSION="24" setup_nodejs
NODE_VERSION="22" setup_nodejs
fetch_and_deploy_gh_release "trek" "mauriceboe/TREK" "tarball"
@@ -34,19 +34,24 @@ mkdir -p /opt/trek/server/public
cp -r /opt/trek/client/dist/* /opt/trek/server/public/
cp -r /opt/trek/client/public/fonts /opt/trek/server/public/fonts 2>/dev/null || true
mkdir -p /opt/trek/{data/logs,uploads/{files,covers,avatars,photos}}
ln -sf /opt/trek/data /opt/trek/server/data
ln -sf /opt/trek/uploads /opt/trek/server/uploads
rm -rf /opt/trek/server/data /opt/trek/server/uploads
ln -s /opt/trek/data /opt/trek/server/data
ln -s /opt/trek/uploads /opt/trek/server/uploads
ENCRYPTION_KEY=$(openssl rand -hex 32)
ADMIN_EMAIL="admin@trek.local"
ADMIN_PASSWORD=$(openssl rand -base64 18 | tr -dc 'A-Za-z0-9' | head -c 16)
cat <<EOF >/opt/trek/server/.env
NODE_ENV=production
PORT=3000
ENCRYPTION_KEY=${ENCRYPTION_KEY}
ADMIN_EMAIL=${ADMIN_EMAIL}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
COOKIE_SECURE=false
FORCE_HTTPS=false
LOG_LEVEL=info
TZ=UTC
EOF
chmod 600 /opt/trek/server/.env
msg_ok "Set up Server"
msg_info "Creating Service"
@@ -77,24 +82,16 @@ for i in $(seq 1 30); do
fi
sleep 1
done
cd /opt/trek/server
$STD node -e "
const Database = require('better-sqlite3');
const bcrypt = require('bcryptjs');
const db = new Database('./data/travel.db');
const hash = bcrypt.hashSync('${ADMIN_PASSWORD}', 12);
db.prepare('UPDATE users SET password_hash = ?, must_change_password = 0 WHERE email = ?').run(hash, 'admin@trek.local');
db.close();
"
{
echo ""
echo "TREK Admin Credentials"
echo "Email: admin@trek.local"
echo "Password: ${ADMIN_PASSWORD}"
echo ""
} >>~/trek.creds
if ! curl -sf http://localhost:3000/api/health >/dev/null 2>&1; then
msg_error "TREK failed to initialize"
exit
fi
sed -i '/^ADMIN_EMAIL=/d;/^ADMIN_PASSWORD=/d' /opt/trek/server/.env
msg_ok "TREK initialized"
msg_ok "Created Service"
echo -e "${INFO}${YW} Default Admin Account:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}Email: ${ADMIN_EMAIL}${CL}"
echo -e "${TAB}${GATEWAY}${BGN}Password: ${ADMIN_PASSWORD}${CL}"
motd_ssh
customize

View File

@@ -28,17 +28,21 @@
}
],
"default_credentials": {
"username": null,
"username": "admin@trek.local",
"password": null
},
"notes": [
{
"text": "The first user to register becomes the admin.",
"text": "A default admin account is seeded during setup with the email admin@trek.local.",
"type": "info"
},
{
"text": "ENCRYPTION_KEY is auto-generated during setup. See `/opt/trek/server/.env`.",
"text": "ENCRYPTION_KEY is auto-generated during setup and stored in `/opt/trek/server/.env`.",
"type": "info"
},
{
"text": "Set APP_URL in `/opt/trek/server/.env` if you plan to use OIDC or email-based features.",
"type": "info"
}
]
}
}

View File

@@ -0,0 +1,103 @@
#!/usr/bin/env bash
set -euo pipefail
# Quick homelab bootstrap for a single-node management VM
# - Installs K3s (if missing)
# - Installs Argo CD (optional)
# - Waits for core components to become ready
#
# Usage examples:
# sudo bash k3s-argocd-bootstrap.sh
# sudo INSTALL_ARGOCD=false bash k3s-argocd-bootstrap.sh
# sudo K3S_VERSION="v1.34.1+k3s1" bash k3s-argocd-bootstrap.sh
K3S_VERSION="${K3S_VERSION:-v1.34.1+k3s1}"
INSTALL_ARGOCD="${INSTALL_ARGOCD:-true}"
ARGOCD_NAMESPACE="${ARGOCD_NAMESPACE:-argocd}"
ARGOCD_MANIFEST_URL="${ARGOCD_MANIFEST_URL:-https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml}"
log() {
echo "[INFO] $*"
}
ok() {
echo "[OK] $*"
}
fail() {
echo "[ERROR] $*" >&2
exit 1
}
require_root() {
if [[ "${EUID}" -ne 0 ]]; then
fail "Run as root (sudo)."
fi
}
install_k3s_if_missing() {
if command -v k3s >/dev/null 2>&1; then
ok "K3s is already installed: $(k3s --version | head -n1)"
return
fi
log "Installing K3s (${K3S_VERSION})"
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION="${K3S_VERSION}" sh -
ln -sf /usr/local/bin/k3s /usr/local/bin/kubectl
ok "K3s installed"
}
wait_for_k3s() {
log "Waiting for K3s node readiness"
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
for _ in $(seq 1 90); do
if kubectl get nodes >/dev/null 2>&1; then
if kubectl get nodes --no-headers 2>/dev/null | grep -q " Ready "; then
ok "K3s node is Ready"
return
fi
fi
sleep 2
done
fail "K3s did not become Ready in time"
}
install_argocd() {
if [[ "${INSTALL_ARGOCD}" != "true" ]]; then
log "Skipping ArgoCD installation (INSTALL_ARGOCD=${INSTALL_ARGOCD})"
return
fi
log "Installing ArgoCD into namespace ${ARGOCD_NAMESPACE}"
kubectl create namespace "${ARGOCD_NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -
kubectl apply -n "${ARGOCD_NAMESPACE}" -f "${ARGOCD_MANIFEST_URL}"
log "Waiting for ArgoCD server deployment"
kubectl -n "${ARGOCD_NAMESPACE}" rollout status deploy/argocd-server --timeout=10m
ok "ArgoCD installed"
}
print_next_steps() {
echo
echo "---"
echo "KUBECONFIG path: /etc/rancher/k3s/k3s.yaml"
if [[ "${INSTALL_ARGOCD}" == "true" ]]; then
echo "ArgoCD initial admin secret:"
echo " kubectl -n ${ARGOCD_NAMESPACE} get secret argocd-initial-admin-secret -o jsonpath='{.data.password}' | base64 -d; echo"
echo "Port-forward UI:"
echo " kubectl -n ${ARGOCD_NAMESPACE} port-forward svc/argocd-server 8080:443"
fi
echo "Cluster check:"
echo " kubectl get nodes -o wide"
}
main() {
require_root
install_k3s_if_missing
wait_for_k3s
install_argocd
print_next_steps
}
main "$@"

View File

@@ -395,10 +395,12 @@ append_unique_line_in_ct() {
local target_file="$1"
local line="$2"
retry_pct_exec bash -c "
touch '$target_file'
grep -Fqx -- \"$line\" '$target_file' || echo \"$line\" >> '$target_file'
"
retry_pct_exec bash -c '
target_file="$1"
line="$2"
touch "$target_file"
grep -Fqx -- "$line" "$target_file" || echo "$line" >> "$target_file"
' _ "$target_file" "$line"
}
resolve_requested_packages() {

View File

@@ -23,6 +23,7 @@ METHOD=""
NSAPP="Debian 12 VM"
var_os="debian"
var_version="12"
INSTALL_ARGOCD_BOOTSTRAP="${INSTALL_ARGOCD_BOOTSTRAP:-1}"
THIN="discard=on,ssd=1,"
set -e
@@ -380,6 +381,57 @@ virt-customize -q -a "${FILE}" \
msg_ok "Added in Image K3s, Helm & k9s"
if [[ "$INSTALL_ARGOCD_BOOTSTRAP" == "1" ]]; then
msg_info "Add in Image ArgoCD Bootstrap"
virt-customize -q -a "${FILE}" \
--run-command 'mkdir -p /usr/local/sbin /etc/systemd/system /var/lib' \
--run-command 'cat <<"EOF" >/usr/local/sbin/bootstrap-argocd.sh
#!/usr/bin/env bash
set -euo pipefail
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
for _ in $(seq 1 120); do
if kubectl get nodes --no-headers 2>/dev/null | grep -q " Ready "; then
break
fi
sleep 2
done
if ! kubectl get nodes --no-headers 2>/dev/null | grep -q " Ready "; then
echo "K3s is not ready yet"
exit 1
fi
kubectl create namespace argocd --dry-run=client -o yaml | kubectl apply -f -
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl -n argocd rollout status deploy/argocd-server --timeout=10m
touch /var/lib/argocd-bootstrap.done
EOF' \
--run-command 'chmod +x /usr/local/sbin/bootstrap-argocd.sh' \
--run-command 'cat <<"EOF" >/etc/systemd/system/argocd-bootstrap.service
[Unit]
Description=ArgoCD Bootstrap
After=network-online.target k3s.service
Wants=network-online.target
ConditionPathExists=!/var/lib/argocd-bootstrap.done
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/bootstrap-argocd.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF' \
--run-command 'systemctl enable argocd-bootstrap.service' >/dev/null
msg_ok "Added in Image ArgoCD Bootstrap"
else
msg_info "Skipping ArgoCD Bootstrap (INSTALL_ARGOCD_BOOTSTRAP=$INSTALL_ARGOCD_BOOTSTRAP)"
fi
msg_ok "Created a Debian 12 VM ${CL}${BL}(${HN})"
if [ "$START_VM" == "yes" ]; then
msg_info "Starting Debian 12 VM"