282 lines
8.8 KiB
Bash
Executable File
282 lines
8.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
USERNAME="$1"
|
|
DOMAIN="$2"
|
|
APACHE_PORT="$3"
|
|
PUBLIC_PORT="$4"
|
|
TALK_PORT="$5"
|
|
|
|
if [ -z "$TALK_PORT" ]; then
|
|
echo "Usage: $0 <username> <domain> <apache_port> <public_port> <talk_port>"
|
|
exit 1
|
|
fi
|
|
|
|
FULL_DOMAIN="${USERNAME}.${DOMAIN}"
|
|
VHOST_FILE="/etc/apache2/sites-available/${FULL_DOMAIN}.conf"
|
|
USER_HOME="/home/${USERNAME}"
|
|
USER_SCRIPT="${USER_HOME}/install_nc.sh"
|
|
|
|
need_cmd() { command -v "$1" >/dev/null 2>&1; }
|
|
|
|
port_free() {
|
|
local p="$1"
|
|
if ss -ltnp 2>/dev/null | grep -qE ":(^|.*:)$p\s"; then
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
############################################################
|
|
# 0 - PACKAGES + APACHE + CERTBOT
|
|
############################################################
|
|
echo "[0/8] Ensuring required packages..."
|
|
need_cmd curl || (apt-get update -y && apt-get install -y curl)
|
|
need_cmd dig || (apt-get update -y && apt-get install -y dnsutils)
|
|
|
|
echo "[0.1/8] Ensuring Apache + modules..."
|
|
need_cmd apache2 || (apt-get update -y && apt-get install -y apache2)
|
|
mkdir -p /etc/apache2/sites-available /etc/apache2/sites-enabled
|
|
a2enmod proxy proxy_http proxy_wstunnel rewrite headers ssl http2 >/dev/null || true
|
|
systemctl enable --now apache2 >/dev/null
|
|
|
|
echo "[0.2/8] Ensuring certbot..."
|
|
need_cmd certbot || (apt-get update -y && apt-get install -y certbot python3-certbot-apache)
|
|
|
|
############################################################
|
|
# 0.3 - DNS CHECK
|
|
############################################################
|
|
echo "[0.3/8] Checking DNS for $FULL_DOMAIN ..."
|
|
SERVER_IP=$(curl -s https://api.ipify.org)
|
|
DOMAIN_IP=$(dig +short "$FULL_DOMAIN" | head -n1)
|
|
|
|
if [ -z "$DOMAIN_IP" ]; then
|
|
echo "❌ ERROR: Domain does not resolve."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$DOMAIN_IP" != "$SERVER_IP" ]; then
|
|
echo "❌ ERROR: DNS does not point to this server."
|
|
echo "Domain IP: $DOMAIN_IP"
|
|
echo "Server IP: $SERVER_IP"
|
|
exit 1
|
|
fi
|
|
echo "✅ DNS OK."
|
|
|
|
############################################################
|
|
# 0.4 - PORT CHECKS (host ports are global even across rootless users)
|
|
############################################################
|
|
echo "[0.4/8] Checking host ports are free..."
|
|
for p in "$PUBLIC_PORT" "$APACHE_PORT" "$TALK_PORT"; do
|
|
if ! port_free "$p"; then
|
|
echo "❌ ERROR: Port $p is already in use on the host."
|
|
ss -ltnp | grep -E ":$p\s" || true
|
|
exit 1
|
|
fi
|
|
done
|
|
echo "✅ Ports look free."
|
|
|
|
############################################################
|
|
# 1 - CREATE USER
|
|
############################################################
|
|
echo "[1/8] Creating user $USERNAME with password 12345..."
|
|
if id "$USERNAME" >/dev/null 2>&1; then
|
|
echo "User already exists. Skipping adduser."
|
|
else
|
|
adduser --gecos "" "$USERNAME" --disabled-password
|
|
echo "${USERNAME}:12345" | chpasswd
|
|
fi
|
|
|
|
############################################################
|
|
# 2 - ADD USER TO SUDO + LINGER
|
|
############################################################
|
|
echo "[2/8] Adding $USERNAME to sudo..."
|
|
usermod -aG sudo "$USERNAME" || true
|
|
|
|
echo "[2.1/8] Enabling linger for $USERNAME..."
|
|
loginctl enable-linger "$USERNAME" || true
|
|
|
|
############################################################
|
|
# 3 - CREATE VHOST
|
|
############################################################
|
|
echo "[3/8] Creating vhost $VHOST_FILE ..."
|
|
|
|
#tee "$VHOST_FILE" >/dev/null <<EOF
|
|
#<VirtualHost *:80>
|
|
# ServerName ${FULL_DOMAIN}
|
|
#
|
|
# RewriteEngine On
|
|
# RewriteCond %{HTTPS} off
|
|
# RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
|
|
#</VirtualHost>
|
|
#
|
|
#<VirtualHost *:443>
|
|
# ServerName ${FULL_DOMAIN}
|
|
#
|
|
# RewriteEngine On
|
|
# ProxyPreserveHost On
|
|
# RequestHeader set X-Real-IP %{REMOTE_ADDR}s
|
|
# AllowEncodedSlashes NoDecode
|
|
#
|
|
# ProxyPass / http://localhost:${APACHE_PORT}/ nocanon
|
|
# ProxyPassReverse / http://localhost:${APACHE_PORT}/
|
|
#
|
|
# RewriteCond %{HTTP:Upgrade} websocket [NC]
|
|
# RewriteCond %{HTTP:Connection} upgrade [NC]
|
|
# RewriteCond %{THE_REQUEST} "^[a-zA-Z]+ /(.*) HTTP/\\d+(\\.\\d+)?$"
|
|
# RewriteRule .? "ws://localhost:${APACHE_PORT}/%1" [P,L,UnsafeAllow3F]
|
|
#
|
|
# Protocols h2 h2c http/1.1
|
|
# H2WindowSize 5242880
|
|
#
|
|
# TraceEnable off
|
|
# <Files ".ht*">
|
|
# Require all denied
|
|
# </Files>
|
|
#
|
|
# LimitRequestBody 0
|
|
# Timeout 86400
|
|
# ProxyTimeout 86400
|
|
#</VirtualHost>
|
|
#EOF
|
|
|
|
############################################################
|
|
# 4 - ENABLE SITE + CERT
|
|
############################################################
|
|
echo "[4/8] Enabling site..."
|
|
#a2ensite "${FULL_DOMAIN}" >/dev/null || true
|
|
#systemctl reload apache2
|
|
#
|
|
#echo "[5/8] Running certbot..."
|
|
#if [ ! -d "/etc/letsencrypt/live/${FULL_DOMAIN}" ]; then
|
|
# certbot certonly --apache -d "${FULL_DOMAIN}"
|
|
#else
|
|
# echo "Certificate already exists. Skipping certbot."
|
|
#fi
|
|
#
|
|
#SSL_CERT="/etc/letsencrypt/live/${FULL_DOMAIN}/fullchain.pem"
|
|
#SSL_KEY="/etc/letsencrypt/live/${FULL_DOMAIN}/privkey.pem"
|
|
#
|
|
#if ! grep -q "SSLCertificateFile ${SSL_CERT}" "$VHOST_FILE"; then
|
|
# sed -i "/Protocols h2 h2c http\\/1.1/a \
|
|
## TLS\n\
|
|
#SSLEngine on\n\
|
|
#SSLProtocol -all +TLSv1.2 +TLSv1.3\n\
|
|
#SSLSessionTickets off\n\
|
|
#SSLCertificateFile ${SSL_CERT}\n\
|
|
#SSLCertificateKeyFile ${SSL_KEY}\n\
|
|
#" "$VHOST_FILE"
|
|
#fi
|
|
#systemctl reload apache2
|
|
|
|
############################################################
|
|
# 6 - CREATE install_nc.sh IN USER HOME
|
|
############################################################
|
|
echo "[6/8] Creating ${USER_SCRIPT} ..."
|
|
|
|
tee "$USER_SCRIPT" >/dev/null <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
# Always have docker available in new SSH sessions
|
|
mkdir -p "$HOME/bin"
|
|
touch "$HOME/.profile" "$HOME/.bashrc"
|
|
|
|
grep -q 'export PATH="$HOME/bin:$PATH"' "$HOME/.profile" || echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.profile"
|
|
grep -q 'export PATH="$HOME/bin:$PATH"' "$HOME/.bashrc" || echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.bashrc"
|
|
|
|
# Rootless docker env for new shells
|
|
grep -q 'export XDG_RUNTIME_DIR="/run/user/$(id -u)"' "$HOME/.bashrc" || echo 'export XDG_RUNTIME_DIR="/run/user/$(id -u)"' >> "$HOME/.bashrc"
|
|
grep -q 'export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock"' "$HOME/.bashrc" || echo 'export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock"' >> "$HOME/.bashrc"
|
|
|
|
# Apply now
|
|
export PATH="$HOME/bin:$PATH"
|
|
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
|
|
export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock"
|
|
|
|
echo "[1/3] Installing rootless Docker prerequisites..."
|
|
sudo apt-get update -y
|
|
sudo apt-get install -y uidmap dbus-user-session slirp4netns fuse-overlayfs curl
|
|
|
|
echo "[2/3] Installing rootless Docker..."
|
|
if ! curl -fsSL https://get.docker.com/rootless | sh; then
|
|
echo "⚠️ Rootless installer failed. Retrying with --skip-iptables..."
|
|
"$HOME/bin/dockerd-rootless-setuptool.sh" install --skip-iptables
|
|
fi
|
|
|
|
export PATH="$HOME/bin:$PATH"
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
echo "❌ docker client not found after install."
|
|
ls -la "$HOME/bin" || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "Enabling linger..."
|
|
sudo loginctl enable-linger "$USER" || true
|
|
|
|
echo "Starting rootless Docker..."
|
|
systemctl --user daemon-reload || true
|
|
systemctl --user enable --now docker || true
|
|
|
|
# Fallback if service isn't active
|
|
if ! systemctl --user is-active --quiet docker 2>/dev/null; then
|
|
nohup dockerd-rootless.sh >/tmp/dockerd-rootless.log 2>&1 &
|
|
fi
|
|
|
|
# Wait for socket
|
|
for i in {1..30}; do
|
|
if [ -S "$XDG_RUNTIME_DIR/docker.sock" ]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if [ ! -S "$XDG_RUNTIME_DIR/docker.sock" ]; then
|
|
echo "❌ docker.sock not found at $XDG_RUNTIME_DIR/docker.sock"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✅ Rootless docker.sock exists: $XDG_RUNTIME_DIR/docker.sock"
|
|
ls -la "$XDG_RUNTIME_DIR/docker.sock" || true
|
|
|
|
echo "[3/3] Starting Nextcloud AIO mastercontainer..."
|
|
docker rm -f nextcloud-aio-mastercontainer >/dev/null 2>&1 || true
|
|
|
|
docker run -d \
|
|
--init \
|
|
--sig-proxy=false \
|
|
--name nextcloud-aio-mastercontainer \
|
|
--restart always \
|
|
--publish __PUBLIC_PORT__:8080 \
|
|
--env APACHE_PORT=__APACHE_PORT__ \
|
|
--env TALK_PORT=__TALK_PORT__ \
|
|
--env APACHE_IP_BINDING=0.0.0.0 \
|
|
--env APACHE_ADDITIONAL_NETWORK="" \
|
|
--env SKIP_DOMAIN_VALIDATION=false \
|
|
--env AIO_DISABLE_SECURITY_CHECKS=true \
|
|
--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \
|
|
--volume "$XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock" \
|
|
ghcr.io/nextcloud-releases/all-in-one:latest
|
|
|
|
echo "✅ AIO mastercontainer started."
|
|
echo "Open: https://<SERVER-IP>:__PUBLIC_PORT__/ (IP only) and click 'Download and start containers'"
|
|
EOF
|
|
|
|
# Patch placeholders with actual ports
|
|
sed -i "s/__PUBLIC_PORT__/${PUBLIC_PORT}/g" "$USER_SCRIPT"
|
|
sed -i "s/__APACHE_PORT__/${APACHE_PORT}/g" "$USER_SCRIPT"
|
|
sed -i "s/__TALK_PORT__/${TALK_PORT}/g" "$USER_SCRIPT"
|
|
|
|
chown "$USERNAME:$USERNAME" "$USER_SCRIPT"
|
|
chmod +x "$USER_SCRIPT"
|
|
|
|
############################################################
|
|
# 7 - DONE
|
|
############################################################
|
|
echo "------------------------------------------------------------"
|
|
echo " PHASE 1 COMPLETE"
|
|
echo " Login as: $USERNAME"
|
|
echo " Run: ./install_nc.sh"
|
|
echo "------------------------------------------------------------"
|