summaryrefslogtreecommitdiffstats
path: root/deployment
diff options
context:
space:
mode:
authorAhmed AbdelHalim <[email protected]>2025-09-09 21:46:50 +0200
committerAhmed AbdelHalim <[email protected]>2025-09-09 21:59:52 +0200
commite3aed3022ff51a5f3b05cc5b8a5076199075c6f1 (patch)
treecb418878a4f7c000b3c4784c93bc6b8d8faace16 /deployment
parent81ca75de8ea7b010203a2036fc02779da8fdadfd (diff)
Add install/uninstall scripts
Diffstat (limited to 'deployment')
-rwxr-xr-xdeployment/install.sh201
-rwxr-xr-xdeployment/uninstall.sh62
-rw-r--r--deployment/wg-portal.service39
3 files changed, 302 insertions, 0 deletions
diff --git a/deployment/install.sh b/deployment/install.sh
new file mode 100755
index 0000000..18652b9
--- /dev/null
+++ b/deployment/install.sh
@@ -0,0 +1,201 @@
+#!/bin/bash
+set -euo pipefail
+
+abort() {
+ printf "\033[31m%s\033[0m\n" "$@" >&2
+ exit 1
+}
+
+log() {
+ printf "%s\n" "$@"
+}
+
+ensure_visudo() {
+ if ! command -v visudo >/dev/null 2>&1; then
+ log "visudo was not found"
+ log "Please install visudo for your distro"
+ abort "sudo must be installed"
+ fi
+}
+
+ensure_curl() {
+ if ! command -v curl >/dev/null 2>&1; then
+ log "curl was not found"
+ log "Please install curl for your distro"
+ abort "curl must be installed"
+ fi
+}
+
+ensure_acl() {
+ if ! command -v setfacl >/dev/null 2>&1; then
+ log "ACL tools not found"
+ log "Please install acl for your distro"
+ abort "setfacl must be installed"
+ fi
+}
+
+ensure_wg() {
+ if ! command -v wg >/dev/null 2>&1; then
+ log "Wireguard tools not found"
+ log "Please install wireguard for your distro"
+ abort "wg/wg-quick must be installed"
+ fi
+ WIREGUARD_PATH="$(which wg)"
+ WIREGUARD_QUICK_PATH="$(which wg-quick)"
+}
+
+ensure_systemd() {
+ if ! systemctl --version >/dev/null 2>&1; then
+ abort "systemd is required but not available"
+ fi
+}
+
+ensure_sudo() {
+ if [ "$EUID" -ne 0 ]; then
+ abort "Must be run as sudo"
+ fi
+}
+
+get_arch() {
+ ARCH=$(uname -m)
+ case $ARCH in
+ x86_64) ARCH="amd64" ;;
+ aarch64) ARCH="arm64" ;;
+ armv7l) ARCH="arm" ;;
+ *) abort "Unsupported architecture: $ARCH" ;;
+ esac
+ log "Architecture: $ARCH"
+}
+
+get_version() {
+ if [ "$VERSION" = "latest" ]; then
+ RELEASE_URL="https://api.github.com/repos/a14m/wg-portal/releases/latest"
+ VERSION=$(curl -s "$RELEASE_URL" | grep '"tag_name":' | cut -d '"' -f 4)
+ log "Latest version: $VERSION"
+ fi
+}
+
+validate_version() {
+ if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] && [ "$VERSION" != "latest" ]; then
+ abort "Invalid version format: $VERSION (valid format example v1.0.0)"
+ fi
+}
+
+create_tmp() {
+ TMP_DIR=$(mktemp -d)
+ trap 'rm -rf $TMP_DIR' EXIT
+}
+
+download_binary() {
+ log "Downloading wg-portal binary"
+ DOWNLOAD_URL="https://github.com/a14m/wg-portal/releases/download/$VERSION/wg-portal-linux-${ARCH}"
+ if ! timeout 120 curl -s -L -o "$TMP_DIR/wg-portal" "$DOWNLOAD_URL"; then
+ log "Failed to download $DOWNLOAD_URL"
+ abort "Failed to download wg-portal binary"
+ fi
+ log "Downloaded $TMP_DIR/wg-portal"
+}
+
+download_systemd_service() {
+ log "Downloading wg-portal.service"
+ DOWNLOAD_SERVICE_URL="https://git.sr.ht/~a14m/wg-portal/blob/$VERSION/deployment/wg-portal.service"
+ if ! timeout 30 curl -s -L -o "$TMP_DIR/wg-portal.service" "$DOWNLOAD_SERVICE_URL"; then
+ log "Failed to download $DOWNLOAD_SERVICE_URL"
+ abort "Failed to download wg-portal.service"
+ fi
+ log "Downloaded $TMP_DIR/wg-portal.service"
+}
+
+create_system_user() {
+ if ! id -u wg-portal >/dev/null 2>&1; then
+ log "Creating wg-portal system user and group..."
+ useradd --system --no-create-home --shell /usr/sbin/nologin wg-portal
+ else
+ log "User wg-portal already exists"
+ fi
+}
+
+create_etc_directory() {
+ log "Creating /etc/wg-portal directory..."
+ mkdir -p /etc/wg-portal
+ chown root:wg-portal /etc/wg-portal
+ chmod 750 /etc/wg-portal
+}
+
+configure_access_control() {
+ log "Configure ACL for /etc/wireguard"
+ setfacl -R -m g:wg-portal:r /etc/wireguard
+
+ log "Setting up wg-portal user/group sudo permissions"
+ cat > "$TMP_DIR/wg-portal-sudoers" << EOF
+%wg-portal ALL=(ALL) NOPASSWD: ${WIREGUARD_QUICK_PATH} up *, ${WIREGUARD_QUICK_PATH} down *
+%wg-portal ALL=(ALL) NOPASSWD: ${WIREGUARD_PATH} show
+EOF
+ # Validate before installing
+ if visudo -c -f "$TMP_DIR/wg-portal-sudoers"; then
+ mv "$TMP_DIR/wg-portal-sudoers" /etc/sudoers.d/wg-portal
+ chmod 440 /etc/sudoers.d/wg-portal
+ else
+ abort "Invalid sudoers configuration"
+ fi
+}
+
+install_binary() {
+ log "Installing wg-portal binary to /etc/wg-portal"
+ chmod +x "$TMP_DIR/wg-portal"
+ mv "$TMP_DIR/wg-portal" /etc/wg-portal
+}
+
+install_systemd_service() {
+ log "Installing wg-portal systemd service..."
+ mv "$TMP_DIR/wg-portal.service" /etc/systemd/system/wg-portal.service
+ systemctl daemon-reload
+ systemctl enable wg-portal
+ log "Service installed and enabled"
+}
+
+show_completion_message() {
+ log ""
+ log "wg-portal installed successfully!"
+ log ""
+ log "Configuration:"
+ log " - Configuration file: /etc/wg-portal/config"
+ log ""
+ log "Service Information:"
+ log " - Binary installed: /etc/wg-portal/wg-portal"
+ log " - Service: wg-portal.service (enabled)"
+ log " - User: wg-portal (system user)"
+ log ""
+ log "Useful Commands:"
+ log " - Check status: systemctl status wg-portal"
+ log " - View logs: journalctl -u wg-portal -f"
+ log " - Restart: systemctl restart wg-portal"
+ log " - Stop: systemctl stop wg-portal"
+ log ""
+ log "Next steps:"
+ log " - Configure: /etc/wg-portal/config"
+ log " - Start Service: systemctl start wg-portal"
+}
+
+
+# Configuration
+VERSION=${1:-latest}
+# Main
+ensure_visudo
+ensure_curl
+ensure_acl
+ensure_wg
+ensure_systemd
+ensure_sudo
+get_arch
+get_version
+validate_version
+create_tmp
+download_binary
+download_systemd_service
+create_system_user
+create_etc_directory
+configure_access_control
+install_binary
+install_systemd_service
+show_completion_message
diff --git a/deployment/uninstall.sh b/deployment/uninstall.sh
new file mode 100755
index 0000000..a3a1b0e
--- /dev/null
+++ b/deployment/uninstall.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+set -euo pipefail
+
+abort() {
+ printf "\033[31m%s\033[0m\n" "$@" >&2
+ exit 1
+}
+
+log() {
+ printf "%s\n" "$@"
+}
+
+ensure_sudo() {
+ if [ "$EUID" -ne 0 ]; then
+ abort "Must be run as sudo"
+ fi
+}
+
+uninstall_systemd_configurations() {
+ log "Removing wg-portal systemd configurations"
+ systemctl stop wg-portal 2>/dev/null || true
+ systemctl disable wg-portal 2>/dev/null || true
+ rm -f /etc/systemd/system/wg-portal.service
+ systemctl daemon-reload
+}
+
+remove_directories() {
+ log "Removing wg-portal directories..."
+ rm -rf /etc/wg-portal
+}
+
+remove_sudo_configurations() {
+ log "Removing wg-portal sudo permissions..."
+ rm -f /etc/sudoers.d/wg-portal
+}
+
+remove_acl_permissions() {
+ if [ -d /etc/wireguard ]; then
+ log "Removing wg-portal ACL permissions from /etc/wireguard..."
+ setfacl -R -x g:wg-portal /etc/wireguard 2>/dev/null || true
+ fi
+}
+
+remove_system_user() {
+ log "Removing wg-portal system user and group..."
+ userdel wg-portal 2>/dev/null || true
+ groupdel wg-portal 2>/dev/null || true
+}
+
+show_completion_message() {
+ log ""
+ log "wg-portal uninstalled successfully!"
+}
+
+# Main
+ensure_sudo
+uninstall_systemd_configurations
+remove_directories
+remove_sudo_configurations
+remove_acl_permissions
+remove_system_user
+show_completion_message
diff --git a/deployment/wg-portal.service b/deployment/wg-portal.service
new file mode 100644
index 0000000..23d9dad
--- /dev/null
+++ b/deployment/wg-portal.service
@@ -0,0 +1,39 @@
+[Unit]
+Description=WireGuard Portal Web Interface
+Documentation=https://git.sr.ht/~a14m/wg-portal
+After=network-online.target
+Wants=network-online.target
+Requires=network.target
+
+[Service]
+Type=simple
+User=wg-portal
+Group=wg-portal
+ExecStart=/etc/wg-portal/wg-portal
+WorkingDirectory=/etc/wg-portal
+Restart=always
+RestartSec=5
+TimeoutStartSec=30
+TimeoutStopSec=30
+
+# Security hardening
+NoNewPrivileges=true
+ProtectSystem=strict
+ProtectHome=true
+ReadWritePaths=/etc/wireguard
+PrivateTmp=true
+PrivateDevices=true
+ProtectKernelTunables=true
+ProtectKernelModules=true
+ProtectControlGroups=true
+RestrictSUIDSGID=true
+RestrictRealtime=true
+LockPersonality=true
+
+# Logging
+StandardOutput=journal
+StandardError=journal
+SyslogIdentifier=wg-portal
+
+[Install]
+WantedBy=multi-user.target