Files
gh-christianlouis-install-g…/install_guac.sh
T
2025-09-07 13:17:51 +02:00

339 lines
9.9 KiB
Bash

#!/bin/bash
set -euo pipefail
# --- Defaults ---
GUACVERSION="1.5.5"
GUAC_USER="guacamole_user"
GUAC_DB="guacamole_db"
TOMCAT_VER=9.0.109
CRED_FILE="/root/guacamole-credentials.txt"
VERBOSE=false
# --- Temporary defaults (safe for reruns) ---
MYSQL_ROOT_PWD="root"
GUAC_PWD="guac"
GUACADMIN_PWD="guacadmin"
# --- Colors ---
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
# --- Functions ---
usage() {
cat <<EOF
Usage: $0 [options]
Options:
--help Show this help and exit
-v, --verbose Enable verbose output
-q, --quiet Suppress most output
SERVER_NAME=... Set server FQDN (env variable)
Examples:
SERVER_NAME=guac.example.com $0
SERVER_NAME=guac.example.com $0 -v
EOF
}
log() {
if [ "$VERBOSE" = true ]; then
echo -e "$@"
fi
}
# --- Parse args ---
while [[ $# -gt 0 ]]; do
case $1 in
--help) usage; exit 0 ;;
-v|--verbose) VERBOSE=true ;;
-q|--quiet) exec >/dev/null 2>&1 ;;
*) echo -e "${RED}Unknown option: $1${NC}"; usage; exit 1 ;;
esac
shift
done
# --- Hostname detection (reverse DNS via Google DNS) ---
SERVER_NAME=${SERVER_NAME:-}
if [ -z "$SERVER_NAME" ]; then
PUBIP=$(curl -4 -s ifconfig.me || echo "")
if [ -n "$PUBIP" ]; then
apt-get install -y -qq dnsutils >/dev/null 2>&1 || true
REVNAME=$(dig +short -x $PUBIP @8.8.8.8 | sed 's/\.$//' || true)
if [ -n "$REVNAME" ]; then
DEFAULT_NAME=$REVNAME
else
DEFAULT_NAME=$PUBIP
fi
else
DEFAULT_NAME="localhost"
fi
if [ -t 0 ]; then
read -p "Enter server name for Nginx/Let's Encrypt [${DEFAULT_NAME}]: " SERVER_NAME
SERVER_NAME=${SERVER_NAME:-$DEFAULT_NAME}
else
SERVER_NAME=$DEFAULT_NAME
echo -e "${YELLOW}No SERVER_NAME provided, using default: ${SERVER_NAME}${NC}"
fi
fi
# --- Install base packages ---
log "${BLUE}>>> Installing base packages...${NC}"
apt-get update -y
DEBIAN_FRONTEND=noninteractive apt-get install -yq \
xfce4 xfce4-goodies tightvncserver ufw curl wget zsh firefox dnsutils \
build-essential libjpeg-turbo8-dev libpng-dev libossp-uuid-dev \
libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \
freerdp2-dev libpango1.0-dev libssh2-1-dev libtelnet-dev \
libvncserver-dev libpulse-dev libssl-dev libvorbis-dev libwebp-dev \
libwebsockets-dev freerdp2-x11 libtool-bin ghostscript dpkg-dev crudini \
mariadb-server mariadb-client nginx certbot python3-certbot-nginx openssl
# --- Java ---
if ! command -v java >/dev/null 2>&1; then
apt-get install -y openjdk-17-jre-headless
fi
JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))
log "${GREEN}JAVA_HOME detected as ${JAVA_HOME}${NC}"
# --- Firewall ---
ufw --force enable
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw reload
# --- Tomcat 9 ---
if [ ! -d /opt/apache-tomcat-${TOMCAT_VER} ]; then
log "${BLUE}>>> Installing Tomcat ${TOMCAT_VER}...${NC}"
cd /opt
wget -q https://downloads.apache.org/tomcat/tomcat-9/v${TOMCAT_VER}/bin/apache-tomcat-${TOMCAT_VER}.tar.gz
tar -xzf apache-tomcat-${TOMCAT_VER}.tar.gz
ln -sfn apache-tomcat-${TOMCAT_VER} tomcat9
useradd -r -s /usr/sbin/nologin tomcat || true
chown -R tomcat:tomcat /opt/apache-tomcat-${TOMCAT_VER}
cat > /etc/systemd/system/tomcat9.service <<EOF
[Unit]
Description=Apache Tomcat 9
After=network.target
[Service]
Type=simple
User=tomcat
Group=tomcat
Environment=JAVA_HOME=${JAVA_HOME}
Environment=CATALINA_HOME=/opt/tomcat9
Environment=CATALINA_BASE=/opt/tomcat9
ExecStart=/opt/tomcat9/bin/catalina.sh run
ExecStop=/opt/tomcat9/bin/catalina.sh stop
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
EOF
fi
systemctl daemon-reload
systemctl enable --now tomcat9
# --- Guacamole ---
cd /root
SERVER="https://downloads.apache.org/guacamole/${GUACVERSION}"
if [ ! -d guacamole-server-${GUACVERSION} ]; then
wget -q ${SERVER}/source/guacamole-server-${GUACVERSION}.tar.gz
tar -xzf guacamole-server-${GUACVERSION}.tar.gz
wget -q ${SERVER}/binary/guacamole-${GUACVERSION}.war -O /etc/guacamole.war
wget -q ${SERVER}/binary/guacamole-auth-jdbc-${GUACVERSION}.tar.gz
tar -xzf guacamole-auth-jdbc-${GUACVERSION}.tar.gz
fi
if ! command -v guacd >/dev/null 2>&1; then
cd guacamole-server-${GUACVERSION}
./configure --with-systemd-dir=/etc/systemd/system
make -j$(nproc)
make install
ldconfig
cd ..
fi
if [ ! -f /etc/systemd/system/guacd.service ]; then
cat > /etc/systemd/system/guacd.service <<EOF
[Unit]
Description=Guacamole proxy daemon
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/sbin/guacd -f
User=daemon
Group=daemon
[Install]
WantedBy=multi-user.target
EOF
fi
systemctl daemon-reload
systemctl enable --now guacd
mkdir -p /etc/guacamole/extensions /etc/guacamole/lib
cp /etc/guacamole.war /opt/tomcat9/webapps/guacamole.war
cp guacamole-auth-jdbc-${GUACVERSION}/mysql/guacamole-auth-jdbc-mysql-${GUACVERSION}.jar /etc/guacamole/extensions/
# --- MySQL setup with defaults ---
log "${BLUE}>>> Setting up MySQL with defaults...${NC}"
mysql -u root <<EOF
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PWD}';
EOF
if ! mysql -u root -p${MYSQL_ROOT_PWD} -e "USE ${GUAC_DB}" 2>/dev/null; then
mysql -u root -p${MYSQL_ROOT_PWD} -e "CREATE DATABASE ${GUAC_DB};"
fi
USER_EXISTS=$(mysql -u root -p${MYSQL_ROOT_PWD} -e "SELECT COUNT(*) FROM mysql.user WHERE user='${GUAC_USER}';" -s --skip-column-names)
if [ "$USER_EXISTS" -eq 0 ]; then
mysql -u root -p${MYSQL_ROOT_PWD} -e "CREATE USER '${GUAC_USER}'@'localhost' IDENTIFIED BY '${GUAC_PWD}';"
mysql -u root -p${MYSQL_ROOT_PWD} -e "GRANT SELECT,INSERT,UPDATE,DELETE ON ${GUAC_DB}.* TO '${GUAC_USER}'@'localhost'; FLUSH PRIVILEGES;"
fi
if ! mysql -u root -p${MYSQL_ROOT_PWD} -D ${GUAC_DB} -e "SHOW TABLES;" | grep -q guacamole_user; then
cat guacamole-auth-jdbc-${GUACVERSION}/mysql/schema/*.sql | mysql -u root -p${MYSQL_ROOT_PWD} ${GUAC_DB}
fi
mkdir -p /etc/guacamole
cat > /etc/guacamole/guacamole.properties <<EOF
mysql-hostname: localhost
mysql-port: 3306
mysql-database: ${GUAC_DB}
mysql-username: ${GUAC_USER}
mysql-password: ${GUAC_PWD}
EOF
systemctl restart tomcat9
# --- Nginx reverse proxy ---
cat > /etc/nginx/sites-available/guacamole <<EOF
server {
listen 80;
server_name ${SERVER_NAME};
location / {
proxy_pass http://127.0.0.1:8080/guacamole/;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$http_connection;
proxy_cookie_path /guacamole/ /;
}
}
EOF
ln -sf /etc/nginx/sites-available/guacamole /etc/nginx/sites-enabled/guacamole
nginx -t && systemctl reload nginx
# --- Let's Encrypt with fallback ---
if certbot --nginx -d ${SERVER_NAME} --non-interactive --agree-tos -m admin@${SERVER_NAME} --redirect; then
log "${GREEN}Let's Encrypt certificate installed successfully.${NC}"
else
mkdir -p /etc/ssl/selfsigned
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/selfsigned/guac.key \
-out /etc/ssl/selfsigned/guac.crt \
-subj "/CN=${SERVER_NAME}"
cat > /etc/nginx/sites-available/guacamole <<EOF
server {
listen 80;
server_name ${SERVER_NAME};
return 301 https://\$host\$request_uri;
}
server {
listen 443 ssl;
server_name ${SERVER_NAME};
ssl_certificate /etc/ssl/selfsigned/guac.crt;
ssl_certificate_key /etc/ssl/selfsigned/guac.key;
location / {
proxy_pass http://127.0.0.1:8080/guacamole/;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$http_connection;
proxy_cookie_path /guacamole/ /;
}
}
EOF
nginx -t && systemctl reload nginx
fi
# --- Tailscale ---
echo -e "${BLUE}>>> Installing Tailscale...${NC}"
curl -fsSL https://tailscale.com/install.sh | sh
systemctl enable --now tailscaled
if [ -t 0 ]; then
read -p "Enter Tailscale auth key (leave blank for interactive login): " TSKEY || true
else
TSKEY=""
fi
if [ -n "${TSKEY:-}" ]; then
tailscale up --authkey=${TSKEY} --ssh
else
tailscale up --ssh
fi
# --- Final credential rotation ---
FINAL_MYSQL_ROOT_PWD=$(openssl rand -base64 20)
FINAL_GUAC_PWD=$(openssl rand -base64 20)
FINAL_GUACADMIN_PWD=$(openssl rand -base64 20)
mysql -u root -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${FINAL_MYSQL_ROOT_PWD}';"
mysql -u root -p${FINAL_MYSQL_ROOT_PWD} -e "ALTER USER '${GUAC_USER}'@'localhost' IDENTIFIED BY '${FINAL_GUAC_PWD}'; FLUSH PRIVILEGES;"
# Update guacamole.properties with new DB password
crudini --set /etc/guacamole/guacamole.properties '' mysql-password "${FINAL_GUAC_PWD}"
# Reset guacadmin password
if mysql -u root -p${FINAL_MYSQL_ROOT_PWD} ${GUAC_DB} -e "SHOW COLUMNS FROM guacamole_user LIKE 'username';" | grep -q username; then
COL="username"
else
COL="user_id"
fi
HASHED=$(echo -n "${FINAL_GUACADMIN_PWD}" | openssl md5 | awk '{print $2}')
mysql -u root -p${FINAL_MYSQL_ROOT_PWD} ${GUAC_DB} -e "UPDATE guacamole_user SET password='${HASHED}' WHERE ${COL}='guacadmin';"
systemctl restart tomcat9
# --- Save credentials ---
cat > ${CRED_FILE} <<EOF
Guacamole admin login:
User: guacadmin
Pass: ${FINAL_GUACADMIN_PWD}
MySQL root password:
${FINAL_MYSQL_ROOT_PWD}
MySQL guacamole user (${GUAC_USER}) password:
${FINAL_GUAC_PWD}
Server name:
${SERVER_NAME}
EOF
chmod 600 ${CRED_FILE}
# --- Final info ---
IP=$(curl -s ifconfig.me || echo "localhost")
echo -e "${GREEN}=========================================================${NC}"
echo -e "Guacamole is now running behind Nginx."
echo -e "URL: https://${SERVER_NAME}/"
echo -e "Alt: https://${IP}/"
echo -e "Login: guacadmin / ${FINAL_GUACADMIN_PWD}"
echo -e "MySQL root password: ${FINAL_MYSQL_ROOT_PWD}"
echo -e "MySQL guac user pass: ${FINAL_GUAC_PWD}"
echo -e "Credentials saved in: ${CRED_FILE}"
echo -e "${RED}*** Save them securely! ***${NC}"
echo -e "${GREEN}=========================================================${NC}"