feat(tools): add root-password and update-server tools
- add `tools/root-password.sh` to change root password interactively or generate a random one - add `tools/update-server.sh` to run apt update/upgrade/autoremove/autoclean - register both tools in `lxs.sh` dispatcher and `tools/index.sh` interactive menu - document new tools in README.md
This commit is contained in:
@@ -50,6 +50,8 @@ lxs help # Show help
|
|||||||
| `lxs tool system` | System monitoring and diagnostics |
|
| `lxs tool system` | System monitoring and diagnostics |
|
||||||
| `lxs tool benchmark` | Server benchmark (CPU / RAM / disk / network) |
|
| `lxs tool benchmark` | Server benchmark (CPU / RAM / disk / network) |
|
||||||
| `lxs tool harden` | Baseline hardening: UFW + fail2ban + SSH key-only + unattended-upgrades |
|
| `lxs tool harden` | Baseline hardening: UFW + fail2ban + SSH key-only + unattended-upgrades |
|
||||||
|
| `lxs tool root-password` | Change the root password (interactive or generated) |
|
||||||
|
| `lxs tool update` | Update the server (apt update + upgrade + autoremove + autoclean) |
|
||||||
|
|
||||||
## Project structure
|
## Project structure
|
||||||
|
|
||||||
@@ -70,7 +72,9 @@ lxs/
|
|||||||
├── index.sh # Interactive menu listing the tools below
|
├── index.sh # Interactive menu listing the tools below
|
||||||
├── system-infos.sh
|
├── system-infos.sh
|
||||||
├── server-benchmark.sh
|
├── server-benchmark.sh
|
||||||
└── harden.sh
|
├── harden.sh
|
||||||
|
├── root-password.sh
|
||||||
|
└── update-server.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
After `lxs setup`, the full tree lives in `/usr/local/share/lxs/` and sub-scripts execute from disk. If `lxs.sh` is run without being installed (the one-liner mode), it falls back to downloading sub-scripts on demand.
|
After `lxs setup`, the full tree lives in `/usr/local/share/lxs/` and sub-scripts execute from disk. If `lxs.sh` is run without being installed (the one-liner mode), it falls back to downloading sub-scripts on demand.
|
||||||
|
|||||||
@@ -287,6 +287,8 @@ cmd_tool() {
|
|||||||
system) download_and_run "tools/system-infos.sh" "$@" ;;
|
system) download_and_run "tools/system-infos.sh" "$@" ;;
|
||||||
benchmark) download_and_run "tools/server-benchmark.sh" "$@" ;;
|
benchmark) download_and_run "tools/server-benchmark.sh" "$@" ;;
|
||||||
harden) download_and_run "tools/harden.sh" "$@" ;;
|
harden) download_and_run "tools/harden.sh" "$@" ;;
|
||||||
|
root-password) download_and_run "tools/root-password.sh" "$@" ;;
|
||||||
|
update) download_and_run "tools/update-server.sh" "$@" ;;
|
||||||
"") echo -e "${RED}[✗] Missing tool name. Try: lxs help${NC}"; return 1 ;;
|
"") echo -e "${RED}[✗] Missing tool name. Try: lxs help${NC}"; return 1 ;;
|
||||||
*) echo -e "${RED}[✗] Unknown tool: $tool. Try: lxs help${NC}"; return 1 ;;
|
*) echo -e "${RED}[✗] Unknown tool: $tool. Try: lxs help${NC}"; return 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
+6
-2
@@ -60,17 +60,21 @@ menu_tools() {
|
|||||||
echo -e " ${CYAN}[1]${NC} System Infos"
|
echo -e " ${CYAN}[1]${NC} System Infos"
|
||||||
echo -e " ${PURPLE}[2]${NC} Server Benchmark"
|
echo -e " ${PURPLE}[2]${NC} Server Benchmark"
|
||||||
echo -e " ${YELLOW}[3]${NC} Harden Server"
|
echo -e " ${YELLOW}[3]${NC} Harden Server"
|
||||||
|
echo -e " ${GREEN}[4]${NC} Change Root Password"
|
||||||
|
echo -e " ${CYAN}[5]${NC} Update Server"
|
||||||
echo -e " ${RED}[0]${NC} Back"
|
echo -e " ${RED}[0]${NC} Back"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e -n "${BOLD}Choice [0-3]: ${NC}"
|
echo -e -n "${BOLD}Choice [0-5]: ${NC}"
|
||||||
read -r choice
|
read -r choice
|
||||||
|
|
||||||
case $choice in
|
case $choice in
|
||||||
1) run_sibling "tools/system-infos.sh" ;;
|
1) run_sibling "tools/system-infos.sh" ;;
|
||||||
2) run_sibling "tools/server-benchmark.sh" ;;
|
2) run_sibling "tools/server-benchmark.sh" ;;
|
||||||
3) run_sibling "tools/harden.sh" ;;
|
3) run_sibling "tools/harden.sh" ;;
|
||||||
|
4) run_sibling "tools/root-password.sh" ;;
|
||||||
|
5) run_sibling "tools/update-server.sh" ;;
|
||||||
0) return ;;
|
0) return ;;
|
||||||
*) echo -e "${RED}[✗] Invalid option. Please select 0-3.${NC}"; sleep 1; continue ;;
|
*) echo -e "${RED}[✗] Invalid option. Please select 0-5.${NC}"; sleep 1; continue ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ "$choice" != "0" ]; then
|
if [ "$choice" != "0" ]; then
|
||||||
|
|||||||
Executable
+121
@@ -0,0 +1,121 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# LXS - Change root password
|
||||||
|
# Description: Change the root account password (interactive or generated)
|
||||||
|
# Author: LXS
|
||||||
|
# Date: 2025
|
||||||
|
|
||||||
|
# Load LXS common library (colors, separator, run_spinner, loggers, helpers)
|
||||||
|
LXS_RAW_BASE="${LXS_RAW_BASE:-https://git.hyko.cx/hykocx/lxs/raw/branch/main}"
|
||||||
|
_lib=$(curl -fsSL "${LXS_RAW_BASE}/lib/common.sh") || { echo "Failed to fetch lib/common.sh" >&2; exit 1; }
|
||||||
|
eval "$_lib"
|
||||||
|
unset _lib
|
||||||
|
export LXS_LOG_FILE="/tmp/lxs_root_password.log"
|
||||||
|
|
||||||
|
require_root "$0" "$@"
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Arguments
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
MODE=""
|
||||||
|
PASSWORD_LENGTH=24
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
-g|--generate) MODE="generate" ;;
|
||||||
|
-i|--interactive) MODE="interactive" ;;
|
||||||
|
--length=*) PASSWORD_LENGTH="${arg#*=}" ;;
|
||||||
|
-h|--help)
|
||||||
|
cat <<EOF
|
||||||
|
Usage: root-password.sh [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-i, --interactive Prompt for the new password (passwd root)
|
||||||
|
-g, --generate Generate a strong random password and apply it
|
||||||
|
--length=N Length of the generated password (default: 24)
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
With no option, an interactive menu is shown.
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}Unknown option: $arg${NC}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Actions
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
change_interactive() {
|
||||||
|
info "Setting root password interactively..."
|
||||||
|
show_separator
|
||||||
|
if passwd root; then
|
||||||
|
show_separator
|
||||||
|
ok "Root password updated"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
show_separator
|
||||||
|
err "Failed to update root password"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
change_generated() {
|
||||||
|
if ! [[ "$PASSWORD_LENGTH" =~ ^[0-9]+$ ]] || [ "$PASSWORD_LENGTH" -lt 12 ]; then
|
||||||
|
err "--length must be a number ≥ 12 (got: ${PASSWORD_LENGTH})"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local new_password
|
||||||
|
new_password=$(generate_password "$PASSWORD_LENGTH")
|
||||||
|
if [ -z "$new_password" ]; then
|
||||||
|
err "Failed to generate a password"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! echo "root:${new_password}" | chpasswd; then
|
||||||
|
err "Failed to apply the generated password"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
show_separator
|
||||||
|
ok "Root password updated"
|
||||||
|
echo ""
|
||||||
|
echo -e "${WHITE}${BOLD}New root password:${NC} ${YELLOW}${new_password}${NC}"
|
||||||
|
echo ""
|
||||||
|
warn "Store this password in a secure place. It will not be shown again."
|
||||||
|
show_separator
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Menu (when no mode is given on the CLI)
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
if [ -z "$MODE" ]; then
|
||||||
|
echo -e "${WHITE}${BOLD}LXS - Change root password${NC}"
|
||||||
|
show_separator
|
||||||
|
echo -e " ${CYAN}[1]${NC} Set a new password interactively"
|
||||||
|
echo -e " ${CYAN}[2]${NC} Generate a strong random password"
|
||||||
|
echo -e " ${RED}[0]${NC} Cancel"
|
||||||
|
echo ""
|
||||||
|
echo -e -n "${BOLD}Choice [0-2]: ${NC}"
|
||||||
|
read -r choice
|
||||||
|
case "$choice" in
|
||||||
|
1) MODE="interactive" ;;
|
||||||
|
2) MODE="generate" ;;
|
||||||
|
0|"") info "Cancelled."; exit 0 ;;
|
||||||
|
*) err "Invalid option."; exit 1 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
interactive) change_interactive ;;
|
||||||
|
generate) change_generated ;;
|
||||||
|
esac
|
||||||
Executable
+133
@@ -0,0 +1,133 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# LXS - Update server
|
||||||
|
# Description: Refresh package lists and upgrade installed packages
|
||||||
|
# Author: LXS
|
||||||
|
# Date: 2025
|
||||||
|
|
||||||
|
# Load LXS common library (colors, separator, run_spinner, loggers, helpers)
|
||||||
|
LXS_RAW_BASE="${LXS_RAW_BASE:-https://git.hyko.cx/hykocx/lxs/raw/branch/main}"
|
||||||
|
_lib=$(curl -fsSL "${LXS_RAW_BASE}/lib/common.sh") || { echo "Failed to fetch lib/common.sh" >&2; exit 1; }
|
||||||
|
eval "$_lib"
|
||||||
|
unset _lib
|
||||||
|
export LXS_LOG_FILE="/tmp/lxs_update_server.log"
|
||||||
|
|
||||||
|
require_root "$0" "$@"
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Arguments
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
DO_FULL_UPGRADE=0
|
||||||
|
DO_AUTOREMOVE=1
|
||||||
|
DO_AUTOCLEAN=1
|
||||||
|
ASSUME_YES=0
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--full|--dist-upgrade) DO_FULL_UPGRADE=1 ;;
|
||||||
|
--no-autoremove) DO_AUTOREMOVE=0 ;;
|
||||||
|
--no-autoclean) DO_AUTOCLEAN=0 ;;
|
||||||
|
-y|--yes) ASSUME_YES=1 ;;
|
||||||
|
-h|--help)
|
||||||
|
cat <<EOF
|
||||||
|
Usage: update-server.sh [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--full, --dist-upgrade Use 'apt-get full-upgrade' (may add/remove packages)
|
||||||
|
--no-autoremove Skip 'apt-get autoremove'
|
||||||
|
--no-autoclean Skip 'apt-get autoclean'
|
||||||
|
-y, --yes Skip confirmation prompt
|
||||||
|
-h, --help Show this help
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}Unknown option: $arg${NC}" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Pre-checks
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
require_debian_ubuntu || exit 1
|
||||||
|
|
||||||
|
if ! command -v apt-get >/dev/null 2>&1; then
|
||||||
|
err "apt-get is not available on this system"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
UPGRADE_CMD="upgrade"
|
||||||
|
UPGRADE_LABEL="Upgrade installed packages"
|
||||||
|
if [ $DO_FULL_UPGRADE -eq 1 ]; then
|
||||||
|
UPGRADE_CMD="full-upgrade"
|
||||||
|
UPGRADE_LABEL="Full-upgrade (may add/remove packages)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${WHITE}${BOLD}LXS Server Update${NC}"
|
||||||
|
show_separator
|
||||||
|
echo "The following actions will be performed:"
|
||||||
|
echo " • Refresh package lists (apt-get update)"
|
||||||
|
echo " • ${UPGRADE_LABEL}"
|
||||||
|
[ $DO_AUTOREMOVE -eq 1 ] && echo " • Remove unused packages (apt-get autoremove)"
|
||||||
|
[ $DO_AUTOCLEAN -eq 1 ] && echo " • Clean old package archives (apt-get autoclean)"
|
||||||
|
show_separator
|
||||||
|
|
||||||
|
if [ $ASSUME_YES -ne 1 ]; then
|
||||||
|
echo -e -n "${BOLD}Proceed? [y/N]: ${NC}"
|
||||||
|
read -r reply
|
||||||
|
case "$reply" in
|
||||||
|
[yY]|[yY][eE][sS]) ;;
|
||||||
|
*) info "Cancelled."; exit 0 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Run
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
apt_noninteractive
|
||||||
|
wait_for_apt || exit 1
|
||||||
|
|
||||||
|
APT_OPTS='-y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold"'
|
||||||
|
|
||||||
|
run_spinner "Refreshing package lists..." "apt-get update" || {
|
||||||
|
err "apt-get update failed — see ${LXS_LOG_FILE}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
run_spinner "${UPGRADE_LABEL}..." "apt-get ${APT_OPTS} ${UPGRADE_CMD}" || {
|
||||||
|
err "apt-get ${UPGRADE_CMD} failed — see ${LXS_LOG_FILE}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $DO_AUTOREMOVE -eq 1 ]; then
|
||||||
|
run_spinner "Removing unused packages..." "apt-get ${APT_OPTS} autoremove --purge" \
|
||||||
|
|| warn "autoremove failed — see ${LXS_LOG_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $DO_AUTOCLEAN -eq 1 ]; then
|
||||||
|
run_spinner "Cleaning old archives..." "apt-get ${APT_OPTS} autoclean" \
|
||||||
|
|| warn "autoclean failed — see ${LXS_LOG_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
show_separator
|
||||||
|
ok "Server updated"
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Reboot hint
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
if [ -f /var/run/reboot-required ]; then
|
||||||
|
echo ""
|
||||||
|
warn "A reboot is required to complete the update."
|
||||||
|
if [ -f /var/run/reboot-required.pkgs ]; then
|
||||||
|
echo -e "${GRAY}Packages requiring reboot:${NC}"
|
||||||
|
sed 's/^/ • /' /var/run/reboot-required.pkgs
|
||||||
|
fi
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user