- 'websitebox up' now automatically runs 'docker compose up -d' - 'websitebox logs' now automatically runs 'docker compose logs -f' - All other commands pass through unchanged - Added 'source ~/.bashrc' instruction at end of installer so the command works immediately without logout/login - Updated tips and setup summary to show simplified commands Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
307 lines
10 KiB
Bash
Executable File
307 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
set -eo pipefail
|
|
|
|
# WebsiteBox Setup Wizard
|
|
# Generates .env file and creates data directories
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# --- Colors and formatting ---
|
|
BOLD='\033[1m'
|
|
DIM='\033[2m'
|
|
RESET='\033[0m'
|
|
RED='\033[1;31m'
|
|
GREEN='\033[1;32m'
|
|
YELLOW='\033[1;33m'
|
|
ORANGE='\033[1;38;5;208m'
|
|
CYAN='\033[1;36m'
|
|
BLUE='\033[1;34m'
|
|
WHITE='\033[1;37m'
|
|
|
|
printf "\n${WHITE}═══════════════════════════════════════════════════════════${RESET}\n"
|
|
printf " ${BOLD}WebsiteBox Setup Wizard${RESET}\n"
|
|
printf "${WHITE}═══════════════════════════════════════════════════════════${RESET}\n\n"
|
|
|
|
# --- Prerequisite Checks ---
|
|
|
|
check_command() {
|
|
if ! command -v "$1" &>/dev/null; then
|
|
printf "${RED} ✗ $1 is not installed.${RESET}\n"
|
|
printf "${RED} $2${RESET}\n"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_command docker "Install Docker: https://docs.docker.com/engine/install/"
|
|
|
|
if ! docker compose version &>/dev/null; then
|
|
printf "${RED} ✗ Docker Compose (v2) is not available.${RESET}\n"
|
|
printf "${RED} Install it: https://docs.docker.com/compose/install/${RESET}\n"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if Docker is accessible
|
|
if ! docker info &>/dev/null; then
|
|
printf "${RED} ✗ Cannot connect to Docker daemon.${RESET}\n"
|
|
printf "${RED} Make sure Docker is running and your user has permission.${RESET}\n"
|
|
printf "${RED} You may need to: sudo usermod -aG docker \$USER && newgrp docker${RESET}\n"
|
|
exit 1
|
|
fi
|
|
|
|
# Check ports
|
|
for port in 80 443; do
|
|
if ss -tlnp 2>/dev/null | grep -q ":${port} " || netstat -tlnp 2>/dev/null | grep -q ":${port} "; then
|
|
printf "${YELLOW} ⚠ Port ${port} is already in use.${RESET}\n"
|
|
printf "${YELLOW} Another service may need to be stopped first.${RESET}\n"
|
|
read -rp "Continue anyway? (y/N) " cont
|
|
if [ "$cont" != "y" ] && [ "$cont" != "Y" ]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# --- Generate Random Strings ---
|
|
|
|
generate_password() {
|
|
local length="${1:-32}"
|
|
openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | head -c "$length"
|
|
}
|
|
|
|
generate_salt() {
|
|
openssl rand -base64 48 | head -c 64
|
|
}
|
|
|
|
# --- Collect Configuration ---
|
|
|
|
printf "Please provide the following configuration:\n\n"
|
|
|
|
# Domain
|
|
while true; do
|
|
printf "${BLUE}Domain name${RESET} (e.g., example.com): "
|
|
read -r DOMAIN
|
|
if [[ "$DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z]{2,})+$ ]]; then
|
|
break
|
|
fi
|
|
printf "${RED} Invalid domain format. Please enter a valid domain (e.g., example.com)${RESET}\n"
|
|
done
|
|
|
|
# Site title
|
|
printf "${BLUE}Site title${RESET} [My Portfolio]: "
|
|
read -r SITE_TITLE
|
|
SITE_TITLE="${SITE_TITLE:-My Portfolio}"
|
|
|
|
# Admin username
|
|
while true; do
|
|
printf "${BLUE}WordPress admin username${RESET}: "
|
|
read -r ADMIN_USER
|
|
if [ -z "$ADMIN_USER" ]; then
|
|
printf "${RED} Username cannot be empty.${RESET}\n"
|
|
continue
|
|
fi
|
|
if [ "$ADMIN_USER" = "admin" ]; then
|
|
printf "${YELLOW} For security, please choose a username other than 'admin'.${RESET}\n"
|
|
continue
|
|
fi
|
|
break
|
|
done
|
|
|
|
# Admin email
|
|
while true; do
|
|
printf "${BLUE}Admin email${RESET} (used for SSL & WordPress): "
|
|
read -r ADMIN_EMAIL
|
|
if [[ "$ADMIN_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
|
|
break
|
|
fi
|
|
printf "${RED} Please enter a valid email address.${RESET}\n"
|
|
done
|
|
|
|
# Admin password
|
|
echo ""
|
|
printf "${BLUE}Set your WordPress admin password.${RESET}\n"
|
|
printf "${DIM} Press Enter to auto-generate a secure 20-character password.${RESET}\n"
|
|
printf "${DIM} Note: your password won't appear on screen as you type — that's normal.${RESET}\n"
|
|
while true; do
|
|
printf "${BLUE}Admin password${RESET}: "
|
|
read -rs ADMIN_PASSWORD
|
|
echo ""
|
|
if [ -z "$ADMIN_PASSWORD" ]; then
|
|
ADMIN_PASSWORD=$(generate_password 20)
|
|
PASSWORD_AUTO_GENERATED=true
|
|
printf "${GREEN} ✓ Password auto-generated.${RESET}\n"
|
|
break
|
|
fi
|
|
if [ ${#ADMIN_PASSWORD} -lt 12 ]; then
|
|
printf "${RED} Password must be at least 12 characters.${RESET}\n"
|
|
continue
|
|
fi
|
|
printf "${BLUE}Confirm password${RESET}: "
|
|
read -rs ADMIN_PASSWORD_CONFIRM
|
|
echo ""
|
|
if [ "$ADMIN_PASSWORD" != "$ADMIN_PASSWORD_CONFIRM" ]; then
|
|
printf "${RED} Passwords do not match. Try again.${RESET}\n"
|
|
continue
|
|
fi
|
|
PASSWORD_AUTO_GENERATED=false
|
|
printf "${GREEN} ✓ Password set.${RESET}\n"
|
|
break
|
|
done
|
|
|
|
# Age Gate
|
|
echo ""
|
|
printf "${BLUE}Enable age verification gate?${RESET} (Y/n): "
|
|
read -r AGE_GATE_INPUT
|
|
if [ "$AGE_GATE_INPUT" = "n" ] || [ "$AGE_GATE_INPUT" = "N" ]; then
|
|
AGE_GATE_ENABLED=false
|
|
AGE_GATE_MIN_AGE=18
|
|
else
|
|
AGE_GATE_ENABLED=true
|
|
printf "${BLUE}Minimum age${RESET} (18-21) [18]: "
|
|
read -r AGE_GATE_MIN_AGE
|
|
AGE_GATE_MIN_AGE="${AGE_GATE_MIN_AGE:-18}"
|
|
if [ "$AGE_GATE_MIN_AGE" -lt 18 ] 2>/dev/null || [ "$AGE_GATE_MIN_AGE" -gt 21 ] 2>/dev/null; then
|
|
printf "${YELLOW} Invalid age. Using default: 18${RESET}\n"
|
|
AGE_GATE_MIN_AGE=18
|
|
fi
|
|
fi
|
|
|
|
# SMTP (optional)
|
|
echo ""
|
|
printf "${BLUE}SMTP server${RESET} (if you don't know what this is, press Enter to skip): "
|
|
read -r SMTP_HOST
|
|
SMTP_PORT=587
|
|
SMTP_USER=""
|
|
SMTP_PASS=""
|
|
SMTP_FROM=""
|
|
if [ -n "$SMTP_HOST" ]; then
|
|
printf "${BLUE}SMTP port${RESET} [587]: "
|
|
read -r SMTP_PORT_INPUT
|
|
SMTP_PORT="${SMTP_PORT_INPUT:-587}"
|
|
printf "${BLUE}SMTP username${RESET}: "
|
|
read -r SMTP_USER
|
|
printf "${BLUE}SMTP password${RESET}: "
|
|
read -rs SMTP_PASS
|
|
echo ""
|
|
printf "${BLUE}SMTP from address${RESET} [${ADMIN_EMAIL}]: "
|
|
read -r SMTP_FROM_INPUT
|
|
SMTP_FROM="${SMTP_FROM_INPUT:-$ADMIN_EMAIL}"
|
|
fi
|
|
|
|
# Backup retention
|
|
printf "${BLUE}Days to keep local backups${RESET} (1-365) [30]: "
|
|
read -r BACKUP_RETENTION_DAYS
|
|
BACKUP_RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-30}"
|
|
|
|
# --- Auto-generated Values ---
|
|
|
|
DB_NAME="websitebox"
|
|
DB_USER="websitebox"
|
|
DB_PASSWORD=$(generate_password 32)
|
|
DB_ROOT_PASSWORD=$(generate_password 32)
|
|
|
|
AUTH_KEY=$(generate_salt)
|
|
SECURE_AUTH_KEY=$(generate_salt)
|
|
LOGGED_IN_KEY=$(generate_salt)
|
|
NONCE_KEY=$(generate_salt)
|
|
AUTH_SALT=$(generate_salt)
|
|
SECURE_AUTH_SALT=$(generate_salt)
|
|
LOGGED_IN_SALT=$(generate_salt)
|
|
NONCE_SALT=$(generate_salt)
|
|
|
|
# --- Write .env File ---
|
|
|
|
cat > .env <<ENVEOF
|
|
# WebsiteBox Configuration — Generated by setup.sh
|
|
# $(date)
|
|
|
|
DOMAIN='${DOMAIN}'
|
|
SITE_TITLE='${SITE_TITLE//\'/\'\\\'\'}'
|
|
ADMIN_USER='${ADMIN_USER}'
|
|
ADMIN_EMAIL='${ADMIN_EMAIL}'
|
|
ADMIN_PASSWORD='${ADMIN_PASSWORD//\'/\'\\\'\'}'
|
|
|
|
DB_NAME='${DB_NAME}'
|
|
DB_USER='${DB_USER}'
|
|
DB_PASSWORD='${DB_PASSWORD}'
|
|
DB_ROOT_PASSWORD='${DB_ROOT_PASSWORD}'
|
|
|
|
AGE_GATE_ENABLED=${AGE_GATE_ENABLED}
|
|
AGE_GATE_MIN_AGE=${AGE_GATE_MIN_AGE}
|
|
|
|
SMTP_HOST='${SMTP_HOST}'
|
|
SMTP_PORT=${SMTP_PORT}
|
|
SMTP_USER='${SMTP_USER}'
|
|
SMTP_PASS='${SMTP_PASS//\'/\'\\\'\'}'
|
|
SMTP_FROM='${SMTP_FROM}'
|
|
|
|
BACKUP_RETENTION_DAYS=${BACKUP_RETENTION_DAYS}
|
|
|
|
AUTH_KEY='${AUTH_KEY}'
|
|
SECURE_AUTH_KEY='${SECURE_AUTH_KEY}'
|
|
LOGGED_IN_KEY='${LOGGED_IN_KEY}'
|
|
NONCE_KEY='${NONCE_KEY}'
|
|
AUTH_SALT='${AUTH_SALT}'
|
|
SECURE_AUTH_SALT='${SECURE_AUTH_SALT}'
|
|
LOGGED_IN_SALT='${LOGGED_IN_SALT}'
|
|
NONCE_SALT='${NONCE_SALT}'
|
|
ENVEOF
|
|
|
|
chmod 600 .env
|
|
|
|
# --- Create Data Directories ---
|
|
|
|
mkdir -p websitebox-data/{wordpress,database,certs,certbot-webroot,certbot-signal,backups}
|
|
|
|
# --- Save Auto-generated Password ---
|
|
|
|
if [ "$PASSWORD_AUTO_GENERATED" = true ]; then
|
|
cat > .credentials <<CREDEOF
|
|
# WebsiteBox Admin Credentials
|
|
# DELETE THIS FILE after recording your password somewhere secure.
|
|
#
|
|
# Username: ${ADMIN_USER}
|
|
# Password: ${ADMIN_PASSWORD}
|
|
CREDEOF
|
|
chmod 600 .credentials
|
|
fi
|
|
|
|
# --- Get Server IP ---
|
|
|
|
SERVER_IP=$(curl -s -4 ifconfig.me 2>/dev/null || curl -s -4 icanhazip.com 2>/dev/null || echo "YOUR_SERVER_IP")
|
|
|
|
# --- Print Summary ---
|
|
|
|
printf "\n${WHITE}═══════════════════════════════════════════════════════════${RESET}\n"
|
|
printf " ${GREEN}${BOLD}WebsiteBox Setup Complete!${RESET}\n"
|
|
printf "${WHITE}═══════════════════════════════════════════════════════════${RESET}\n\n"
|
|
printf " ${GREEN}✓${RESET} Configuration saved to ${BOLD}.env${RESET}\n\n"
|
|
printf " ${BOLD}Next steps:${RESET}\n\n"
|
|
printf " ${BLUE}1.${RESET} ${BOLD}Point your domain's A record to this server${RESET}\n"
|
|
printf " Log in to your domain registrar and add a DNS record:\n"
|
|
printf " ${DIM}Type:${RESET} A\n"
|
|
printf " ${DIM}Name:${RESET} @ ${DIM}(this means the root domain, e.g., ${DOMAIN})${RESET}\n"
|
|
printf " ${DIM}Value:${RESET} ${BOLD}${SERVER_IP}${RESET} ${DIM}(your server's IP address)${RESET}\n"
|
|
printf " ${DIM}TTL:${RESET} Auto ${DIM}(or the lowest option available)${RESET}\n\n"
|
|
printf " ${BLUE}2.${RESET} ${BOLD}Wait for DNS propagation, then verify it's working${RESET}\n"
|
|
printf " Copy this command into the server terminal:\n\n"
|
|
printf " ${CYAN}dig ${DOMAIN} +short${RESET}\n\n"
|
|
printf " ${GREEN}✓ Success looks like:${RESET} ${BOLD}${SERVER_IP}${RESET}\n"
|
|
printf " ${RED}✗ Not ready yet:${RESET} ${DIM}(blank output or a different IP — wait a few minutes and try again)${RESET}\n\n"
|
|
printf " ${BLUE}3.${RESET} ${BOLD}Launch your website${RESET}\n"
|
|
printf " Once DNS is working, copy this command into the server terminal:\n\n"
|
|
printf " ${CYAN}websitebox up${RESET}\n\n"
|
|
printf " ${BLUE}4.${RESET} ${BOLD}Visit your site${RESET}\n"
|
|
printf " Your website: ${CYAN}https://${DOMAIN}${RESET}\n"
|
|
printf " Admin login: ${CYAN}https://${DOMAIN}/wp-admin${RESET}\n"
|
|
printf " Username: ${BOLD}${ADMIN_USER}${RESET}\n"
|
|
|
|
if [ "$PASSWORD_AUTO_GENERATED" = true ]; then
|
|
printf " Password: ${BOLD}${ADMIN_PASSWORD}${RESET}\n\n"
|
|
printf " ${YELLOW}⚠${RESET} Your auto-generated password has also been saved to: ${BOLD}.credentials${RESET}\n"
|
|
printf " Delete this file after recording your password somewhere secure.\n"
|
|
else
|
|
printf " Password: ${DIM}(the password you set during setup)${RESET}\n"
|
|
fi
|
|
|
|
printf "\n${WHITE}═══════════════════════════════════════════════════════════${RESET}\n"
|