Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
This commit is contained in:
Executable
+368
@@ -0,0 +1,368 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
######################################################################################
|
||||
#### install-webtop.sh — Deploy LinuxServer.io Webtop behind nginx reverse proxy ####
|
||||
#### Installs Docker, runs Webtop container with persistent config, configures ####
|
||||
#### nginx with basic auth and WebSocket proxy for KasmVNC. ####
|
||||
#### Requires: Ubuntu 22.04+, root access ####
|
||||
#### ####
|
||||
#### Author: Phil Connor ####
|
||||
#### Contact: contact@mylinux.work ####
|
||||
#### License: MIT ####
|
||||
#### Version 1.00 ####
|
||||
#### ####
|
||||
#### Usage: ####
|
||||
#### sudo ./install-webtop.sh --domain webtop.example.com ####
|
||||
#### sudo ./install-webtop.sh --domain webtop.example.com --no-ssl ####
|
||||
#### sudo ./install-webtop.sh --domain webtop.example.com --allow-ip 1.2.3.4 ####
|
||||
#### ####
|
||||
#### See --help for all options. ####
|
||||
######################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────
|
||||
DOMAIN=""
|
||||
DESKTOP="fedora-mate"
|
||||
WEBTOP_IMAGE=""
|
||||
CONTAINER_NAME="webtop"
|
||||
CONFIG_DIR="/opt/webtop"
|
||||
INTERNAL_PORT="3000"
|
||||
TIMEZONE="${TZ:-America/Chicago}"
|
||||
SHM_SIZE="1gb"
|
||||
ALLOW_IP=""
|
||||
NO_SSL=false
|
||||
AUTH_USER="admin"
|
||||
AUTH_PASS=""
|
||||
SKIP_DOCKER=false
|
||||
|
||||
# ── Colors ────────────────────────────────────────────────────────────
|
||||
if [[ -t 1 ]]; then
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
BOLD='\033[1m'
|
||||
RESET='\033[0m'
|
||||
else
|
||||
GREEN="" YELLOW="" RED="" BLUE="" BOLD="" RESET=""
|
||||
fi
|
||||
|
||||
log() { echo -e "${GREEN}[OK]${RESET} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; }
|
||||
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
|
||||
step() { echo -e "\n${BOLD}── $* ──${RESET}"; }
|
||||
|
||||
# ── Help ──────────────────────────────────────────────────────────────
|
||||
show_help() {
|
||||
cat <<'EOF'
|
||||
Usage: install-webtop.sh [OPTIONS]
|
||||
|
||||
Deploy LinuxServer.io Webtop (Fedora MATE) behind nginx reverse proxy
|
||||
with basic auth, WebSocket support, and optional Let's Encrypt SSL.
|
||||
|
||||
Required:
|
||||
--domain DOMAIN Domain name for nginx vhost and SSL cert
|
||||
|
||||
Options:
|
||||
--desktop DESKTOP Desktop environment (default: fedora-mate)
|
||||
Options: fedora-mate, fedora-xfce, fedora-kde,
|
||||
ubuntu-mate, ubuntu-xfce, ubuntu-kde,
|
||||
alpine-xfce, alpine-kde
|
||||
--image IMAGE Override with a custom image tag
|
||||
--name NAME Container name (default: webtop)
|
||||
--config-dir PATH Persistent config directory (default: /opt/webtop)
|
||||
--port PORT Internal KasmVNC port (default: 3000)
|
||||
--tz TIMEZONE Timezone (default: America/Chicago)
|
||||
--shm-size SIZE Shared memory size (default: 1gb)
|
||||
--allow-ip IP Restrict access to this IP in UFW (optional)
|
||||
--auth-user USER Basic auth username (default: admin)
|
||||
--auth-pass PASS Basic auth password (prompted if not set)
|
||||
--no-ssl Skip Let's Encrypt — use HTTP only
|
||||
--skip-docker Skip Docker installation (already installed)
|
||||
-h, --help Show this help
|
||||
|
||||
Examples:
|
||||
sudo ./install-webtop.sh --domain webtop.example.com
|
||||
sudo ./install-webtop.sh --domain webtop.example.com --allow-ip 203.0.113.50
|
||||
sudo ./install-webtop.sh --domain webtop.example.com --desktop ubuntu-xfce
|
||||
sudo ./install-webtop.sh --domain webtop.example.com --no-ssl --auth-pass s3cret
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ── Parse Arguments ───────────────────────────────────────────────────
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--domain) DOMAIN="$2"; shift 2 ;;
|
||||
--desktop) DESKTOP="$2"; shift 2 ;;
|
||||
--image) WEBTOP_IMAGE="$2"; shift 2 ;;
|
||||
--name) CONTAINER_NAME="$2"; shift 2 ;;
|
||||
--config-dir) CONFIG_DIR="$2"; shift 2 ;;
|
||||
--port) INTERNAL_PORT="$2"; shift 2 ;;
|
||||
--tz) TIMEZONE="$2"; shift 2 ;;
|
||||
--shm-size) SHM_SIZE="$2"; shift 2 ;;
|
||||
--allow-ip) ALLOW_IP="$2"; shift 2 ;;
|
||||
--auth-user) AUTH_USER="$2"; shift 2 ;;
|
||||
--auth-pass) AUTH_PASS="$2"; shift 2 ;;
|
||||
--no-ssl) NO_SSL=true; shift ;;
|
||||
--skip-docker) SKIP_DOCKER=true; shift ;;
|
||||
-h|--help) show_help ;;
|
||||
*) err "Unknown option: $1"; echo "Run with --help for usage."; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$DOMAIN" ]]; then
|
||||
err "--domain is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# resolve image from desktop choice (--image overrides)
|
||||
if [[ -z "$WEBTOP_IMAGE" ]]; then
|
||||
local valid_desktops="fedora-mate fedora-xfce fedora-kde ubuntu-mate ubuntu-xfce ubuntu-kde alpine-xfce alpine-kde"
|
||||
if ! echo "$valid_desktops" | grep -qw "$DESKTOP"; then
|
||||
err "Unknown desktop: ${DESKTOP}"
|
||||
echo "Valid options: ${valid_desktops}"
|
||||
exit 1
|
||||
fi
|
||||
WEBTOP_IMAGE="lscr.io/linuxserver/webtop:${DESKTOP}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Root Check ────────────────────────────────────────────────────────
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
err "This script must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Install Docker ────────────────────────────────────────────────────
|
||||
install_docker() {
|
||||
step "Docker"
|
||||
|
||||
if [[ "$SKIP_DOCKER" == "true" ]]; then
|
||||
log "Skipping Docker install (--skip-docker)"
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v docker &>/dev/null; then
|
||||
log "Docker already installed: $(docker --version)"
|
||||
return
|
||||
fi
|
||||
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
systemctl enable --now docker
|
||||
log "Docker installed: $(docker --version)"
|
||||
}
|
||||
|
||||
# ── Create Config Directory ───────────────────────────────────────────
|
||||
setup_config_dir() {
|
||||
step "Config directory"
|
||||
mkdir -p "${CONFIG_DIR}"
|
||||
log "Persistent config: ${CONFIG_DIR}"
|
||||
}
|
||||
|
||||
# ── Run Webtop Container ─────────────────────────────────────────────
|
||||
run_webtop() {
|
||||
step "Webtop container"
|
||||
|
||||
if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||
warn "Container '${CONTAINER_NAME}' already exists — removing"
|
||||
docker rm -f "${CONTAINER_NAME}" >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
docker run -d \
|
||||
--name "${CONTAINER_NAME}" \
|
||||
--restart unless-stopped \
|
||||
-p "127.0.0.1:${INTERNAL_PORT}:3000" \
|
||||
-e PUID=1000 \
|
||||
-e PGID=1000 \
|
||||
-e "TZ=${TIMEZONE}" \
|
||||
-v "${CONFIG_DIR}:/config" \
|
||||
--shm-size="${SHM_SIZE}" \
|
||||
"${WEBTOP_IMAGE}"
|
||||
|
||||
log "Container '${CONTAINER_NAME}' running (${WEBTOP_IMAGE})"
|
||||
log "Bound to 127.0.0.1:${INTERNAL_PORT} (nginx will proxy)"
|
||||
}
|
||||
|
||||
# ── Install nginx ─────────────────────────────────────────────────────
|
||||
install_nginx() {
|
||||
step "nginx"
|
||||
|
||||
if ! command -v nginx &>/dev/null; then
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq nginx apache2-utils >/dev/null
|
||||
log "nginx installed"
|
||||
else
|
||||
log "nginx already installed"
|
||||
if ! command -v htpasswd &>/dev/null; then
|
||||
apt-get install -y -qq apache2-utils >/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Basic Auth ────────────────────────────────────────────────────────
|
||||
setup_auth() {
|
||||
step "Basic auth"
|
||||
|
||||
if [[ -z "$AUTH_PASS" ]]; then
|
||||
AUTH_PASS=$(openssl rand -base64 16)
|
||||
fi
|
||||
|
||||
htpasswd -bc /etc/nginx/.htpasswd_webtop "${AUTH_USER}" "${AUTH_PASS}" 2>/dev/null
|
||||
chown root:www-data /etc/nginx/.htpasswd_webtop
|
||||
chmod 640 /etc/nginx/.htpasswd_webtop
|
||||
|
||||
# save credentials to a root-only file
|
||||
local creds_file="${CONFIG_DIR}/.credentials"
|
||||
echo "username=${AUTH_USER}" > "${creds_file}"
|
||||
echo "password=${AUTH_PASS}" >> "${creds_file}"
|
||||
chmod 600 "${creds_file}"
|
||||
|
||||
log "Basic auth configured (user: ${AUTH_USER})"
|
||||
log "Credentials saved to ${creds_file} (root-only)"
|
||||
}
|
||||
|
||||
# ── nginx Vhost ───────────────────────────────────────────────────────
|
||||
configure_nginx() {
|
||||
step "nginx vhost"
|
||||
|
||||
cat > "/etc/nginx/sites-available/${DOMAIN}" <<NGINX
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${DOMAIN};
|
||||
|
||||
auth_basic "Webtop";
|
||||
auth_basic_user_file /etc/nginx/.htpasswd_webtop;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:${INTERNAL_PORT};
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade \$http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 86400s;
|
||||
}
|
||||
}
|
||||
NGINX
|
||||
|
||||
ln -sf "/etc/nginx/sites-available/${DOMAIN}" /etc/nginx/sites-enabled/
|
||||
|
||||
nginx -t 2>&1
|
||||
systemctl reload nginx
|
||||
log "nginx vhost configured: ${DOMAIN}"
|
||||
}
|
||||
|
||||
# ── Let's Encrypt SSL ────────────────────────────────────────────────
|
||||
setup_ssl() {
|
||||
step "SSL (Let's Encrypt)"
|
||||
|
||||
if [[ "$NO_SSL" == "true" ]]; then
|
||||
warn "Skipping SSL (--no-ssl) — access via http://${DOMAIN}"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! command -v certbot &>/dev/null; then
|
||||
apt-get install -y -qq certbot python3-certbot-nginx >/dev/null
|
||||
log "certbot installed"
|
||||
fi
|
||||
|
||||
certbot --nginx -d "${DOMAIN}" --non-interactive --agree-tos \
|
||||
--register-unsafely-without-email --redirect
|
||||
|
||||
log "SSL configured: https://${DOMAIN}"
|
||||
}
|
||||
|
||||
# ── UFW Rules ─────────────────────────────────────────────────────────
|
||||
setup_ufw() {
|
||||
step "Firewall"
|
||||
|
||||
if ! command -v ufw &>/dev/null; then
|
||||
warn "UFW not found — skipping firewall config"
|
||||
return
|
||||
fi
|
||||
|
||||
ufw allow OpenSSH >/dev/null 2>&1 || true
|
||||
ufw allow 'Nginx Full' >/dev/null 2>&1 || true
|
||||
|
||||
if [[ -n "$ALLOW_IP" ]]; then
|
||||
ufw deny from any to any port 80 >/dev/null 2>&1 || true
|
||||
ufw deny from any to any port 443 >/dev/null 2>&1 || true
|
||||
ufw allow from "${ALLOW_IP}" to any port 80 >/dev/null 2>&1 || true
|
||||
ufw allow from "${ALLOW_IP}" to any port 443 >/dev/null 2>&1 || true
|
||||
log "Access restricted to ${ALLOW_IP}"
|
||||
else
|
||||
log "nginx ports open (no IP restriction)"
|
||||
warn "Consider using --allow-ip to restrict access"
|
||||
fi
|
||||
|
||||
if ! ufw status | grep -q "^Status: active"; then
|
||||
ufw --force enable >/dev/null 2>&1
|
||||
log "UFW enabled"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Summary ───────────────────────────────────────────────────────────
|
||||
print_summary() {
|
||||
local proto="http"
|
||||
if [[ "$NO_SSL" == "false" ]]; then
|
||||
proto="https"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "────────────────────────────────────────"
|
||||
echo -e "${BOLD}Webtop Deployment Complete${RESET}"
|
||||
echo "────────────────────────────────────────"
|
||||
echo " URL: ${proto}://${DOMAIN}"
|
||||
echo " Username: ${AUTH_USER}"
|
||||
echo " Password: ${AUTH_PASS}"
|
||||
echo " Creds file: ${CONFIG_DIR}/.credentials"
|
||||
echo " Image: ${WEBTOP_IMAGE}"
|
||||
echo " Container: ${CONTAINER_NAME}"
|
||||
echo " Config: ${CONFIG_DIR}"
|
||||
echo " Timezone: ${TIMEZONE}"
|
||||
if [[ -n "$ALLOW_IP" ]]; then
|
||||
echo " Allowed IP: ${ALLOW_IP}"
|
||||
fi
|
||||
echo "────────────────────────────────────────"
|
||||
echo ""
|
||||
echo "Manage:"
|
||||
echo " docker logs ${CONTAINER_NAME} # view logs"
|
||||
echo " docker restart ${CONTAINER_NAME} # restart"
|
||||
echo " docker stop ${CONTAINER_NAME} # stop"
|
||||
echo " docker start ${CONTAINER_NAME} # start"
|
||||
echo " ls ${CONFIG_DIR}/ # persistent data"
|
||||
}
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────
|
||||
main() {
|
||||
parse_args "$@"
|
||||
check_root
|
||||
|
||||
echo -e "${BOLD}Webtop Installer${RESET}"
|
||||
echo "Domain: ${DOMAIN}"
|
||||
echo "Image: ${WEBTOP_IMAGE}"
|
||||
echo "Config: ${CONFIG_DIR}"
|
||||
|
||||
install_docker
|
||||
setup_config_dir
|
||||
run_webtop
|
||||
install_nginx
|
||||
setup_auth
|
||||
configure_nginx
|
||||
setup_ssl
|
||||
setup_ufw
|
||||
print_summary
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user