730 lines
24 KiB
Bash
Executable File
730 lines
24 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Unified installation script for apXtri (dev and prod)
|
|
# Launching command for any environment:
|
|
# sudo apt install wget -y && sudo wget -O init.sh https://gitea.ndda.fr/apxtri/apxtri/raw/branch/main/setup/init.sh && sudo chmod +x init.sh && ./init.sh
|
|
|
|
# If you have already an install, add "--clean" at the end of the command above.
|
|
|
|
set -eEuo pipefail
|
|
trap 'err_handler $LINENO $?' ERR
|
|
|
|
# ==== CONFIG ====
|
|
URL_REPO="https://gitea.ndda.fr/apxtri"
|
|
REPO_APXTRI="$URL_REPO/apxtri.git"
|
|
REPO_OBJECTS="$URL_REPO/objects.git"
|
|
DATAPATH="/var/lib/apxtowns"
|
|
NODEPATH="/opt/apxtowns"
|
|
LOGPATH="/var/log/apxtowns"
|
|
APXTRI_USER="apxtri"
|
|
NODE_VERSION="lts"
|
|
URLBACKUP="https://app1.smatchit.io"
|
|
|
|
# Variables to be configured
|
|
NATION=""
|
|
TOWN=""
|
|
DOMAIN=""
|
|
APIPORT=""
|
|
MODE=""
|
|
|
|
# ==== LOGGING ====
|
|
sudo touch /var/log/apxtri_install.log
|
|
sudo chown "$USER":"$USER" /var/log/apxtri_install.log
|
|
exec > >(tee -i /var/log/apxtri_install.log)
|
|
exec 2>&1
|
|
|
|
# ==== ERROR HANDLER ====
|
|
err_handler() {
|
|
local lineno="$1"
|
|
local code="$2"
|
|
if [[ "$code" -eq 99 ]]; then
|
|
echo "[INFO] Installation voluntarily stopped at line $lineno (exit 99)."
|
|
exit 99
|
|
fi
|
|
echo "[ERROR] Failure at line $lineno (code $code). Starting cleanup..."
|
|
echo "[INFO] The script has stopped due to an error. Please check the logs above for details."
|
|
exit "$code"
|
|
}
|
|
|
|
# ==== CLEANING ====
|
|
cleaning() {
|
|
echo "[CLEAN] Starting cleanup..."
|
|
echo "If you need help or give back suggestion about init.sh please feel free to join in discord https://discord.gg/89Ucsnej"
|
|
# Kill any lingering process on the API port
|
|
if [[ -n "${APIPORT}" ]]; then
|
|
echo "[CLEAN] Checking for lingering processes on API port ${APIPORT}..."
|
|
sudo fuser -k "${APIPORT}/tcp" 2>/dev/null || true
|
|
fi
|
|
|
|
# Stop and disable services if they exist
|
|
sudo systemctl stop apxtri 2>/dev/null || true
|
|
sudo systemctl disable apxtri 2>/dev/null || true
|
|
sudo systemctl stop caddy 2>/dev/null || true
|
|
sudo systemctl disable caddy 2>/dev/null || true
|
|
|
|
# Remove service files
|
|
sudo rm -f /etc/systemd/system/apxtri.service
|
|
sudo rm -f /etc/systemd/system/caddy.service.d/override.conf 2>/dev/null || true
|
|
sudo systemctl daemon-reload
|
|
|
|
# Cleanup apxtri-specific files
|
|
CURRENT_USER=${SUDO_USER:-$(whoami)}
|
|
if sudo -u "$APXTRI_USER" crontab -l 2>/dev/null | grep -Fq "backup.sh"; then
|
|
sudo -u "$APXTRI_USER" crontab -l 2>/dev/null | grep -v "backup.sh" | sudo -u "$APXTRI_USER" crontab -
|
|
fi
|
|
if id -nG "$CURRENT_USER" | grep -qw "$APXTRI_USER"; then
|
|
sudo gpasswd -d "$CURRENT_USER" "$APXTRI_USER" || true
|
|
fi
|
|
if id "$APXTRI_USER" &>/dev/null; then
|
|
sudo userdel -r "$APXTRI_USER" 2>/dev/null || true
|
|
fi
|
|
if getent group "$APXTRI_USER" &>/dev/null; then
|
|
sudo groupdel "$APXTRI_USER" 2>/dev/null || true
|
|
fi
|
|
sudo rm -rf "$DATAPATH" "$NODEPATH" "$LOGPATH" /etc/apxtowns
|
|
|
|
# Clean up hosts entries
|
|
if [[ -n "${DOMAIN}" ]]; then
|
|
sudo sed -i "/${DOMAIN}/d" /etc/hosts || true
|
|
fi
|
|
|
|
# Complete Caddy cleanup
|
|
if command -v caddy &>/dev/null; then
|
|
echo "[CLEAN] Removing Caddy and its configuration..."
|
|
sudo apt-get purge -y caddy
|
|
sudo rm -rf /etc/caddy /var/lib/caddy /usr/share/caddy
|
|
sudo rm -f /etc/apt/sources.list.d/caddy-stable.list
|
|
sudo rm -f /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
fi
|
|
|
|
# Cleanup permissions and sudoers files
|
|
sudo rm -f /etc/sudoers.d/apxtri-caddy
|
|
sudo rm -rf /run/caddy
|
|
echo "[CLEAN] Cleanup complete."
|
|
}
|
|
|
|
# ==== UTILITY FUNCTIONS ====
|
|
find_free_port() {
|
|
local port=$1
|
|
while sudo lsof -Pi :$port -sTCP:LISTEN -t >/dev/null 2>&1 ; do
|
|
echo "[INFO] Port $port is in use, trying next port..."
|
|
port=$((port + 1))
|
|
done
|
|
echo "$port"
|
|
}
|
|
|
|
# ==== ARGUMENT PARSING ====
|
|
clean_install=false
|
|
|
|
# Function to display usage
|
|
usage() {
|
|
echo "Usage: $0 [--town <name>] [--nation <name>] [--domain <domain>] [--datapath <path>] [--nodepath <path>] [--apiport <port>] [--clean] [--help]"
|
|
echo " --town Set the town name. If not set, prompts interactively."
|
|
echo " --nation Set the nation name. If not set, prompts interactively."
|
|
echo " Use 'test' for dev mode, any other value for prod mode."
|
|
echo " --domain Set the domain name. Required for prod, auto-generated for dev."
|
|
echo " --datapath Set the data path (default: '/var/lib/apxtowns')."
|
|
echo " --nodepath Set the node path (default: '/opt/apxtowns')."
|
|
echo " --apiport Set the API port (default: auto-detect from 3000)."
|
|
echo " --clean Force removal of any existing installation before proceeding."
|
|
echo " --help Display this help message."
|
|
exit 1
|
|
}
|
|
|
|
# Parse command-line arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--town)
|
|
if [[ -z "$2" || "$2" == --* ]]; then echo "Error: Missing value for --town" >&2; usage; fi
|
|
TOWN="$2"
|
|
shift 2
|
|
;;
|
|
--nation)
|
|
if [[ -z "$2" || "$2" == --* ]]; then echo "Error: Missing value for --nation" >&2; usage; fi
|
|
NATION="$2"
|
|
shift 2
|
|
;;
|
|
--domain)
|
|
if [[ -z "$2" || "$2" == --* ]]; then echo "Error: Missing value for --domain" >&2; usage; fi
|
|
DOMAIN="$2"
|
|
shift 2
|
|
;;
|
|
--datapath)
|
|
if [[ -z "$2" || "$2" == --* ]]; then echo "Error: Missing value for --datapath" >&2; usage; fi
|
|
DATAPATH="$2"
|
|
shift 2
|
|
;;
|
|
--nodepath)
|
|
if [[ -z "$2" || "$2" == --* ]]; then echo "Error: Missing value for --nodepath" >&2; usage; fi
|
|
NODEPATH="$2"
|
|
shift 2
|
|
;;
|
|
--apiport)
|
|
if [[ -z "$2" || "$2" == --* ]]; then echo "Error: Missing value for --apiport" >&2; usage; fi
|
|
APIPORT="$2"
|
|
shift 2
|
|
;;
|
|
--clean)
|
|
clean_install=true
|
|
shift 1
|
|
;;
|
|
--help|-h)
|
|
usage
|
|
;;
|
|
*)
|
|
echo "Error: Unknown option $1" >&2
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# ==== CHECK EXISTING INSTALLATION ====
|
|
if [ -d "$NODEPATH" ] || [ -d "$DATAPATH" ] || { [ "$(id -u 2>/dev/null || echo)" -eq 0 ] && id "$APXTRI_USER" &>/dev/null; }; then
|
|
if [ "$clean_install" = true ]; then
|
|
echo "Existing installation detected and --clean flag was provided."
|
|
echo "Removing existing installation..."
|
|
cleaning
|
|
else
|
|
echo "[WARN] Existing apxtri installation detected."
|
|
echo "To perform a clean re-installation, please run the script again with the --clean flag."
|
|
echo "Example: $0 --clean"
|
|
echo "Aborting installation to prevent accidental data loss."
|
|
exit 99
|
|
fi
|
|
fi
|
|
|
|
# ==== INTERACTIVE PROMPTS ====
|
|
echo "============================================"
|
|
echo "apXtri Installation Configuration"
|
|
echo "============================================"
|
|
echo ""
|
|
|
|
# Prompt for TOWN if not provided
|
|
if [[ -z "$TOWN" ]]; then
|
|
read -p "Enter town name [farm]: " TOWN
|
|
TOWN=${TOWN:-farm}
|
|
fi
|
|
|
|
# Prompt for NATION if not provided
|
|
if [[ -z "$NATION" ]]; then
|
|
read -p "Enter nation name (use 'test' for dev mode) [ants]: " NATION
|
|
NATION=${NATION:-ants}
|
|
fi
|
|
|
|
# Auto-detect mode based on NATION
|
|
if [[ "$NATION" == "test" ]]; then
|
|
MODE="dev"
|
|
echo "[INFO] Detected DEV mode (nation=test)"
|
|
# Auto-generate domain for dev
|
|
if [[ -z "$DOMAIN" ]]; then
|
|
DOMAIN="admin.apxtri.${TOWN}.test"
|
|
echo "[INFO] Using local domain: $DOMAIN"
|
|
fi
|
|
else
|
|
MODE="prod"
|
|
echo "[INFO] Detected PROD mode (nation=$NATION)"
|
|
# Domain is mandatory for prod
|
|
if [[ -z "$DOMAIN" ]]; then
|
|
while [[ -z "$DOMAIN" ]]; do
|
|
read -p "Enter domain name (e.g., mytown.example.com): " DOMAIN
|
|
if [[ -z "$DOMAIN" ]]; then
|
|
echo "[ERROR] Domain is mandatory for production mode."
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# Auto-detect free port if not provided
|
|
if [[ -z "$APIPORT" ]]; then
|
|
APIPORT=$(find_free_port 3000)
|
|
echo "[INFO] Using API port: $APIPORT"
|
|
fi
|
|
|
|
echo ""
|
|
echo "---"
|
|
echo "Final configuration:"
|
|
echo " Mode: $MODE"
|
|
echo " Town: $TOWN"
|
|
echo " Nation: $NATION"
|
|
echo " Domain: $DOMAIN"
|
|
echo " API Port: $APIPORT"
|
|
echo " Data Path: $DATAPATH"
|
|
echo " Node Path: $NODEPATH"
|
|
echo "---"
|
|
echo ""
|
|
|
|
read -p "Continue with this configuration? [Y/n]: " confirm
|
|
if [[ "$confirm" =~ ^[Nn]$ ]]; then
|
|
echo "Installation cancelled."
|
|
exit 0
|
|
fi
|
|
|
|
# ==== INSTALL TOOLS ====
|
|
echo "[STEP 1/10] Installing system dependencies..."
|
|
sudo apt update --fix-missing
|
|
sudo apt install -y curl git gnupg jq build-essential locales vim libcap2-bin p7zip-full p7zip-rar unzip psmisc
|
|
|
|
# Check if no locale (can be the case with an lxc container or basic ubuntu server install)
|
|
if ! locale -a 2>/dev/null | grep -q '\.UTF-8'; then
|
|
echo "[INFO] No UTF-8 locale found, generating en_US.UTF-8..."
|
|
sudo locale-gen en_US.UTF-8
|
|
sudo update-locale LANG=en_US.UTF-8
|
|
else
|
|
echo "[INFO] UTF-8 locale already exists, no modification needed."
|
|
fi
|
|
|
|
# ==== INSTALL CADDY ====
|
|
echo "[STEP 2/10] Installing Caddy..."
|
|
if ! command -v caddy &>/dev/null; then
|
|
echo "Installing Caddy..."
|
|
sudo mkdir -p /usr/share/keyrings
|
|
sudo chmod 755 /usr/share/keyrings
|
|
|
|
sudo curl -fsSL https://dl.cloudsmith.io/public/caddy/stable/gpg.key -o /tmp/caddy-key.gpg
|
|
sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg /tmp/caddy-key.gpg
|
|
sudo chmod 644 /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
|
sudo rm -f /tmp/caddy-key.gpg
|
|
|
|
echo "deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main" | sudo tee /etc/apt/sources.list.d/caddy-stable.list
|
|
|
|
sudo apt update && sudo apt install -y caddy
|
|
else
|
|
echo "Caddy already installed."
|
|
fi
|
|
|
|
# ==== HOSTS CONFIGURATION ====
|
|
echo "[STEP 3/10] Configuring /etc/hosts..."
|
|
if [[ "$NATION" == "test" ]]; then
|
|
# For dev mode, add local domain to /etc/hosts
|
|
if ! grep -q "$DOMAIN" /etc/hosts; then
|
|
echo "127.0.0.1 $DOMAIN" | sudo tee -a /etc/hosts
|
|
echo "[INFO] Added $DOMAIN to /etc/hosts"
|
|
else
|
|
echo "[INFO] $DOMAIN already in /etc/hosts"
|
|
fi
|
|
else
|
|
# For prod mode, verify DNS resolution
|
|
if host "$DOMAIN" &>/dev/null; then
|
|
echo "[INFO] Domain $DOMAIN resolves correctly"
|
|
else
|
|
echo "[WARN] Domain $DOMAIN does not resolve. Make sure DNS is configured correctly."
|
|
echo "[INFO] Adding to /etc/hosts for local testing..."
|
|
if ! grep -q "$DOMAIN" /etc/hosts; then
|
|
echo "127.0.0.1 $DOMAIN" | sudo tee -a /etc/hosts
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# ==== CREATE USER ====
|
|
echo "[STEP 4/10] Creating system user..."
|
|
if ! id "$APXTRI_USER" &>/dev/null; then
|
|
echo "Creating system user $APXTRI_USER..."
|
|
sudo useradd --system --no-create-home --shell /usr/sbin/nologin "$APXTRI_USER"
|
|
echo "$APXTRI_USER:$APXTRI_USER" | sudo chpasswd
|
|
else
|
|
echo "User $APXTRI_USER already exists."
|
|
fi
|
|
|
|
# ==== CONFIGURE CADDY SERVICE ====
|
|
echo "[STEP 5/10] Configuring Caddy service..."
|
|
sudo rm -f /etc/systemd/system/caddy.service.d/override.conf
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl start caddy || true
|
|
|
|
# ==== ADD USERS TO APXTRI GROUP ====
|
|
CURRENT_USER=${SUDO_USER:-$(whoami)}
|
|
sudo usermod -aG "$APXTRI_USER" "$CURRENT_USER"
|
|
sudo usermod -aG "$APXTRI_USER" caddy
|
|
|
|
# ==== CREATE DIRECTORIES ====
|
|
echo "[STEP 6/10] Creating directories..."
|
|
sudo mkdir -p "$NODEPATH/$TOWN-$NATION" "$LOGPATH" "$DATAPATH/data/apxtri/logs" "$DATAPATH/data/apxtri/tmp" "$NODEPATH/$TOWN-$NATION/apxtri/tmp"
|
|
sudo chown -R "$APXTRI_USER:$APXTRI_USER" "$DATAPATH" "$NODEPATH" "$LOGPATH" "$NODEPATH/$TOWN-$NATION/apxtri/tmp"
|
|
sudo chmod -R g+rwX "$NODEPATH" "$DATAPATH"
|
|
|
|
# ==== SET GROUP INHERITANCE FOR WWWS ====
|
|
echo "Configuring group permission inheritance for Caddy on wwws directories..."
|
|
sudo find "$DATAPATH" -type d -name "wwws" -exec chmod g+s {} + 2>/dev/null || true
|
|
sudo find "$DATAPATH" -type d -name "wwws" -exec chmod -R g+rX {} + 2>/dev/null || true
|
|
|
|
# ==== CLONE REPOSITORIES ====
|
|
echo "[STEP 7/10] Cloning repositories..."
|
|
# Clone objects repo first
|
|
sudo -u "$APXTRI_USER" mkdir -p "$DATAPATH/data/apxtri/objects"
|
|
sudo -u "$APXTRI_USER" git clone "$REPO_OBJECTS" "$DATAPATH/data/apxtri/objects" || {
|
|
echo "[WARN] Objects repository clone failed or already exists, continuing..."
|
|
}
|
|
sudo -u "$APXTRI_USER" git config --global --add safe.directory "$DATAPATH/data/apxtri/objects" || true
|
|
|
|
# Download and extract setup files
|
|
|
|
TAR_URL="$URL_REPO/apxtri/raw/branch/main/setup/setup.apxtri.objects.tar.gz"
|
|
TAR_FILE="$DATAPATH/data/apxtri/setup.apxtri.objects.tar.gz"
|
|
|
|
sudo -u "$APXTRI_USER" bash -c "cd /tmp && wget -O '$TAR_FILE' '$TAR_URL'" || {
|
|
echo "[WARN] Failed to download setup zip, continuing..."
|
|
}
|
|
|
|
sudo -u "$APXTRI_USER" bash -c "
|
|
mkdir -p '$DATAPATH/data/apxtri/objects' && \
|
|
tar -xzf '$TAR_FILE' -C '$DATAPATH/data/apxtri/objects'" || {
|
|
echo "[WARN] Failed to extract .tar.gz, continuing..."
|
|
}
|
|
sudo rm -f "$TAR_FILE"
|
|
|
|
# Clone main repo
|
|
if [ -d "$NODEPATH/$TOWN-$NATION/apxtri" ]; then
|
|
echo "[INFO] Removing existing apxtri directory for clean clone..."
|
|
sudo rm -rf "$NODEPATH/$TOWN-$NATION/apxtri"
|
|
fi
|
|
sudo -u "$APXTRI_USER" git clone "$REPO_APXTRI" "$NODEPATH/$TOWN-$NATION/apxtri"
|
|
sudo -u "$APXTRI_USER" git config --global --add safe.directory "$NODEPATH/$TOWN-$NATION/apxtri" || true
|
|
|
|
# ==== CREATE ENV FILE ====
|
|
echo "[STEP 8/10] Creating environment configuration..."
|
|
sudo tee "$NODEPATH/$TOWN-$NATION/apxtri/.env" > /dev/null <<EOL
|
|
URL_REPO="$URL_REPO"
|
|
VERSION="1.0.0"
|
|
MODE="$MODE"
|
|
TOWN="$TOWN"
|
|
NATION="$NATION"
|
|
DOMAIN="$DOMAIN"
|
|
UBUNTU="server"
|
|
ETCCONF="/etc/apxtowns/apxtowns"
|
|
DATAPATH="$DATAPATH"
|
|
NODEPATH="$NODEPATH"
|
|
LOGPATH="$LOGPATH"
|
|
APIPORT="$APIPORT"
|
|
ACTIVELOG=apxtri,isAuthenticated,checkHeaders,Odmdb,Pagans,Persons,Wwws,Trackings,Notifications
|
|
##debug,info,warn,error, debug and info will be shown only if a name.js is in ACTIVELOG to help to be focus in debugging
|
|
LOG_LEVEL=debug
|
|
EXPOSEDHEADERS="xdays,xalias,xlang,xtribe,xapp,xuuid"
|
|
SOCKETPORT="$((APIPORT + 1))"
|
|
BACKENDURL="localhost"
|
|
CADDYAPIURL="http://localhost:2019"
|
|
BLOCKCHAIN_CONNECT=false
|
|
PRIVKMAYOR=""
|
|
EOL
|
|
sudo chown "$APXTRI_USER:$APXTRI_USER" "$NODEPATH/$TOWN-$NATION/apxtri/.env"
|
|
|
|
# ==== INSTALL NVM + NODE ====
|
|
echo "[STEP 9/10] Installing Node.js via NVM..."
|
|
npm_config_cache="${DATAPATH:-/tmp}/.npm"
|
|
sudo mkdir -p "$npm_config_cache"
|
|
sudo chown -R "$APXTRI_USER:$APXTRI_USER" "$npm_config_cache"
|
|
NVM_DIR="$NODEPATH/$TOWN-$NATION/apxtri/.nvm"
|
|
|
|
sudo -u "$APXTRI_USER" HOME="$NODEPATH/$TOWN-$NATION/apxtri" DATAPATH="$DATAPATH" NODE_VERSION="$NODE_VERSION" npm_config_cache="$npm_config_cache" NVM_DIR="$NVM_DIR" bash <<EOF
|
|
set -euo pipefail
|
|
if [ ! -d "$NVM_DIR" ]; then
|
|
echo "Installing NVM..."
|
|
git clone https://github.com/nvm-sh/nvm.git "$NVM_DIR"
|
|
cd "$NVM_DIR"
|
|
git checkout master
|
|
else
|
|
echo "NVM already installed in $NVM_DIR"
|
|
fi
|
|
|
|
chmod +x "$NVM_DIR/nvm.sh"
|
|
|
|
export NVM_DIR="$NVM_DIR"
|
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
nvm install --lts
|
|
nvm alias default 'lts/*'
|
|
nvm use default
|
|
npm install -g npm@latest
|
|
|
|
cd "$NODEPATH/$TOWN-$NATION/apxtri"
|
|
if [ -f package.json ]; then
|
|
echo "Installing npm dependencies..."
|
|
npm install
|
|
fi
|
|
EOF
|
|
#=== Add symlink to main_modules for tailwindcss to work properly
|
|
ln -s "$NODEPATH/$TOWN-$NATION/apxtri/node_modules/" "$NODEPATH/main_modules"
|
|
|
|
#==
|
|
|
|
# ==== CREATE SYSTEMD SERVICE (BOTH DEV AND PROD) ====
|
|
echo "[STEP 10/10] Creating systemd service..."
|
|
SERVICE_PATH="/etc/systemd/system/apxtri.service"
|
|
|
|
if [[ "$MODE" == "dev" ]]; then
|
|
# Dev mode: tee output to log file for easier access
|
|
LOG_FILE="$DATAPATH/data/apxtri/logs/dev.log"
|
|
sudo tee "$SERVICE_PATH" > /dev/null <<EOF
|
|
[Unit]
|
|
Description=apXtri development service
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=$APXTRI_USER
|
|
Group=$APXTRI_USER
|
|
WorkingDirectory=$NODEPATH/$TOWN-$NATION/apxtri
|
|
EnvironmentFile=$NODEPATH/$TOWN-$NATION/apxtri/.env
|
|
ExecStart=/bin/bash -lc "source $NODEPATH/$TOWN-$NATION/apxtri/.nvm/nvm.sh && npm run dev 2>&1 | tee -a $LOG_FILE"
|
|
ExecStop=/bin/bash -lc "pkill -u $APXTRI_USER -f 'node.*apxtri.js'"
|
|
Restart=on-failure
|
|
RestartSec=5s
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
else
|
|
# Prod mode: also tee output to log file
|
|
LOG_FILE="$DATAPATH/data/apxtri/logs/prod.log"
|
|
sudo tee "$SERVICE_PATH" > /dev/null <<EOF
|
|
[Unit]
|
|
Description=apXtri production service
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=$APXTRI_USER
|
|
Group=$APXTRI_USER
|
|
WorkingDirectory=$NODEPATH/$TOWN-$NATION/apxtri
|
|
EnvironmentFile=$NODEPATH/$TOWN-$NATION/apxtri/.env
|
|
ExecStart=/bin/bash -lc "source $NODEPATH/$TOWN-$NATION/apxtri/.nvm/nvm.sh && npm run prod 2>&1 | tee -a $LOG_FILE"
|
|
ExecStop=/bin/bash -lc "pkill -u $APXTRI_USER -f 'node.*apxtri.js'"
|
|
Restart=on-failure
|
|
RestartSec=5s
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
fi
|
|
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable apxtri
|
|
sudo systemctl start apxtri
|
|
|
|
# ==== CREATE HELPER SCRIPTS ====
|
|
echo "Creating helper scripts..."
|
|
|
|
# Create apxdev script (works for both modes but most useful in dev)
|
|
SCRIPT_PATH="/usr/local/bin/apxdev"
|
|
cat <<EOF | sudo tee $SCRIPT_PATH > /dev/null
|
|
#!/bin/bash
|
|
# apxdev - apXtri development helper
|
|
# Usage: apxdev [command]
|
|
# Commands:
|
|
# start - Start the apxtri service
|
|
# stop - Stop the apxtri service
|
|
# restart - Restart the apxtri service
|
|
# logs - Show logs (file and journalctl)
|
|
# status - Show service status
|
|
# (no arg) - Restart and follow logs
|
|
|
|
MODE="\$(grep MODE= $NODEPATH/$TOWN-$NATION/apxtri/.env | cut -d= -f2 | tr -d '"')"
|
|
LOG_FILE="$DATAPATH/data/apxtri/logs/\${MODE}.log"
|
|
|
|
case "\${1:-restart}" in
|
|
start)
|
|
sudo systemctl start apxtri
|
|
echo "apXtri started. View logs with: apxdev logs"
|
|
;;
|
|
stop)
|
|
sudo systemctl stop apxtri
|
|
echo "apXtri stopped."
|
|
;;
|
|
restart)
|
|
echo "Restarting apXtri..."
|
|
sudo systemctl restart apxtri
|
|
sleep 2
|
|
tail -f "\$LOG_FILE"
|
|
;;
|
|
logs)
|
|
echo "=== Recent journalctl logs ==="
|
|
sudo journalctl -u apxtri -n 50 --no-pager
|
|
echo ""
|
|
echo "=== Following log file: \$LOG_FILE ==="
|
|
tail -f "\$LOG_FILE"
|
|
;;
|
|
status)
|
|
sudo systemctl status apxtri --no-pager
|
|
;;
|
|
*)
|
|
echo "Usage: apxdev [start|stop|restart|logs|status]"
|
|
echo " start - Start the service"
|
|
echo " stop - Stop the service"
|
|
echo " restart - Restart and follow logs (default)"
|
|
echo " logs - Show recent logs and follow"
|
|
echo " status - Show service status"
|
|
exit 1
|
|
;;
|
|
esac
|
|
EOF
|
|
sudo chmod +x $SCRIPT_PATH
|
|
|
|
# Create apxgeminicli script
|
|
SCRIPT_PATH="/usr/local/bin/apxgeminicli"
|
|
cat <<EOF | sudo tee $SCRIPT_PATH > /dev/null
|
|
#!/bin/bash
|
|
# apxgeminicli - Run Gemini CLI in apxtri context
|
|
# Add your gemini key in $NODEPATH/$TOWN-$NATION/apxtri/.env
|
|
# GEMINI_API_KEY=your_key_here
|
|
|
|
sudo -u apxtri env HOME="$NODEPATH/$TOWN-$NATION/apxtri" bash -c 'cd "$NODEPATH/$TOWN-$NATION/apxtri" && source .nvm/nvm.sh && nvm use default && npx @google/gemini-cli'
|
|
EOF
|
|
sudo chmod +x $SCRIPT_PATH
|
|
|
|
# Create apxtailwind script
|
|
SCRIPT_PATH="/usr/local/bin/apxtailwind"
|
|
cat <<'EOF' | sudo tee $SCRIPT_PATH > /dev/null
|
|
#!/bin/bash
|
|
# apxtailwind - Run Tailwind CSS compiler
|
|
# Usage: apxtailwind <tribe> <appname> [extra args...]
|
|
set -euo pipefail
|
|
|
|
if [[ $# -lt 2 ]]; then
|
|
echo "Usage: $0 <tribe> <appname> [extra args...]"
|
|
exit 1
|
|
fi
|
|
|
|
TRIBE="$1"
|
|
APPNAME="$2"
|
|
shift 2
|
|
|
|
BASE_DIR="__NODEPATH__/__TOWN__-__NATION__/${TRIBE}"
|
|
CSS_IN="__DATAPATH__/data/${TRIBE}/objects/wwws/${APPNAME}/src/static/css/input.css"
|
|
CSS_OUT="__DATAPATH__/data/${TRIBE}/objects/wwws/${APPNAME}/src/static/css/output.css"
|
|
|
|
sudo -u apxtri env HOME="${BASE_DIR}" bash -c '
|
|
cd ~ &&
|
|
source .nvm/nvm.sh &&
|
|
nvm use default &&
|
|
npx @tailwindcss/cli -i "'"${CSS_IN}"'" -o "'"${CSS_OUT}"'" "$@"
|
|
' _ "$@"
|
|
EOF
|
|
|
|
# Replace placeholders with actual values from the main script
|
|
sudo sed -i "s|__NODEPATH__|$NODEPATH|g" "$SCRIPT_PATH"
|
|
sudo sed -i "s|__DATAPATH__|$DATAPATH|g" "$SCRIPT_PATH"
|
|
sudo sed -i "s|__NATION__|$NATION|g" "$SCRIPT_PATH"
|
|
sudo sed -i "s|__TOWN__|$TOWN|g" "$SCRIPT_PATH"
|
|
sudo chmod +x $SCRIPT_PATH
|
|
|
|
|
|
# ==== CONFIGURE CRONTABS ====
|
|
echo "Configuring crontab for automated tasks..."
|
|
|
|
# Make scripts executable
|
|
sudo chmod +x "$NODEPATH/$TOWN-$NATION/apxtri/setup/update.sh"
|
|
sudo chmod +x "$NODEPATH/$TOWN-$NATION/apxtri/setup/backup.sh"
|
|
|
|
# Get current user (the one who ran sudo)
|
|
CRON_USER=${SUDO_USER:-$(whoami)}
|
|
|
|
# Define cron jobs (will run as current user with sudo)
|
|
UPDATE_CRON="0 3 * * * $NODEPATH/$TOWN-$NATION/apxtri/setup/update.sh >> $DATAPATH/data/apxtri/logs/update.log 2>&1"
|
|
BACKUP_CRON="0 1 * * * $NODEPATH/$TOWN-$NATION/apxtri/setup/backup.sh apxtri setup nations,towns,pagans >> $DATAPATH/data/apxtri/logs/backup.log 2>&1"
|
|
|
|
# Get existing crontab
|
|
TEMP_CRON=$(mktemp)
|
|
crontab -l 2>/dev/null > "$TEMP_CRON" || true
|
|
|
|
# Remove all existing /opt/apxtowns entries
|
|
sed -i '\|/opt/apxtowns|d' "$TEMP_CRON"
|
|
echo "[INFO] Removed all existing /opt/apxtowns cron entries"
|
|
|
|
# Add new cron jobs
|
|
echo "$UPDATE_CRON" >> "$TEMP_CRON"
|
|
echo "[INFO] Added update.sh cron job (daily at 03:00) for user $CRON_USER"
|
|
|
|
echo "$BACKUP_CRON" >> "$TEMP_CRON"
|
|
echo "[INFO] Added backup.sh cron job (daily at 01:00) for user $CRON_USER"
|
|
|
|
# Install the crontab for current user
|
|
crontab "$TEMP_CRON"
|
|
rm -f "$TEMP_CRON"
|
|
|
|
echo "[INFO] Crontab configured successfully for user $CRON_USER"
|
|
echo " - Update check: Daily at 03:00 AM"
|
|
echo " - Backup: Daily at 01:00 AM (setup backup)"
|
|
|
|
# ==== FINAL MESSAGE ====
|
|
echo
|
|
echo "============================================"
|
|
echo "INSTALLATION COMPLETE"
|
|
echo "============================================"
|
|
echo ""
|
|
echo "Configuration Summary:"
|
|
echo " Mode: $MODE"
|
|
echo " Town: $TOWN"
|
|
echo " Nation: $NATION"
|
|
echo " Domain: $DOMAIN"
|
|
echo " API Port: $APIPORT"
|
|
echo " Data Path: $DATAPATH"
|
|
echo " Node Path: $NODEPATH"
|
|
echo ""
|
|
|
|
# Get network info
|
|
LAN_IP=$(hostname -I | awk '{print $1}')
|
|
PUBLIC_IP=$(curl -s http://icanhazip.com || echo "Failed to retrieve")
|
|
echo "Network Information:"
|
|
echo " LAN IP: $LAN_IP"
|
|
echo " Public IP: $PUBLIC_IP"
|
|
echo ""
|
|
|
|
echo "Service Management:"
|
|
echo " Start: sudo systemctl start apxtri"
|
|
echo " Stop: sudo systemctl stop apxtri"
|
|
echo " Restart: sudo systemctl restart apxtri"
|
|
echo " Status: sudo systemctl status apxtri"
|
|
echo ""
|
|
|
|
echo "Log Access:"
|
|
echo " File: tail -f $DATAPATH/data/apxtri/logs/${MODE}.log"
|
|
echo " Journal: sudo journalctl -u apxtri -f"
|
|
echo ""
|
|
|
|
echo "Helper Commands:"
|
|
echo " apxdev - Quick restart and log viewing"
|
|
echo " apxgeminicli - Run Gemini CLI"
|
|
echo " apxtailwind - Run Tailwind CSS compiler"
|
|
echo ""
|
|
|
|
if [[ "$MODE" == "dev" ]]; then
|
|
echo "[DEV MODE SETUP]"
|
|
echo "1. Exit this terminal to refresh your group permissions"
|
|
echo "2. Open VS Code: code $NODEPATH"
|
|
echo "3. Add workspace folder: File > Add Folder to Workspace > $DATAPATH"
|
|
echo "4. Start development: apxdev"
|
|
echo ""
|
|
echo "Development URL: http://$DOMAIN:$APIPORT"
|
|
echo ""
|
|
echo "⚠️ User $CURRENT_USER was added to group $APXTRI_USER"
|
|
echo " Run 'newgrp $APXTRI_USER' or log out/in for permissions to take effect"
|
|
else
|
|
echo "[PROD MODE SETUP]"
|
|
echo "apXtri is now running as a systemd service"
|
|
echo "Access your application at: https://$DOMAIN"
|
|
echo ""
|
|
echo "⚠️ IMPORTANT SECURITY STEPS:"
|
|
echo " 1. Change the password for user $APXTRI_USER: sudo passwd $APXTRI_USER"
|
|
echo " 2. Configure firewall rules if needed"
|
|
echo " 3. Review and secure $NODEPATH/$TOWN-$NATION/apxtri/.env"
|
|
fi
|
|
|
|
echo ""
|
|
echo "Automated Tasks (Crontab for user $CURRENT_USER):"
|
|
echo " Update: Daily at 03:00 AM - Checks for updates and applies minor/patch versions"
|
|
echo " Backup: Daily at 01:00 AM - Creates setup backup"
|
|
echo " View crons: crontab -l"
|
|
echo " Update log: tail -f $DATAPATH/data/apxtri/logs/update.log"
|
|
echo " Backup log: tail -f $DATAPATH/data/apxtri/logs/backup.log"
|
|
echo ""
|
|
|
|
echo "Next Steps:"
|
|
echo "1. Complete the town setup by accessing the admin interface"
|
|
echo "2. Monitor automated backups in $DATAPATH/data/apxtri/backups/"
|
|
echo "3. Check logs for any issues"
|
|
echo ""
|
|
echo "For help or feedback: https://discord.gg/89Ucsnej"
|
|
echo "============================================"
|