From 752d80e11cf7b9370bd13fcf7d615ec45d3aee9c Mon Sep 17 00:00:00 2001 From: xtcnet Date: Thu, 19 Mar 2026 14:38:22 +0700 Subject: [PATCH] Automate blog deploy user setup --- README.md | 1 + blog-starter/.forgejo/workflows/deploy.yml | 8 +- blog-starter/README.md | 3 +- install.sh | 103 +++++++++++++++++++-- 4 files changed, 106 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7e7d51d..331f368 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ A lightweight all-in-one Docker deployment that combines reverse proxy managemen - `blog-starter/` contains a ready-to-use Hugo + LoveIt starter - includes a Forgejo Actions workflow that deploys generated files to `/opt/blog/public` - intended to be used as the base of a separate blog repository +- `install.sh blog-deploy-info` prints the deploy user and the secret values needed by Forgejo Actions --- diff --git a/blog-starter/.forgejo/workflows/deploy.yml b/blog-starter/.forgejo/workflows/deploy.yml index d07b98d..2c97c14 100644 --- a/blog-starter/.forgejo/workflows/deploy.yml +++ b/blog-starter/.forgejo/workflows/deploy.yml @@ -62,7 +62,11 @@ jobs: test -n "$BLOG_DEPLOY_PORT" test -n "$BLOG_DEPLOY_USER" test -n "$BLOG_DEPLOY_PATH" - ssh -p "$BLOG_DEPLOY_PORT" "$BLOG_DEPLOY_USER@$BLOG_DEPLOY_HOST" "mkdir -p '$BLOG_DEPLOY_PATH/public'" + SSH_OPTS="-p $BLOG_DEPLOY_PORT" + if [ ! -f ~/.ssh/known_hosts ]; then + SSH_OPTS="$SSH_OPTS -o StrictHostKeyChecking=accept-new" + fi + ssh $SSH_OPTS "$BLOG_DEPLOY_USER@$BLOG_DEPLOY_HOST" "mkdir -p '$BLOG_DEPLOY_PATH/public'" rsync -az --delete \ - -e "ssh -p $BLOG_DEPLOY_PORT" \ + -e "ssh $SSH_OPTS" \ public/ "$BLOG_DEPLOY_USER@$BLOG_DEPLOY_HOST:$BLOG_DEPLOY_PATH/public/" diff --git a/blog-starter/README.md b/blog-starter/README.md index 31c0d73..fcecf7e 100644 --- a/blog-starter/README.md +++ b/blog-starter/README.md @@ -74,7 +74,8 @@ The workflow expects these repository secrets: - Blog host installed from this repo's `install.sh` - `d3v-blog` container running -- the deploy user can write to `/opt/blog/public` +- a deploy user created by `install.sh blog-install` or `install.sh blog-update` +- `install.sh blog-deploy-info` prints the exact secret values to paste into Forgejo - Nginx Proxy Manager forwards `blog.yourdomain.com` to `d3v-blog:80` ## Notes diff --git a/install.sh b/install.sh index 54b6b97..1e30c5e 100644 --- a/install.sh +++ b/install.sh @@ -16,6 +16,10 @@ BLOG_INSTALL_DIR="/opt/blog" BLOG_COMPOSE_FILE="${BLOG_INSTALL_DIR}/docker-compose.yml" BLOG_CONTAINER_NAME="d3v-blog" BLOG_IMAGE="nginx:alpine" +BLOG_DEPLOY_USER="blogdeploy" +BLOG_DEPLOY_KEY_DIR="${BLOG_INSTALL_DIR}/deploy-keys" +BLOG_DEPLOY_PRIVATE_KEY="${BLOG_DEPLOY_KEY_DIR}/id_ed25519" +BLOG_DEPLOY_PUBLIC_KEY="${BLOG_DEPLOY_KEY_DIR}/id_ed25519.pub" FORGEJO_INSTALL_DIR="/opt/forgejo" FORGEJO_COMPOSE_FILE="${FORGEJO_INSTALL_DIR}/docker-compose.yml" @@ -259,6 +263,86 @@ ensure_docker_network() { fi } +ensure_blog_deploy_user() { + log_step "Ensuring blog deploy user '${BLOG_DEPLOY_USER}' exists..." + if id -u "${BLOG_DEPLOY_USER}" > /dev/null 2>&1; then + log_ok "Deploy user '${BLOG_DEPLOY_USER}' already exists." + else + useradd --create-home --shell /bin/bash "${BLOG_DEPLOY_USER}" + log_ok "Deploy user '${BLOG_DEPLOY_USER}' created." + fi +} + +ensure_blog_deploy_paths() { + log_step "Preparing blog deploy paths..." + mkdir -p "${BLOG_INSTALL_DIR}/public" "${BLOG_DEPLOY_KEY_DIR}" + chown -R "${BLOG_DEPLOY_USER}:${BLOG_DEPLOY_USER}" "${BLOG_INSTALL_DIR}/public" + chmod 755 "${BLOG_INSTALL_DIR}" "${BLOG_INSTALL_DIR}/public" + chmod 700 "${BLOG_DEPLOY_KEY_DIR}" + log_ok "Blog deploy paths are ready." +} + +ensure_blog_deploy_keypair() { + ensure_blog_deploy_user + ensure_blog_deploy_paths + + if [ -f "${BLOG_DEPLOY_PRIVATE_KEY}" ] && [ -f "${BLOG_DEPLOY_PUBLIC_KEY}" ]; then + log_ok "Blog deploy keypair already exists." + else + log_step "Generating blog deploy SSH keypair..." + ssh-keygen -q -t ed25519 -C "blog-deploy@$(hostname)" -f "${BLOG_DEPLOY_PRIVATE_KEY}" -N "" + chmod 600 "${BLOG_DEPLOY_PRIVATE_KEY}" + chmod 644 "${BLOG_DEPLOY_PUBLIC_KEY}" + log_ok "Blog deploy keypair generated." + fi + + install -d -m 700 -o "${BLOG_DEPLOY_USER}" -g "${BLOG_DEPLOY_USER}" "/home/${BLOG_DEPLOY_USER}/.ssh" + touch "/home/${BLOG_DEPLOY_USER}/.ssh/authorized_keys" + grep -qxF "$(cat "${BLOG_DEPLOY_PUBLIC_KEY}")" "/home/${BLOG_DEPLOY_USER}/.ssh/authorized_keys" 2>/dev/null \ + || cat "${BLOG_DEPLOY_PUBLIC_KEY}" >> "/home/${BLOG_DEPLOY_USER}/.ssh/authorized_keys" + chown "${BLOG_DEPLOY_USER}:${BLOG_DEPLOY_USER}" "/home/${BLOG_DEPLOY_USER}/.ssh/authorized_keys" + chmod 600 "/home/${BLOG_DEPLOY_USER}/.ssh/authorized_keys" + log_ok "Blog deploy public key installed for ${BLOG_DEPLOY_USER}." +} + +get_ssh_port() { + local ssh_port + ssh_port=$(sshd -T 2>/dev/null | awk '/^port / {print $2; exit}') + echo "${ssh_port:-22}" +} + +show_blog_deploy_info() { + require_root + + if [ ! -d "$BLOG_INSTALL_DIR" ]; then + log_err "Blog is not installed. Install it first." + return + fi + + ensure_blog_deploy_keypair + + local deploy_host ssh_port + deploy_host=$(detect_public_ip) + ssh_port=$(get_ssh_port) + + separator + echo -e "${BOLD} Blog Deploy Information${NC}" + separator + echo -e " ${CYAN}BLOG_DEPLOY_HOST${NC} : ${BOLD}${deploy_host:-YOUR_SERVER_HOST}${NC}" + echo -e " ${CYAN}BLOG_DEPLOY_PORT${NC} : ${BOLD}${ssh_port}${NC}" + echo -e " ${CYAN}BLOG_DEPLOY_USER${NC} : ${BOLD}${BLOG_DEPLOY_USER}${NC}" + echo -e " ${CYAN}BLOG_DEPLOY_PATH${NC} : ${BOLD}${BLOG_INSTALL_DIR}${NC}" + echo "" + echo -e "${BOLD} BLOG_DEPLOY_KEY${NC}" + cat "${BLOG_DEPLOY_PRIVATE_KEY}" + echo "" + echo -e "${BOLD} Server Public Key Installed In authorized_keys${NC}" + cat "${BLOG_DEPLOY_PUBLIC_KEY}" + echo "" + echo -e " Add the private key above to your Forgejo repo secret ${BOLD}BLOG_DEPLOY_KEY${NC}." + separator +} + # ----------------------------------------------------------- # 2. Install Gateway # ----------------------------------------------------------- @@ -598,6 +682,7 @@ do_blog_install() { echo "" ensure_docker_network + ensure_blog_deploy_keypair log_step "Creating ${BLOG_INSTALL_DIR}..." mkdir -p "${BLOG_INSTALL_DIR}/public" @@ -680,9 +765,10 @@ YAML separator echo -e " ${CYAN}Container${NC} : ${BOLD}${BLOG_CONTAINER_NAME}${NC}" echo -e " ${CYAN}Content Dir${NC}: ${BOLD}${BLOG_INSTALL_DIR}/public${NC}" + echo -e " ${CYAN}Deploy User${NC}: ${BOLD}${BLOG_DEPLOY_USER}${NC}" echo "" echo -e " ${BOLD}Next steps${NC}" - echo -e " 1. Deploy your Hugo build output to ${BLOG_INSTALL_DIR}/public" + echo -e " 1. Run ${BOLD}$0 blog-deploy-info${NC} to get the Forgejo deploy secrets" echo -e " 2. In Nginx Proxy Manager create a Proxy Host:" echo -e " Domain Names : ${CYAN}blog.yourdomain.com${NC}" echo -e " Scheme : ${CYAN}http${NC}" @@ -736,6 +822,7 @@ do_blog_update() { install_deps ensure_docker_network + ensure_blog_deploy_keypair local dc dc=$(get_compose_cmd) @@ -762,16 +849,18 @@ show_blog_menu() { separator echo " 1) Install Blog" echo " 2) Update Blog" - echo " 3) Uninstall Blog" - echo " 4) Back" + echo " 3) Show Deploy Info" + echo " 4) Uninstall Blog" + echo " 5) Back" separator - read -rp " Select [1-4]: " choice + read -rp " Select [1-5]: " choice echo "" case "$choice" in 1) do_blog_install ;; 2) do_blog_update ;; - 3) do_blog_uninstall ;; - 4) return ;; + 3) show_blog_deploy_info ;; + 4) do_blog_uninstall ;; + 5) return ;; *) log_err "Invalid option." ;; esac done @@ -1371,6 +1460,7 @@ show_help() { echo " blog Open Blog submenu (install/update/uninstall)" echo " blog-install Install lightweight static blog hosting for Hugo" echo " blog-update Update lightweight static blog hosting" + echo " blog-deploy-info Show the Blog deploy user and Forgejo secret values" echo " blog-uninstall Remove lightweight static blog hosting" echo " forgejo Open Forgejo submenu (install/uninstall/update)" echo " runner-update Update Forgejo Runner while keeping its configuration" @@ -1400,6 +1490,7 @@ else blog) show_blog_menu ;; blog-install) do_blog_install ;; blog-update) do_blog_update ;; + blog-deploy-info) show_blog_deploy_info ;; blog-uninstall) do_blog_uninstall ;; forgejo) show_forgejo_menu ;; runner-update) do_forgejo_runner_update ;;