How much does a WordPress website cost?

2»

Comments

  • bikegremlinbikegremlin ModeratorOGContent Writer

    @somik said:

    @bikegremlin said:
    Sums it up well - though my eye starts twitching when I hear "Bluehost" - LOL :)

    Who here, on the low end sites, have never used hosts like bluehost, 25mb host, 000webhosting and all those crappy sites?

    Yup.
    bikegremlin.com was first registered with 1-and-1 for $1 for the first year (then I read the terms, saw the renewal price, and moved it in time to Namecheap, and a few years after that to Porkbun).

    Hosting was first with a suspiciously cheap shared hosting provider (unlimited all LOL), that got sold to Justhost (which was owned by the Bluehost umbrella company). And it took a while to figure out how the hosting is not very good.

    It took me a while to realize that time is the most limited resource and that I should pay a bit more to not worry about hosting, and spend the time (and effort) on writing articles.

    Similar goes for WordPress itself - while it is free and open source, it has its costs in terms of both time and money, depending on what you're using it for.

  • vyasvyas OGSenpai
    edited August 17

    Thanks**

    To this discussion, I spent a couple of hours with chatGPT and grok last night, while visiting a family member at an assisted living facility. (Story for another time)...

    I now have hopefully working scripts for installing ClassicPress (or WordPress if you prefer) on Debian, using Caddy/ Lighttpd and Openlitespeed as the "control" for LES Budget friendly specs.

    Idea came up when I asked chatGPT "why do installer scripts like Webinoly only support Ubuntu? Why can't i get something with Debian 12 (or 13) ? Pasting the "optimized version" of the conversation and the script below. As always, comments and feedback appreciated. I might do an actual testing later in the day.

    What this script is supposed to do:

    • Support Interactive or Defaults mode.

    • Support Dry-run mode (simulate everything; do not change the system).

    • Run pre-flight checks (OS, RAM, CPU, free disk) and warn if low — but allow continuing.

    • Prompt for domain, admin user/email/password (defaults if Enter), install path (default /var/www/classicpress), DB prefix (default cp1_).

    • Install only required packages (skip if already installed) and show progress messages.

    • Install WP-CLI, download ClassicPress, set permissions, generate wp-config.php via WP-CLI, run the ClassicPress install non-interactively.

    • Install optional plugins/themes via WP-CLI (defaults pre-set but editable).

    • Configure SSL:

    • Caddy: automatic (Caddy handles TLS once DNS points).

    • OLS: uses certbot to obtain cert (script checks DNS).

    • Print final summary (login URL, admin creds, DB creds, paths).

    • Plenty of inline comments and terminal output so you can follow what is happening.

    Note: these scripts attempt to be conservative and safe. Always review before running on a production machine. Run first in --dry-run to verify.

    The Script itself: simplenote link - http://simp.ly/p/KMkQVp

    Or read below at your own scrolling risk:

    Example: Classic Press + Caddy

    Save as install_cp_caddy.sh, then
    $ chmod +x install_cp_caddy.sh, and finally, run with
    $ sudo ./install_cp_caddy.sh.


    <

    pre>

    !/usr/bin/env bash

    set -euo pipefail
    IFS=$'\n\t'

    -------------------------

    Defaults & Configurable Vars

    -------------------------

    DEFAULT_DOMAIN="example.com"
    DEFAULT_ADMIN_USER="admin"
    DEFAULT_ADMIN_EMAIL="[email protected]"
    DEFAULT_INSTALL_FOLDER="classicpress"
    DEFAULT_WEBROOT_BASE="/var/www"
    DEFAULT_DB_PREFIX="cp1"
    PHP_VERSION="8.3"
    MIN_DISK_GB=5
    MIN_RAM_MB=1024

    Default plugin/theme lists (empty by default; edit if you want auto-install)

    DEFAULT_PLUGINS=("classic-editor") # Example; add slugs you want
    DEFAULT_THEMES=()

    -------------------------

    Helper functions

    -------------------------

    log() { echo -e "\e[1;34m[ INFO ]\e[0m $"; }
    warn() { echo -e "\e[1;33m[ WARN ]\e[0m $
    "; }
    err() { echo -e "\e[1;31m[ ERROR ]\e[0m $*"; }

    confirm() {
    # prompt with default no
    read -p "$1 (y/N): " ans
    [[ "$ans" == "y" || "$ans" == "Y" ]]
    }

    command_exists() { command -v "$1" >/dev/null 2>&1; }

    -------------------------

    CLI flags: --dry-run

    -------------------------

    DRY_RUN=false
    while [[ $# -gt 0 ]]; do
    case $1 in
    --dry-run) DRY_RUN=true; shift ;;
    --help) echo "Usage: sudo $0 [--dry-run]"; exit 0 ;;
    *) echo "Unknown arg: $1"; exit 1 ;;
    esac
    done

    -------------------------

    Mode selection: interactive or defaults

    -------------------------

    echo "ClassicPress + Caddy Installer"
    echo "Interactive or defaults?"
    echo " 1) Interactive (step-by-step prompts)"
    echo " 2) Defaults (use sensible defaults, minimal prompts)"
    read -p "Choose mode [1-2, default 1]: " MODE_CHOICE
    MODE_CHOICE=${MODE_CHOICE:-1}

    INTERACTIVE=true
    if [[ "$MODE_CHOICE" == "2" ]]; then
    INTERACTIVE=false
    fi

    Dry-run message

    if $DRY_RUN; then
    log "DRY RUN mode enabled — no changes will be made."
    fi

    -------------------------

    Pre-flight checks

    -------------------------

    log "Running pre-flight checks..."

    OS check (Debian)

    if [ -f /etc/debian_version ]; then
    OS_NAME="Debian"
    OS_VER=$(cat /etc/debian_version)
    log "Detected OS: $OS_NAME $OS_VER"
    else
    err "This installer is intended for Debian. Aborting."
    exit 1
    fi

    Hardware checks (warn, not abort)

    TOTAL_RAM_MB=$(free -m | awk '/^Mem:/{print $2}')
    FREE_DISK_GB=$(df -BG --output=avail / | tail -1 | tr -dc '0-9')
    CPU_CORES=$(nproc)

    if (( TOTAL_RAM_MB < MIN_RAM_MB )); then
    warn "Detected RAM: ${TOTAL_RAM_MB} MB — recommended >= ${MIN_RAM_MB} MB."
    if ! confirm "Proceed anyway?"; then
    log "User aborted due to low RAM."
    exit 1
    fi
    fi

    if (( FREE_DISK_GB < MIN_DISK_GB )); then
    warn "Detected free disk: ${FREE_DISK_GB} GB — recommended >= ${MIN_DISK_GB} GB."
    if ! confirm "Proceed anyway?"; then
    log "User aborted due to low disk."
    exit 1
    fi
    fi

    log "CPU cores: $CPU_CORES; RAM: ${TOTAL_RAM_MB} MB; Free disk: ${FREE_DISK_GB} GB"

    -------------------------

    Interactive prompts (or defaults)

    -------------------------

    if $INTERACTIVE; then
    read -p "Enter domain (FQDN) [${DEFAULT_DOMAIN}]: " DOMAIN
    DOMAIN=${DOMAIN:-$DEFAULT_DOMAIN}
    read -p "Install folder name [${DEFAULT_INSTALL_FOLDER}]: " FOLDER_NAME
    FOLDER_NAME=${FOLDER_NAME:-$DEFAULT_INSTALL_FOLDER}
    read -p "Admin username [${DEFAULT_ADMIN_USER}]: " ADMIN_USER
    ADMIN_USER=${ADMIN_USER:-$DEFAULT_ADMIN_USER}
    read -p "Admin email [${DEFAULT_ADMIN_EMAIL}]: " ADMIN_EMAIL
    ADMIN_EMAIL=${ADMIN_EMAIL:-$DEFAULT_ADMIN_EMAIL}
    read -p "Admin password (leave blank to auto-generate): " ADMIN_PASS
    if [[ -z "$ADMIN_PASS" ]]; then
    ADMIN_PASS=$(openssl rand -base64 12)
    log "Generated admin password: $ADMIN_PASS"
    fi
    read -p "DB prefix [${DEFAULT_DB_PREFIX}]: " DB_PREFIX
    DB_PREFIX=${DB_PREFIX:-$DEFAULT_DB_PREFIX}
    read -p "Use MariaDB (y) or SQLite (n)? [y]: " DB_CHOICE
    DB_CHOICE=${DB_CHOICE:-y}
    if [[ "$DB_CHOICE" == "y" || "$DB_CHOICE" == "Y" ]]; then
    DB_ENGINE="mariadb"
    else
    DB_ENGINE="sqlite"
    fi
    read -p "Install default plugins? (classic-editor) [y/N]: " INSTALL_PLUGINS_ANS
    INSTALL_PLUGINS=false
    if [[ "$INSTALL_PLUGINS_ANS" == "y" || "$INSTALL_PLUGINS_ANS" == "Y" ]]; then
    INSTALL_PLUGINS=true
    fi
    else
    # defaults
    DOMAIN=$DEFAULT_DOMAIN
    FOLDER_NAME=$DEFAULT_INSTALL_FOLDER
    ADMIN_USER=$DEFAULT_ADMIN_USER
    ADMIN_EMAIL=$DEFAULT_ADMIN_EMAIL
    ADMIN_PASS=$(openssl rand -base64 12)
    DB_PREFIX=$DEFAULT_DB_PREFIX
    DB_ENGINE="mariadb"
    INSTALL_PLUGINS=false
    fi

    WEBROOT="${DEFAULT_WEBROOT_BASE}/${FOLDER_NAME}"
    DB_NAME="${DB_PREFIX}db"
    DB_USER="${DB_PREFIX}user"
    DB_PASS=$(openssl rand -base64 16)

    log "Summary of choices:"
    echo " Domain: $DOMAIN"
    echo " Webroot: $WEBROOT"
    echo " Admin: $ADMIN_USER / $ADMIN_EMAIL"
    echo " DB engine: $DB_ENGINE"
    echo " DB name/user: $DB_NAME / $DB_USER"
    echo " Install plugins/themes: $INSTALL_PLUGINS"
    echo " PHP version target: $PHP_VERSION"

    if $DRY_RUN; then
    echo
    log "DRY RUN summary complete. No changes will be made."
    exit 0
    fi

    -------------------------

    Install prerequisites (only what is missing)

    -------------------------

    log "Installing prerequisites (only missing packages)..."

    Add Sury repo for PHP 8.3 if needed

    if ! command_exists php || [[ "$(php -r 'echo PHP_VERSION;')" != "$PHP_VERSION"* ]]; then
    log "Installing PHP ${PHP_VERSION} and extensions..."
    apt update
    apt install -y ca-certificates apt-transport-https lsb-release gnupg
    echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/sury-php.list
    wget -qO - https://packages.sury.org/php/apt.gpg | gpg --dearmor -o /usr/share/keyrings/sury-php.gpg
    apt update
    apt install -y "php${PHP_VERSION}" "php${PHP_VERSION}-fpm" "php${PHP_VERSION}-mysql" \
    "php${PHP_VERSION}-xml" "php${PHP_VERSION}-mbstring" "php${PHP_VERSION}-curl" \
    "php${PHP_VERSION}-zip" "php${PHP_VERSION}-gd" unzip wget curl
    else
    log "PHP ${PHP_VERSION} appears installed."
    fi

    Caddy installation (official)

    if ! command_exists caddy; then
    log "Installing Caddy..."
    apt install -y debian-keyring debian-archive-keyring apt-transport-https
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
    apt update
    apt install -y caddy
    else
    log "Caddy already installed."
    fi

    Database

    if [[ "$DB_ENGINE" == "mariadb" ]]; then
    if ! command_exists mysql; then
    log "Installing MariaDB..."
    apt install -y mariadb-server mariadb-client
    log "Securing MariaDB (interactive may appear)..."
    # attempt non-interactive secure install: set root auth to unix_socket (Debian default)
    # create DB and user later
    else
    log "MariaDB present."
    fi
    else
    log "SQLite selected; PHP sqlite extension will be used."
    apt install -y "php${PHP_VERSION}-sqlite3"
    fi

    WP-CLI

    if ! command_exists wp; then
    log "Installing wp-cli..."
    curl -sO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    php wp-cli.phar --info >/dev/null 2>&1 || true
    chmod +x wp-cli.phar
    mv wp-cli.phar /usr/local/bin/wp
    else
    log "wp-cli present."
    fi

    -------------------------

    Database setup

    -------------------------

    if [[ "$DB_ENGINE" == "mariadb" ]]; then
    log "Creating database and user..."
    mysql -e "CREATE DATABASE IF NOT EXISTS `${DB_NAME}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
    mysql -e "CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';"
    mysql -e "GRANT ALL PRIVILEGES ON `${DB_NAME}`.* TO '${DB_USER}'@'localhost';"
    mysql -e "FLUSH PRIVILEGES;"
    log "Database ${DB_NAME} and user ${DB_USER} created."
    fi

    -------------------------

    Download and place ClassicPress

    -------------------------

    log "Downloading ClassicPress..."
    mkdir -p "$WEBROOT"
    cd /tmp
    CP_RELEASE_URL="https://github.com/ClassicPress/ClassicPress-release/archive/refs/tags/1.6.3.tar.gz"
    wget -qO cp.tar.gz "$CP_RELEASE_URL"
    tar -xzf cp.tar.gz
    shopt -s dotglob
    mv ClassicPress-release-/ "$WEBROOT"/
    rm -rf /tmp/ClassicPress-release-* cp.tar.gz
    shopt -u dotglob

    log "Setting ownership and permissions..."
    chown -R www-data:www-data "$WEBROOT"
    find "$WEBROOT" -type d -exec chmod 755 {} \;
    find "$WEBROOT" -type f -exec chmod 644 {} \;

    -------------------------

    Caddy config

    -------------------------

    log "Creating Caddyfile for ${DOMAIN}..."
    cat > /etc/caddy/Caddyfile <<EOF
    ${DOMAIN} {
    root * ${WEBROOT}
    encode gzip zstd
    php_fastcgi unix//run/php/php${PHP_VERSION}-fpm.sock
    file_server
    }
    EOF

    log "Reloading Caddy..."
    systemctl reload caddy || systemctl restart caddy

    -------------------------

    ClassicPress install via WP-CLI

    -------------------------

    log "Preparing wp-config.php and running site install..."

    Create wp-config.php via wp-cli using DB engine chosen

    if [[ "$DB_ENGINE" == "mariadb" ]]; then
    wp config create --path="$WEBROOT" --dbname="$DB_NAME" --dbuser="$DB_USER" --dbpass="$DB_PASS" --dbhost="localhost" --dbprefix="${DB_PREFIX}_" --skip-check --allow-root
    else
    # use SQLite db.php drop-in approach
    # ensure php sqlite extension present
    WP_DB_DIR="$WEBROOT/wp-content/database"
    mkdir -p "$WP_DB_DIR"
    chown -R www-data:www-data "$WP_DB_DIR"
    # download db.php drop-in if available (wp-sqlite-db)
    wget -qO "$WEBROOT/wp-content/db.php" "https://raw.githubusercontent.com/aaemnnosttv/wp-sqlite-db/v1.3.2/src/db.php"
    wp config create --path="$WEBROOT" --skip-check --allow-root
    fi

    Install the site

    wp core install --path="$WEBROOT" --url="https://${DOMAIN}" --title="ClassicPress Site" --admin_user="${ADMIN_USER}" --admin_password="${ADMIN_PASS}" --admin_email="${ADMIN_EMAIL}" --skip-email --allow-root

    log "Installing default plugins/themes if requested..."
    if $INSTALL_PLUGINS; then
    for pl in "${DEFAULT_PLUGINS[@]}"; do
    wp plugin install "$pl" --activate --path="$WEBROOT" --allow-root || warn "Failed to install plugin $pl"
    done
    fi
    for th in "${DEFAULT_THEMES[@]}"; do
    wp theme install "$th" --activate --path="$WEBROOT" --allow-root || warn "Failed to install theme $th"
    done

    -------------------------

    SSL (Caddy auto handles TLS) and reminder

    -------------------------

    log "Caddy will manage TLS automatically when DNS for ${DOMAIN} points to this server's IP."
    log "If DNS is not yet pointed, TLS will be obtained automatically when it is."

    -------------------------

    Final summary

    -------------------------

    echo

    echo "===================================================="

    echo " ClassicPress install complete (Caddy mode)"
    echo " Domain: https://${DOMAIN}"
    echo " Admin user: ${ADMIN_USER}"
    echo " Admin password: ${ADMIN_PASS}"
    if [[ "$DB_ENGINE" == "mariadb" ]]; then
    echo " DB: ${DB_NAME} / ${DB_USER} / ${DB_PASS}"
    else
    echo " DB: SQLite (file stored in wp-content/database by default)"
    fi
    echo " Webroot: ${WEBROOT}"
    echo " Caddyfile: /etc/caddy/Caddyfile"
    echo " WP-CLI: /usr/local/bin/wp"

    echo "===================================================="

    Note

    1. ** (or not - if you ask my wife)

    2. The usual questions came to mind- why not github repo/ Why not use pastebin, etc... before I posted the script here. Anyways, formatting in vanilla drove me nuts.

    3. Since much of the code was AI tested/ suggested, not sure about license either. Lets' call it a bored middle aged man project license.
      (gosh, am I really that old? OR MAybe.. use it ONLY if you are that old..lol)

    4. Sorry @bikegremlin, did not meant to hijack thread.

    Thanked by (1)bikegremlin
  • bikegremlinbikegremlin ModeratorOGContent Writer

    @vyas said:
    Thanks**

    To this discussion, I spent a couple of hours with chatGPT and grok last night, while visiting a family member at an assisted living facility. (Story for another time)...

    I now have hopefully working scripts for installing ClassicPress (or WordPress if you prefer) on Debian, using Caddy/ Lighttpd and Openlitespeed as the "control" for LES Budget friendly specs.

    Idea came up when I asked chatGPT "why do installer scripts like Webinoly only support Ubuntu? Why can't i get something with Debian 12 (or 13) ? Pasting the "optimized version" of the conversation and the script below. As always, comments and feedback appreciated. I might do an actual testing later in the day.

    What this script is supposed to do:

    • Support Interactive or Defaults mode.

    • Support Dry-run mode (simulate everything; do not change the system).

    • Run pre-flight checks (OS, RAM, CPU, free disk) and warn if low — but allow continuing.

    • Prompt for domain, admin user/email/password (defaults if Enter), install path (default /var/www/classicpress), DB prefix (default cp1_).

    • Install only required packages (skip if already installed) and show progress messages.

    • Install WP-CLI, download ClassicPress, set permissions, generate wp-config.php via WP-CLI, run the ClassicPress install non-interactively.

    • Install optional plugins/themes via WP-CLI (defaults pre-set but editable).

    • Configure SSL:

    • Caddy: automatic (Caddy handles TLS once DNS points).

    • OLS: uses certbot to obtain cert (script checks DNS).

    • Print final summary (login URL, admin creds, DB creds, paths).

    • Plenty of inline comments and terminal output so you can follow what is happening.

    Note: these scripts attempt to be conservative and safe. Always review before running on a production machine. Run first in --dry-run to verify.

    The Script itself: simplenote link - http://simp.ly/p/KMkQVp

    Or read below at your own scrolling risk:

    Example: Classic Press + Caddy

    Save as install_cp_caddy.sh, then
    $ chmod +x install_cp_caddy.sh, and finally, run with
    $ sudo ./install_cp_caddy.sh.


    > 
    > ####!/usr/bin/env bash
    > 
    > set -euo pipefail
    > IFS=$'\n\t'
    > 
    > # -------------------------
    > 
    > ##### Defaults & Configurable Vars
    > 
    > # -------------------------
    > 
    > DEFAULT_DOMAIN="example.com"
    > DEFAULT_ADMIN_USER="admin"
    > DEFAULT_ADMIN_EMAIL="[email protected]"
    > DEFAULT_INSTALL_FOLDER="classicpress"
    > DEFAULT_WEBROOT_BASE="/var/www"
    > DEFAULT_DB_PREFIX="cp1"
    > PHP_VERSION="8.3"
    > MIN_DISK_GB=5
    > MIN_RAM_MB=1024
    > 
    > # Default plugin/theme lists (empty by default; edit if you want auto-install)
    > DEFAULT_PLUGINS=("classic-editor")   # Example; add slugs you want
    > DEFAULT_THEMES=()
    > 
    > # -------------------------
    > 
    > ###### Helper functions
    > 
    > # -------------------------
    > log() { echo -e "\e[1;34m[ INFO ]\e[0m $*"; }
    > warn() { echo -e "\e[1;33m[ WARN ]\e[0m $*"; }
    > err() { echo -e "\e[1;31m[ ERROR ]\e[0m $*"; }
    > 
    > confirm() {
    >   # prompt with default no
    >   read -p "$1 (y/N): " ans
    >   [[ "$ans" == "y" || "$ans" == "Y" ]]
    > }
    > 
    > command_exists() { command -v "$1" >/dev/null 2>&1; }
    > 
    > # -------------------------
    > 
    > ##### CLI flags: --dry-run
    > 
    > # -------------------------
    > 
    > DRY_RUN=false
    > while [[ $# -gt 0 ]]; do
    >   case $1 in
    >     --dry-run) DRY_RUN=true; shift ;;
    >     --help) echo "Usage: sudo $0 [--dry-run]"; exit 0 ;;
    >     *) echo "Unknown arg: $1"; exit 1 ;;
    >   esac
    > done
    > 
    > # -------------------------
    > 
    > ##### Mode selection: interactive or defaults
    > 
    > # -------------------------
    > 
    > echo "ClassicPress + Caddy Installer"
    > echo "Interactive or defaults?"
    > echo "  1) Interactive (step-by-step prompts)"
    > echo "  2) Defaults (use sensible defaults, minimal prompts)"
    > read -p "Choose mode [1-2, default 1]: " MODE_CHOICE
    > MODE_CHOICE=${MODE_CHOICE:-1}
    > 
    > INTERACTIVE=true
    > if [[ "$MODE_CHOICE" == "2" ]]; then
    >   INTERACTIVE=false
    > fi
    > 
    > # Dry-run message
    > if $DRY_RUN; then
    >   log "DRY RUN mode enabled — no changes will be made."
    > fi
    > 
    > # -------------------------
    > 
    > ##### Pre-flight checks
    > 
    > # -------------------------
    > 
    > log "Running pre-flight checks..."
    > 
    > #### OS check (Debian)
    > if [ -f /etc/debian_version ]; then
    >   OS_NAME="Debian"
    >   OS_VER=$(cat /etc/debian_version)
    >   log "Detected OS: $OS_NAME $OS_VER"
    > else
    >   err "This installer is intended for Debian. Aborting."
    >   exit 1
    > fi
    > 
    > ##### Hardware checks (warn, not abort)
    > TOTAL_RAM_MB=$(free -m | awk '/^Mem:/{print $2}')
    > FREE_DISK_GB=$(df -BG --output=avail / | tail -1 | tr -dc '0-9')
    > CPU_CORES=$(nproc)
    > 
    > if (( TOTAL_RAM_MB < MIN_RAM_MB )); then
    >   warn "Detected RAM: ${TOTAL_RAM_MB} MB — recommended >= ${MIN_RAM_MB} MB."
    >   if ! confirm "Proceed anyway?"; then
    >     log "User aborted due to low RAM."
    >     exit 1
    >   fi
    > fi
    > 
    > if (( FREE_DISK_GB < MIN_DISK_GB )); then
    >   warn "Detected free disk: ${FREE_DISK_GB} GB — recommended >= ${MIN_DISK_GB} GB."
    >   if ! confirm "Proceed anyway?"; then
    >     log "User aborted due to low disk."
    >     exit 1
    >   fi
    > fi
    > 
    > log "CPU cores: $CPU_CORES; RAM: ${TOTAL_RAM_MB} MB; Free disk: ${FREE_DISK_GB} GB"
    > 
    > # -------------------------
    > 
    > ##### Interactive prompts (or defaults)
    > 
    > # -------------------------
    > 
    > if $INTERACTIVE; then
    >   read -p "Enter domain (FQDN) [${DEFAULT_DOMAIN}]: " DOMAIN
    >   DOMAIN=${DOMAIN:-$DEFAULT_DOMAIN}
    >   read -p "Install folder name [${DEFAULT_INSTALL_FOLDER}]: " FOLDER_NAME
    >   FOLDER_NAME=${FOLDER_NAME:-$DEFAULT_INSTALL_FOLDER}
    >   read -p "Admin username [${DEFAULT_ADMIN_USER}]: " ADMIN_USER
    >   ADMIN_USER=${ADMIN_USER:-$DEFAULT_ADMIN_USER}
    >   read -p "Admin email [${DEFAULT_ADMIN_EMAIL}]: " ADMIN_EMAIL
    >   ADMIN_EMAIL=${ADMIN_EMAIL:-$DEFAULT_ADMIN_EMAIL}
    >   read -p "Admin password (leave blank to auto-generate): " ADMIN_PASS
    >   if [[ -z "$ADMIN_PASS" ]]; then
    >     ADMIN_PASS=$(openssl rand -base64 12)
    >     log "Generated admin password: $ADMIN_PASS"
    >   fi
    >   read -p "DB prefix [${DEFAULT_DB_PREFIX}]: " DB_PREFIX
    >   DB_PREFIX=${DB_PREFIX:-$DEFAULT_DB_PREFIX}
    >   read -p "Use MariaDB (y) or SQLite (n)? [y]: " DB_CHOICE
    >   DB_CHOICE=${DB_CHOICE:-y}
    >   if [[ "$DB_CHOICE" == "y" || "$DB_CHOICE" == "Y" ]]; then
    >     DB_ENGINE="mariadb"
    >   else
    >     DB_ENGINE="sqlite"
    >   fi
    >   read -p "Install default plugins? (classic-editor) [y/N]: " INSTALL_PLUGINS_ANS
    >   INSTALL_PLUGINS=false
    >   if [[ "$INSTALL_PLUGINS_ANS" == "y" || "$INSTALL_PLUGINS_ANS" == "Y" ]]; then
    >     INSTALL_PLUGINS=true
    >   fi
    > else
    >   # defaults
    >   DOMAIN=$DEFAULT_DOMAIN
    >   FOLDER_NAME=$DEFAULT_INSTALL_FOLDER
    >   ADMIN_USER=$DEFAULT_ADMIN_USER
    >   ADMIN_EMAIL=$DEFAULT_ADMIN_EMAIL
    >   ADMIN_PASS=$(openssl rand -base64 12)
    >   DB_PREFIX=$DEFAULT_DB_PREFIX
    >   DB_ENGINE="mariadb"
    >   INSTALL_PLUGINS=false
    > fi
    > 
    > WEBROOT="${DEFAULT_WEBROOT_BASE}/${FOLDER_NAME}"
    > DB_NAME="${DB_PREFIX}db"
    > DB_USER="${DB_PREFIX}user"
    > DB_PASS=$(openssl rand -base64 16)
    > 
    > log "Summary of choices:"
    > echo " Domain: $DOMAIN"
    > echo " Webroot: $WEBROOT"
    > echo " Admin: $ADMIN_USER / $ADMIN_EMAIL"
    > echo " DB engine: $DB_ENGINE"
    > echo " DB name/user: $DB_NAME / $DB_USER"
    > echo " Install plugins/themes: $INSTALL_PLUGINS"
    > echo " PHP version target: $PHP_VERSION"
    > 
    > if $DRY_RUN; then
    >   echo
    >   log "DRY RUN summary complete. No changes will be made."
    >   exit 0
    > fi
    > 
    > # -------------------------
    > 
    > ##### Install prerequisites (only what is missing)
    > 
    > # -------------------------
    > 
    > log "Installing prerequisites (only missing packages)..."
    > ##### Add Sury repo for PHP 8.3 if needed
    > if ! command_exists php || [[ "$(php -r 'echo PHP_VERSION;')" != "$PHP_VERSION"* ]]; then
    >   log "Installing PHP ${PHP_VERSION} and extensions..."
    >   apt update
    >   apt install -y ca-certificates apt-transport-https lsb-release gnupg
    >   echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/sury-php.list
    >   wget -qO - https://packages.sury.org/php/apt.gpg | gpg --dearmor -o /usr/share/keyrings/sury-php.gpg
    >   apt update
    >   apt install -y "php${PHP_VERSION}" "php${PHP_VERSION}-fpm" "php${PHP_VERSION}-mysql" \
    >     "php${PHP_VERSION}-xml" "php${PHP_VERSION}-mbstring" "php${PHP_VERSION}-curl" \
    >     "php${PHP_VERSION}-zip" "php${PHP_VERSION}-gd" unzip wget curl
    > else
    >   log "PHP ${PHP_VERSION} appears installed."
    > fi
    > 
    > ##### Caddy installation (official)
    > if ! command_exists caddy; then
    >   log "Installing Caddy..."
    >   apt install -y debian-keyring debian-archive-keyring apt-transport-https
    >   curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable.gpg
    >   curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
    >   apt update
    >   apt install -y caddy
    > else
    >   log "Caddy already installed."
    > fi
    > 
    > #### Database
    > if [[ "$DB_ENGINE" == "mariadb" ]]; then
    >   if ! command_exists mysql; then
    >     log "Installing MariaDB..."
    >     apt install -y mariadb-server mariadb-client
    >     log "Securing MariaDB (interactive may appear)..."
    >     # attempt non-interactive secure install: set root auth to unix_socket (Debian default)
    >     # create DB and user later
    >   else
    >     log "MariaDB present."
    >   fi
    > else
    >   log "SQLite selected; PHP sqlite extension will be used."
    >   apt install -y "php${PHP_VERSION}-sqlite3"
    > fi
    > 
    > #### WP-CLI
    > if ! command_exists wp; then
    >   log "Installing wp-cli..."
    >   curl -sO https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    >   php wp-cli.phar --info >/dev/null 2>&1 || true
    >   chmod +x wp-cli.phar
    >   mv wp-cli.phar /usr/local/bin/wp
    > else
    >   log "wp-cli present."
    > fi
    > 
    > # -------------------------
    > 
    > ##### Database setup
    > 
    > # -------------------------
    > 
    > if [[ "$DB_ENGINE" == "mariadb" ]]; then
    >   log "Creating database and user..."
    >   mysql -e "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
    >   mysql -e "CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';"
    >   mysql -e "GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';"
    >   mysql -e "FLUSH PRIVILEGES;"
    >   log "Database ${DB_NAME} and user ${DB_USER} created."
    > fi
    > 
    > # -------------------------
    > 
    > ##### Download and place ClassicPress
    > 
    > # -------------------------
    > 
    > log "Downloading ClassicPress..."
    > mkdir -p "$WEBROOT"
    > cd /tmp
    > CP_RELEASE_URL="https://github.com/ClassicPress/ClassicPress-release/archive/refs/tags/1.6.3.tar.gz"
    > wget -qO cp.tar.gz "$CP_RELEASE_URL"
    > tar -xzf cp.tar.gz
    > shopt -s dotglob
    > mv ClassicPress-release-*/* "$WEBROOT"/
    > rm -rf /tmp/ClassicPress-release-* cp.tar.gz
    > shopt -u dotglob
    > 
    > log "Setting ownership and permissions..."
    > chown -R www-data:www-data "$WEBROOT"
    > find "$WEBROOT" -type d -exec chmod 755 {} \;
    > find "$WEBROOT" -type f -exec chmod 644 {} \;
    > 
    > # -------------------------
    > 
    > ##### Caddy config
    > 
    > # -------------------------
    > 
    > log "Creating Caddyfile for ${DOMAIN}..."
    > cat > /etc/caddy/Caddyfile <<EOF
    > ${DOMAIN} {
    >     root * ${WEBROOT}
    >     encode gzip zstd
    >     php_fastcgi unix//run/php/php${PHP_VERSION}-fpm.sock
    >     file_server
    > }
    > EOF
    > 
    > log "Reloading Caddy..."
    > systemctl reload caddy || systemctl restart caddy
    > 
    > # -------------------------
    > 
    > ##### ClassicPress install via WP-CLI
    > 
    > # -------------------------
    > 
    > log "Preparing wp-config.php and running site install..."
    > # Create wp-config.php via wp-cli using DB engine chosen
    > if [[ "$DB_ENGINE" == "mariadb" ]]; then
    >   wp config create --path="$WEBROOT" --dbname="$DB_NAME" --dbuser="$DB_USER" --dbpass="$DB_PASS" --dbhost="localhost" --dbprefix="${DB_PREFIX}_" --skip-check --allow-root
    > else
    >   # use SQLite db.php drop-in approach
    >   # ensure php sqlite extension present
    >   WP_DB_DIR="$WEBROOT/wp-content/database"
    >   mkdir -p "$WP_DB_DIR"
    >   chown -R www-data:www-data "$WP_DB_DIR"
    >   # download db.php drop-in if available (wp-sqlite-db)
    >   wget -qO "$WEBROOT/wp-content/db.php" "https://raw.githubusercontent.com/aaemnnosttv/wp-sqlite-db/v1.3.2/src/db.php"
    >   wp config create --path="$WEBROOT" --skip-check --allow-root
    > fi
    > 
    > #### Install the site
    > wp core install --path="$WEBROOT" --url="https://${DOMAIN}" --title="ClassicPress Site" --admin_user="${ADMIN_USER}" --admin_password="${ADMIN_PASS}" --admin_email="${ADMIN_EMAIL}" --skip-email --allow-root
    > 
    > log "Installing default plugins/themes if requested..."
    > if $INSTALL_PLUGINS; then
    >   for pl in "${DEFAULT_PLUGINS[@]}"; do
    >     wp plugin install "$pl" --activate --path="$WEBROOT" --allow-root || warn "Failed to install plugin $pl"
    >   done
    > fi
    > for th in "${DEFAULT_THEMES[@]}"; do
    >   wp theme install "$th" --activate --path="$WEBROOT" --allow-root || warn "Failed to install theme $th"
    > done
    > 
    > # -------------------------
    > ##### SSL (Caddy auto handles TLS) and reminder
    > 
    > # -------------------------
    > 
    > log "Caddy will manage TLS automatically when DNS for ${DOMAIN} points to this server's IP."
    > log "If DNS is not yet pointed, TLS will be obtained automatically when it is."
    > 
    > # -------------------------
    > 
    > ##### Final summary
    > 
    > # -------------------------
    > 
    > echo
    > 
    > echo "===================================================="
    > 
    > echo " ClassicPress install complete (Caddy mode)"
    > echo " Domain: https://${DOMAIN}"
    > echo " Admin user: ${ADMIN_USER}"
    > echo " Admin password: ${ADMIN_PASS}"
    > if [[ "$DB_ENGINE" == "mariadb" ]]; then
    >   echo " DB: ${DB_NAME} / ${DB_USER} / ${DB_PASS}"
    > else
    >   echo " DB: SQLite (file stored in wp-content/database by default)"
    > fi
    > echo " Webroot: ${WEBROOT}"
    > echo " Caddyfile: /etc/caddy/Caddyfile"
    > echo " WP-CLI: /usr/local/bin/wp"
    > 
    > echo "===================================================="
    > 
    > 

    Note

    1. ** (or not - if you ask my wife)

    2. The usual questions came to mind- why not github repo/ Why not use pastebin, etc... before I posted the script here. Anyways, formatting in vanilla drove me nuts.

    3. Since much of the code was AI tested/ suggested, not sure about license either. Lets' call it a bored middle aged man project license.
      (gosh, am I really that old? OR MAybe.. use it ONLY if you are that old..lol)

    4. Sorry @bikegremlin, did not meant to hijack thread.

    Pretty cool - though it would make more sense to move it to a separate thread for easier finding in the future (and for any updates and feedback).

  • vyasvyas OGSenpai
    edited August 17

    :-)

    On serious note, you may kindly move to cest pit. If we do separate thread, Accidentaly we might trigger a storm of AI bot “guided” scripts and make a mess out of les. Don’t want that now, do we ?

    Cheers

  • bikegremlinbikegremlin ModeratorOGContent Writer

    @vyas said:
    :-)

    On serious note, you may kindly move to cest pit. If we do separate thread, Accidentaly we might trigger a storm of AI bot “guided” scripts and make a mess out of les. Don’t want that now, do we ?

    Cheers

    IMO it would make more sense to move it to a normal theme under the WordPress section - and act differently if we do run into any problems.

  • @vyas said:
    :-)

    On serious note, you may kindly move to cest pit. If we do separate thread, Accidentaly we might trigger a storm of AI bot “guided” scripts and make a mess out of les. Don’t want that now, do we ?

    Cheers

    What? What's wrong with AI generated scripts (other then it not working)?

    I mean we can even have a AI generated script to post AI generated scripts to LES and have other AI generated scripts to reply and fix the AI generated scripts! Viva la AI generated scripts!

    Thanked by (1)bikegremlin

    Never make the same mistake twice. There are so many new ones to make.
    It’s OK if you disagree with me. I can’t force you to be right.

  • I've managed WordPress websites with templates and plugins I built myself, handling spikes of 2k concurrent users on $3/month VPSes.

    Later, another company hired me to do something similar for more than 10 million unique visitors per month, and it cost them around $2k/month including a larger server.

    Thanked by (1)bikegremlin
  • @imok said:

    I've managed WordPress websites with templates and plugins I built myself, handling spikes of 2k concurrent users on $3/month VPSes.

    Later, another company hired me to do something similar for more than 10 million unique visitors per month, and it cost them around $2k/month including a larger server.

    1998Euros profit - 2 euros infrastrcture

    I believe in good luck. Harder that I work ,luckier i get.

  • @Chievo said:

    @imok said:

    I've managed WordPress websites with templates and plugins I built myself, handling spikes of 2k concurrent users on $3/month VPSes.

    Later, another company hired me to do something similar for more than 10 million unique visitors per month, and it cost them around $2k/month including a larger server.

    1998Euros profit - 2 euros infrastrcture

    Actually I moved everything to bare metal to have peace of mind. I slept better after that.

    Thanked by (1)Chievo
  • @imok said:

    @Chievo said:

    @imok said:

    I've managed WordPress websites with templates and plugins I built myself, handling spikes of 2k concurrent users on $3/month VPSes.

    Later, another company hired me to do something similar for more than 10 million unique visitors per month, and it cost them around $2k/month including a larger server.

    1998Euros profit - 2 euros infrastrcture

    Actually I moved everything to bare metal to have peace of mind. I slept better after that.

    Baremetal never gives me piece of mind...

    A dedicated server running my own VMs on proxmos + onsite snapshot backup + offsite snapshot backup + offsite code backup is what gives me piece of mind. And yes, I know it's overkill, but this is what helps me sleep better at night so it's all worth it :D

    Thanked by (1)bikegremlin

    Never make the same mistake twice. There are so many new ones to make.
    It’s OK if you disagree with me. I can’t force you to be right.

  • Yes, that’s what I meant to say. I mixed up the words. I meant a dedicated server (plus a VPS for backups). I always run Proxmox on my dedis.

  • somiksomik OG
    edited August 18

    @imok said:
    Yes, that’s what I meant to say. I mixed up the words. I meant a dedicated server (plus a VPS for backups). I always run Proxmox on my dedis.

    And a few idlers used to monitor uptime, right? :lol:

    Ya, proxmox is awesome. I dunno what to do if proxmox ever removes their community version...

    Thanked by (1)imok

    Never make the same mistake twice. There are so many new ones to make.
    It’s OK if you disagree with me. I can’t force you to be right.

  • @somik said: And a few idlers used to monitor uptime, right?

    I use Hetrixtools (free plan), otherwise I would need another server to monitor my monitoring server and so on...

    Thanked by (1)bikegremlin
  • AuroraZeroAuroraZero Hosting ProviderRetired

    @bikegremlin oh I gots problems bud BIG problems!!!!

    Thanked by (1)bikegremlin
  • bikegremlinbikegremlin ModeratorOGContent Writer

    @AuroraZero said:
    @bikegremlin oh I gots problems bud BIG problems!!!!

    Should I send Rocky and Knuckles over?

  • AuroraZeroAuroraZero Hosting ProviderRetired

    @bikegremlin said:

    @AuroraZero said:
    @bikegremlin oh I gots problems bud BIG problems!!!!

    Should I send Rocky and Knuckles over?

    Not unless they have a j2534 passthru and a GM SPS subscription lol

  • bikegremlinbikegremlin ModeratorOGContent Writer

    @AuroraZero said:

    @bikegremlin said:

    @AuroraZero said:
    @bikegremlin oh I gots problems bud BIG problems!!!!

    Should I send Rocky and Knuckles over?

    Not unless they have a j2534 passthru and a GM SPS subscription lol

    We got SPS - since the very start of the 90s! :)

  • AuroraZeroAuroraZero Hosting ProviderRetired

    @bikegremlin said:

    @AuroraZero said:

    @bikegremlin said:

    @AuroraZero said:
    @bikegremlin oh I gots problems bud BIG problems!!!!

    Should I send Rocky and Knuckles over?

    Not unless they have a j2534 passthru and a GM SPS subscription lol

    We got SPS - since the very start of the 90s! :)

    I don't know what you have confused SPS for but it is not a VD bud!!!

Sign In or Register to comment.