How much does a WordPress website cost?

I've finally gotten down to writing an article on all the related costs when it comes to WP websites.

Surely, with a bit of coding and patience (read: "Black Friday sales") the costs can be significantly reduced, but I wanted to make a "pessimistic/realistic" overview, 'cause we all know that only pigeon pictures are really free:

How much does a WordPress website cost?

Comments

  • WordPress.com : starting from zero US Dollars

    Wordpress.org : starting from zero US Dollars

  • WordPress website costs a lot of pain

  • I'd say 1 dollar to somewhere around 70 dollars.

    It's the content and the amount of organic traffic that matters. A site optimized for bots (AKA SEO optimized) ain't worth shit.

    ♻ Amitz day is October 21.
    ♻ Join Nigh sect by adopting my avatar. Let us spread the joys of the end.

  • dosaidosai OG தோசை

    Good email infrastructure is the key to every victory!
    – Sun Tzu, “The Art of War”

    kek

  • edited April 2022

    Just my opinion here, from the article:
    "A vast majority of my websites are hosted with HostMantis Enterprise Reseller hosting. It costs around $ 22 per month"

    OH my god no - I've never even heard of that host. My entire company and about 20 sub-partners, and sub-websites, run on Stablehost for about $30/year combined (so $1.50/year each?) on their pro unlimited domain plan - and have been running there for over a decade, and that is a touch on the high-cost side for wordpress.

    There are about a dozen other large hosts I'd recommend in the $30 to $70/year cost range. But $22 a month for wordpress is ... yikes.

    XR Developer | https://redironlabs.com

  • bikegremlinbikegremlin ModeratorOG

    @lloyd said:
    Just my opinion here, from the article:
    "A vast majority of my websites are hosted with HostMantis Enterprise Reseller hosting. It costs around $ 22 per month"

    OH my god no - I've never even heard of that host. My entire company and about 20 sub-partners, and sub-websites, run on Stablehost for about $30/year combined (so $1.50/year each?) on their pro unlimited domain plan - and have been running there for over a decade, and that is a touch on the high-cost side for wordpress.

    There are about a dozen other large hosts I'd recommend in the $30 to $70/year cost range. But $22 a month for wordpress is ... yikes.

    I'm interested in finding a good alternative.
    DirectAdmin reseller hosting, preferably UK, or US-East coast location.

  • I didn't read the article. Not worth it in my book. No point in reading any articles in 2022.

    But several WP sites I run and maintain for others, each of them costs around 5 bucks a month.

    ♻ Amitz day is October 21.
    ♻ Join Nigh sect by adopting my avatar. Let us spread the joys of the end.

  • Almost forgot: when you Google “best hosting providers” or something similar, you’ll get a ton of paid articles that are nonsense – disregard them.

    I agree, but HostMantis isn't that great either. They are doing huge price hikes in the name of cpanel hikes, but lot of people are still complaining about sub optimal performance.

    If you are willing to spend 8 bucks more, might as well grab a slice and you get managed VPS, which will be overkill if you do not have much traffic.

    If you are looking for alternative, then I might suggest Crocweb. I have been with them for almost a decade now, and they are pretty good. In spite of being in opposite timezone, they reply within minutes. And they do not have any affiliate system, so not many people promote them. Other option that I really liked was Ramnode, their uptime and support is really good.

  • bikegremlinbikegremlin ModeratorOG

    @coo said:

    Almost forgot: when you Google “best hosting providers” or something similar, you’ll get a ton of paid articles that are nonsense – disregard them.

    I agree, but HostMantis isn't that great either. They are doing huge price hikes in the name of cpanel hikes, but lot of people are still complaining about sub optimal performance.

    If you are willing to spend 8 bucks more, might as well grab a slice and you get managed VPS, which will be overkill if you do not have much traffic.

    If you are looking for alternative, then I might suggest Crocweb. I have been with them for almost a decade now, and they are pretty good. In spite of being in opposite timezone, they reply within minutes. And they do not have any affiliate system, so not many people promote them. Other option that I really liked was Ramnode, their uptime and support is really good.

    I've tried a few other options, and in terms of uptime no one was better (so far), while regarding performance, Brixly was just a tad better (but had some other hiccups so it's not a good match for me).

    Tried even some more expensive options, like Veerotech (I think they're still a bit more expensive for what I'm using the hosting for).

    I've heard good things about CrocWeb, but haven't used the service.

    MDDhosting reseller offers also look promising - again, for my intended use - they (now, as of relatively recently) limit the resources per reseller account, not per a created cPanel account, but since I manage all the websites (not re-selling hosting literally), that works for me - more flexibility.

    Both of those are using cPanel - while I finally switched completely to DirectAdmin. :)
    I'm always one step ahead behind! :)

    I prefer a reseller package (Cloudlinux, Jetbackups and all), compared to paying (probably even more money) for a managed VPS.

  • deankdeank OG
    edited April 2022

    Well, if you use Cpenis, the overall cost is going to go up, yes. You don't really need cPenis. I mean we all need dicks, but CpEnis is worthless.

    Get rid of it.

    P.S. The 5 bucks I mentioned, it's 5 Canadian Rubles. In US currency, it should be more akin to 1 buck.

    ♻ Amitz day is October 21.
    ♻ Join Nigh sect by adopting my avatar. Let us spread the joys of the end.

  • bikegremlinbikegremlin ModeratorOG

    @deank said:
    Well, if you use Cpenis, the overall cost is going to go up, yes. You don't really need cPenis. I mean we all need dicks, but CpEnis is worthless.

    Get rid of it.

    P.S. The 5 bucks I mentioned, it's 5 Canadian Rubles. In US currency, it should be more akin to 1 buck.

    I thought they be payin' you!? They ought to!

    :)

  • @bikegremlin said:

    @lloyd said:
    Just my opinion here, from the article:
    "A vast majority of my websites are hosted with HostMantis Enterprise Reseller hosting. It costs around $ 22 per month"

    OH my god no - I've never even heard of that host. My entire company and about 20 sub-partners, and sub-websites, run on Stablehost for about $30/year combined (so $1.50/year each?) on their pro unlimited domain plan - and have been running there for over a decade, and that is a touch on the high-cost side for wordpress.

    There are about a dozen other large hosts I'd recommend in the $30 to $70/year cost range. But $22 a month for wordpress is ... yikes.

    I'm interested in finding a good alternative.
    DirectAdmin reseller hosting, preferably UK, or US-East coast location.

    We’re in Canada but we will eventually be migrating to NYC. PM me if you want to give us a try, first month on us

  • 7 is fair. Sell it to @revolver.

    ♻ Amitz day is October 21.
    ♻ Join Nigh sect by adopting my avatar. Let us spread the joys of the end.

  • (Between) Zero (to) Lots of Pain

  • 30$ minimum/year if developed by yourself, If you hired someone then 30$/year + developing costs.
    Why 30$?
    10$-12$ for the domain cost, 15$ to 20$ for decent hosting, and you will need to learn how to use free themes.

  • YmpkerYmpker OG
    edited April 2022

    For me it was 50$ for 2-3 years (and hopefully many more) using @MikePT lifetime hosting :D Some even might get the small lifetime plan for 10$ which is more than enough for WP :)
    Props to Mike <3

  • edited April 2022

    @Ympker said:
    For me it was 50$ for 2-3 years (and hopefully many more) using @MikePT lifetime hosting :D Some even might get the small lifetime plan for 10$ which is more than enough for WP :)
    Props to Mike <3

    I am also using Mike services, top notch, but here we're talking about general users who are not tech savy or looted by big companies Facebook or AdWords ads.

  • $3 :)

    wow! cheap vps and cloud server, 16 nodes. our site: www.surfercloud.com

  • @SurferCloud said:
    $3 :)

    A two year old thread?

  • @skorous said:

    @SurferCloud said:
    $3 :)

    A two year old thread?

    One of the requirements for a provider tag is "minimum of 5 non-spammy posts."

    Many people don't seem to understand what "non-spammy" means. :(

  • Real talk: even with discounts, a decent WordPress site ain’t free. You’re looking at $50–150/year for solid hosting (cheap shared won’t cut it for speed or security). Domain’s around $12. Premium theme? $60 one-time. Plugins - backup, security, caching - another $50–100. If you mess up, recovery or dev help adds $100+. Renewals stack. So yeah, $200–300 first year, $100–150 after. Pigeon pics are free. Everything else? Not so much.

  • somiksomik OG Hostbusters

    The cost of running a WordPress website can range from just a few dollars per month to hundreds, depending on whether you go for a budget DIY setup or a high-performance, professional stack.
    Here’s a detailed breakdown of typical costs so you can see where the money goes:

    1. Domain Name
      Cost: USD $10–$20/year for a .com (other TLDs can be more expensive)
      Notes: Paid annually. You can register with Namecheap, Google Domains, Cloudflare, etc.
      Tip: Sometimes hosting companies give the first year free, but renewal is never free.

    2. Hosting (Required)
      Options & Costs:
      Shared Hosting: $3–$10/month (Bluehost, Hostinger, SiteGround)
      Managed WordPress Hosting: $20–$40/month (Kinsta, WP Engine, Flywheel)
      VPS / Cloud Hosting: $5–$30/month (DigitalOcean, Linode, AWS Lightsail)
      High-end Enterprise: $100+/month for very high traffic.

    3. SSL Certificate (Required if you want HTTPS)
      Cost: Free with Let’s Encrypt (most hosts offer it)
      Paid SSL (e.g., EV or Wildcard): $50–$200/year.
      Notes: Paid SSL usually only matters for specific corporate or e-commerce requirements.

    4. Themes (Optional but common)
      Free themes: $0 (from WordPress.org)
      Premium themes: $30–$80 one-time or yearly (ThemeForest, Elegant Themes, GeneratePress)
      Notes: Premium themes often come with better designs, features, and support.

    5. Plugins (Optional but often needed)
      Free plugins: $0 (many great free ones exist)
      Premium plugins: $5–$100/year each
      Examples:
      SEO (Yoast Premium, Rank Math Pro)
      Security (Wordfence Premium, iThemes Security Pro)
      Backups (UpdraftPlus Premium, BlogVault)
      Page Builders (Elementor Pro, WPBakery)
      Typical spend: $50–$300/year if you use several premium plugins.

    6. Maintenance & Backups (If not included in hosting)
      DIY: $0 (manual updates & free backup plugins)
      Paid service: $10–$50/month for outsourced maintenance.

    7. Optional Extras
      Email Hosting: $0–$6/month (Zoho Mail free tier or Google Workspace)
      CDN (Content Delivery Network): Free (Cloudflare) or $10–$20/month (paid plans)
      Custom Development: $20–$150/hour if hiring developers.
      Example Cost Scenarios

    A. Bare-bones personal blog (cheap)
    Domain: $12/year
    Shared hosting: $5/month → $60/year
    SSL: Free via Let’s Encrypt
    Theme: Free
    Plugins: Free
    Total yearly: ~$72

    B. Professional small business site
    Domain: $15/year
    Managed WordPress hosting: $25/month → $300/year
    SSL: Free
    Premium theme: $60 (one-time or yearly)
    Premium plugins: $150/year
    Total yearly: ~$525

    C. High-traffic e-commerce site
    Domain: $20/year per domain
    High-end managed hosting: $60/month → $720/year
    Premium SSL: $120/year
    Premium theme: $80/year
    Premium plugins (WooCommerce add-ons, security, backups): $300/year
    CDN Pro Plan: $20/month → $240/year
    Total yearly: ~$1,480

    I speak fluent sarcasm and broken logic. | I would agree with you, but thæn we’d both be wrong.

  • bikegremlinbikegremlin ModeratorOG

    @somik said:
    The cost of running a WordPress website can range from just a few dollars per month to hundreds, depending on whether you go for a budget DIY setup or a high-performance, professional stack.
    Here’s a detailed breakdown of typical costs so you can see where the money goes:

    1. Domain Name
      Cost: USD $10–$20/year for a .com (other TLDs can be more expensive)
      Notes: Paid annually. You can register with Namecheap, Google Domains, Cloudflare, etc.
      Tip: Sometimes hosting companies give the first year free, but renewal is never free.

    2. Hosting (Required)
      Options & Costs:
      Shared Hosting: $3–$10/month (Bluehost, Hostinger, SiteGround)
      Managed WordPress Hosting: $20–$40/month (Kinsta, WP Engine, Flywheel)
      VPS / Cloud Hosting: $5–$30/month (DigitalOcean, Linode, AWS Lightsail)
      High-end Enterprise: $100+/month for very high traffic.

    3. SSL Certificate (Required if you want HTTPS)
      Cost: Free with Let’s Encrypt (most hosts offer it)
      Paid SSL (e.g., EV or Wildcard): $50–$200/year.
      Notes: Paid SSL usually only matters for specific corporate or e-commerce requirements.

    4. Themes (Optional but common)
      Free themes: $0 (from WordPress.org)
      Premium themes: $30–$80 one-time or yearly (ThemeForest, Elegant Themes, GeneratePress)
      Notes: Premium themes often come with better designs, features, and support.

    5. Plugins (Optional but often needed)
      Free plugins: $0 (many great free ones exist)
      Premium plugins: $5–$100/year each
      Examples:
      SEO (Yoast Premium, Rank Math Pro)
      Security (Wordfence Premium, iThemes Security Pro)
      Backups (UpdraftPlus Premium, BlogVault)
      Page Builders (Elementor Pro, WPBakery)
      Typical spend: $50–$300/year if you use several premium plugins.

    6. Maintenance & Backups (If not included in hosting)
      DIY: $0 (manual updates & free backup plugins)
      Paid service: $10–$50/month for outsourced maintenance.

    7. Optional Extras
      Email Hosting: $0–$6/month (Zoho Mail free tier or Google Workspace)
      CDN (Content Delivery Network): Free (Cloudflare) or $10–$20/month (paid plans)
      Custom Development: $20–$150/hour if hiring developers.
      Example Cost Scenarios

    A. Bare-bones personal blog (cheap)
    Domain: $12/year
    Shared hosting: $5/month → $60/year
    SSL: Free via Let’s Encrypt
    Theme: Free
    Plugins: Free
    Total yearly: ~$72

    B. Professional small business site
    Domain: $15/year
    Managed WordPress hosting: $25/month → $300/year
    SSL: Free
    Premium theme: $60 (one-time or yearly)
    Premium plugins: $150/year
    Total yearly: ~$525

    C. High-traffic e-commerce site
    Domain: $20/year per domain
    High-end managed hosting: $60/month → $720/year
    Premium SSL: $120/year
    Premium theme: $80/year
    Premium plugins (WooCommerce add-ons, security, backups): $300/year
    CDN Pro Plan: $20/month → $240/year
    Total yearly: ~$1,480

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

  • @bikegremlin said:

    @somik said:
    The cost of running a WordPress website can range from just a few dollars per month to hundreds, depending on whether you go for a budget DIY setup or a high-performance, professional stack.
    Here’s a detailed breakdown of typical costs so you can see where the money goes:

    1. Domain Name
      Cost: USD $10–$20/year for a .com (other TLDs can be more expensive)
      Notes: Paid annually. You can register with Namecheap, Google Domains, Cloudflare, etc.
      Tip: Sometimes hosting companies give the first year free, but renewal is never free.

    2. Hosting (Required)
      Options & Costs:
      Shared Hosting: $3–$10/month (Bluehost, Hostinger, SiteGround)
      Managed WordPress Hosting: $20–$40/month (Kinsta, WP Engine, Flywheel)
      VPS / Cloud Hosting: $5–$30/month (DigitalOcean, Linode, AWS Lightsail)
      High-end Enterprise: $100+/month for very high traffic.

    3. SSL Certificate (Required if you want HTTPS)
      Cost: Free with Let’s Encrypt (most hosts offer it)
      Paid SSL (e.g., EV or Wildcard): $50–$200/year.
      Notes: Paid SSL usually only matters for specific corporate or e-commerce requirements.

    4. Themes (Optional but common)
      Free themes: $0 (from WordPress.org)
      Premium themes: $30–$80 one-time or yearly (ThemeForest, Elegant Themes, GeneratePress)
      Notes: Premium themes often come with better designs, features, and support.

    5. Plugins (Optional but often needed)
      Free plugins: $0 (many great free ones exist)
      Premium plugins: $5–$100/year each
      Examples:
      SEO (Yoast Premium, Rank Math Pro)
      Security (Wordfence Premium, iThemes Security Pro)
      Backups (UpdraftPlus Premium, BlogVault)
      Page Builders (Elementor Pro, WPBakery)
      Typical spend: $50–$300/year if you use several premium plugins.

    6. Maintenance & Backups (If not included in hosting)
      DIY: $0 (manual updates & free backup plugins)
      Paid service: $10–$50/month for outsourced maintenance.

    7. Optional Extras
      Email Hosting: $0–$6/month (Zoho Mail free tier or Google Workspace)
      CDN (Content Delivery Network): Free (Cloudflare) or $10–$20/month (paid plans)
      Custom Development: $20–$150/hour if hiring developers.
      Example Cost Scenarios

    A. Bare-bones personal blog (cheap)
    Domain: $12/year
    Shared hosting: $5/month → $60/year
    SSL: Free via Let’s Encrypt
    Theme: Free
    Plugins: Free
    Total yearly: ~$72

    B. Professional small business site
    Domain: $15/year
    Managed WordPress hosting: $25/month → $300/year
    SSL: Free
    Premium theme: $60 (one-time or yearly)
    Premium plugins: $150/year
    Total yearly: ~$525

    C. High-traffic e-commerce site
    Domain: $20/year per domain
    High-end managed hosting: $60/month → $720/year
    Premium SSL: $120/year
    Premium theme: $80/year
    Premium plugins (WooCommerce add-ons, security, backups): $300/year
    CDN Pro Plan: $20/month → $240/year
    Total yearly: ~$1,480

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

    The greatest cost for websites like the bullet proof of bikes maniacs like the @bikegremlin one is the time. This superb person has dedicated probably over 10000 hours for content creation. 10000x40( or more per hour) euros per hour for mechanic price(car s mechanic charge between 36to 100 euros per hour) = 400000 euros just in time dedicated to it . More or less! Cost of the infrastructure is just a really small part of all the costs.

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

  • vyasvyas OG
    edited August 2025

    Just this morning as my dog was insisting we do an extra 20 minutes of walk across wet streets... I had a long chat with chatGPT & grok on this very topic.

    I pushed and pushed till both these tools agree that a low traffic/ lightweight WP site could run on Caddy + Sqlite with bare bones specs even in 2025. (not that I would set such a site up) Then we had a big back and forth on hosting, VPS specs, prices.... most of which I disagreed with ( AI Loves to recommend Hostinger or Hostgator, close to Bluehost territory)

    Then, the most important line comes up in this discussion...

    @Chievo said:
    The greatest cost for websites like the bullet proof of bikes maniacs like the @bikegremlin one is the time.

  • somiksomik OG Hostbusters

    @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?

    @Chievo said:
    Cost of the infrastructure is just a really small part of all the costs.

    Not to mention you can go complete free if you are willing to live with using your residential IP (with unblocked port 80 & 443) and a old computer you have, to setup your own infra.

    I speak fluent sarcasm and broken logic. | I would agree with you, but thæn we’d both be wrong.

  • @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?

    Hell no; there are plenty of stupidly cheap hosters that aren't maliciously incompetent :-)

  • somiksomik OG Hostbusters

    @ahnlak said:

    @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?

    Hell no; there are plenty of stupidly cheap hosters that aren't maliciously incompetent :-)

    And you expect me to believe you never fell for it and knew from the start which hosts are good? Well, I for one wasn't that lucky and back in the 2000s I went with a lot of cheap/free hosts...

    I speak fluent sarcasm and broken logic. | I would agree with you, but thæn we’d both be wrong.

  • Not saying every hoster I've used has been great but no, never fell under the influence of bluehost and the like.

  • bikegremlinbikegremlin ModeratorOG

    @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 OG
    edited August 2025

    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 &#96;${DB_NAME}&#96;.* 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.

  • bikegremlinbikegremlin ModeratorOG

    @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
    &gt;   php wp-cli.phar --info &gt;/dev/null 2&gt;&amp;1 || true
    &gt;   chmod +x wp-cli.phar
    &gt;   mv wp-cli.phar /usr/local/bin/wp
    &gt; else
    &gt;   log "wp-cli present."
    &gt; fi
    &gt; 
    &gt; # -------------------------
    &gt; 
    &gt; ##### Database setup
    &gt; 
    &gt; # -------------------------
    &gt; 
    &gt; if [[ "$DB_ENGINE" == "mariadb" ]]; then
    &gt;   log "Creating database and user..."
    &gt;   mysql -e "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
    &gt;   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
    &gt; 
    &gt; log "Installing default plugins/themes if requested..."
    &gt; if $INSTALL_PLUGINS; then
    &gt;   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 OG
    edited August 2025

    :-)

    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 ModeratorOG

    @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.

  • somiksomik OG Hostbusters

    @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!

    I speak fluent sarcasm and broken logic. | I would agree with you, but thæn we’d both be wrong.

  • imokimok OG Not Administrator

    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.

  • @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.

  • imokimok OG Not Administrator

    @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.

  • somiksomik OG Hostbusters

    @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

    I speak fluent sarcasm and broken logic. | I would agree with you, but thæn we’d both be wrong.

  • imokimok OG Not Administrator

    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 Hostbusters
    edited August 2025

    @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...

    I speak fluent sarcasm and broken logic. | I would agree with you, but thæn we’d both be wrong.

  • imokimok OG Not Administrator

    @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...

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

    The Yeti has left the building.

  • bikegremlinbikegremlin ModeratorOG

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

    Should I send Rocky and Knuckles over?

  • @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

    The Yeti has left the building.

  • bikegremlinbikegremlin ModeratorOG

    @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! :)

  • @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!!!

    The Yeti has left the building.

Sign In or Register to comment.