From db655fb8185f7a89fc5ba397bd5b5f315f8ad226 Mon Sep 17 00:00:00 2001 From: Thuan Bui Date: Wed, 1 Jan 2025 17:56:45 +0900 Subject: [PATCH] Add more functionality: list and delete sites --- README.md | 62 ++++--- install.sh | 118 ------------ kazewp.sh | 257 ++++++++++++++++++++++++++ lib/docker.sh | 24 +++ lib/wordpress.sh | 2 +- templates/docker-compose.yml.template | 22 +-- templates/wp-setup.sh.template | 6 +- uninstall.sh | 26 --- 8 files changed, 329 insertions(+), 188 deletions(-) delete mode 100755 install.sh create mode 100755 kazewp.sh delete mode 100755 uninstall.sh diff --git a/README.md b/README.md index 45e4faf..4e0acf7 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -# **CaddyWP** +# **KazeWP** -**CaddyWP** is an open-source tool designed to simplify the deployment and management of multiple WordPress sites behind a Caddy reverse proxy. It uses Docker and Bash scripts to automate configuration, allowing you to easily set up and scale your WordPress instances with minimal hassle. +**KazeWP** is an open-source tool designed to simplify the deployment and management of multiple WordPress sites behind a lightweight reverse proxy. It uses Docker and Bash scripts to automate configuration, allowing you to quickly set up and scale your WordPress instances with minimal effort. --- ## **Features** -- **Multiple WordPress Sites**: Manage as many WordPress sites as you want, all running on a single reverse proxy server. -- **Caddy Integration**: Seamlessly integrates Caddy as the reverse proxy for efficient traffic routing and SSL management. -- **Dockerized**: Fully containerized environment for easy setup and management. -- **Bash Automation**: Automate your WordPress site configurations using simple Bash scripts. -- **Scalable**: Easily add new sites and scale your infrastructure as needed. +- **Multiple WordPress Sites**: Easily manage multiple WordPress sites, each running in its own container. +- **Reverse Proxy Integration**: Leverages Caddy for efficient traffic routing and automatic SSL certificate management. +- **Containerized Environment**: Fully Dockerized for simplicity, portability, and scalability. +- **Bash Automation**: Intuitive Bash scripts automate site configuration and deployment. +- **Effortless Scaling**: Add or remove WordPress sites with ease, scaling as your needs grow. --- @@ -27,32 +27,48 @@ Ensure you have the following installed: ### **Installation** 1. **Clone the repository**: - ```bash - git clone https://github.com/your-username/caddywp.git - cd caddywp - ``` + ```bash + git clone https://github.com/your-username/kazewp.git + cd kazewp + ``` 2. **Run the install script**: + ```bash + ./kazewp.sh install domain.com + ``` + +--- + +## **Usage** + ```bash - ./install.sh + ./kazewp.sh install - Install a new WordPress site" + ./kazewp.sh list - List all installed WordPress sites" + ./kazewp.sh delete - Delete a WordPress site" + ./kazewp.sh delete all - Delete everything" ``` -## How It Works +## **How It Works** -Caddy: Serves as a reverse proxy, automatically obtaining SSL certificates and routing traffic to the correct WordPress container. +- **Reverse Proxy**: KazeWP uses Caddy as a reverse proxy, automatically handling SSL certificates and routing traffic to the appropriate WordPress container. +- **WordPress Isolation**: Each WordPress site runs in its own Docker container with a unique configuration. +- **Shared Database**: MariaDB serves as the database for all WordPress sites, with each site using a unique database user and password. -WordPress: Each WordPress site is hosted in its own Docker container, ensuring that each site runs in isolation with its own environment and database. +--- -MariaDB: A single MariaDB container serves as the database for all WordPress sites. Each site uses a unique database user and password. - -## License +## **License** This project is licensed under the MIT License - see the LICENSE file for details. -Acknowledgements - Caddy: https://caddyserver.com/ - WordPress: https://wordpress.org/ - Docker: https://www.docker.com/ - MariaDB: https://mariadb.org/ +--- + +## **Acknowledgements** + +- [Caddy](https://caddyserver.com/) +- [WordPress](https://wordpress.org/) +- [Docker](https://www.docker.com/) +- [MariaDB](https://mariadb.org/) + +---

(back to top)

diff --git a/install.sh b/install.sh deleted file mode 100755 index 9a0c3cc..0000000 --- a/install.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash - -# Get the directory where the script is located -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# Source library files in specific order -source "${SCRIPT_DIR}/lib/colors.sh" -source "${SCRIPT_DIR}/lib/config.sh" -source "${SCRIPT_DIR}/lib/utils.sh" -source "${SCRIPT_DIR}/lib/validation.sh" -source "${SCRIPT_DIR}/lib/docker.sh" -source "${SCRIPT_DIR}/lib/caddy.sh" -source "${SCRIPT_DIR}/lib/wordpress.sh" - -echo "WordPress Site Setup Script" -echo "==========================" - -setup_directories - -FIRST_TIME=false -if ! check_container_running "caddy"; then - FIRST_TIME=true -fi - -while true; do - read -p "Enter domain (e.g., example.com): " DOMAIN - if validate_domain "$DOMAIN"; then - break - fi -done - -while true; do - read -p "Enter admin email: " ADMIN_EMAIL - if validate_email "$ADMIN_EMAIL"; then - break - fi -done - -read -p "Enter admin username: " ADMIN_USER - -read -s -p "Enter password (press Enter for random password): " ADMIN_PASSWORD -echo - -if [ -z "$ADMIN_PASSWORD" ]; then - ADMIN_PASSWORD=$(generate_password) - echo "Generated password: $ADMIN_PASSWORD" -fi - -read -p "Enter site title: " SITE_TITLE - -MYSQL_ROOT_PASSWORD=$(openssl rand -base64 32) -MYSQL_PASSWORD=$(openssl rand -base64 32) - -WP_PROJECT_DIR="${WORDPRESS_DIR}/${DOMAIN}" -if [ -d "$WP_PROJECT_DIR" ]; then - echo -e "${RED}Directory ${WP_PROJECT_DIR} already exists!${NC}" - exit 1 -fi - -mkdir -p "$WP_PROJECT_DIR" -cd "$WP_PROJECT_DIR" - -create_docker_compose "$DOMAIN" "$MYSQL_ROOT_PASSWORD" "$MYSQL_PASSWORD" -create_caddy_config "$DOMAIN" -create_wp_setup "$DOMAIN" "$ADMIN_USER" "$ADMIN_PASSWORD" "$ADMIN_EMAIL" "$SITE_TITLE" -create_env_file "$DOMAIN" "$ADMIN_USER" "$ADMIN_PASSWORD" "$ADMIN_EMAIL" "$MYSQL_ROOT_PASSWORD" "$MYSQL_PASSWORD" - - -while true; do - read -p "Do you want to (1) start services and set up WordPress automatically or (2) do it manually later? [1/2]: " SETUP_CHOICE - case $SETUP_CHOICE in - 1) - if start_services "$FIRST_TIME" "$DOMAIN"; then - if run_wp_setup "$DOMAIN"; then - echo -e "${GREEN}Complete setup finished successfully!${NC}" - else - echo -e "${RED}WordPress setup failed. You may need to run setup manually later.${NC}" - fi - else - echo -e "${RED}Service startup failed. You may need to start services manually.${NC}" - fi - break - ;; - 2) - echo -e "\n${BLUE}Manual setup instructions:${NC}" - if [ "$FIRST_TIME" = true ]; then - echo "1. Start Caddy:" - echo " cd ${CADDY_DIR} && docker compose up -d" - fi - reload_caddy - echo "2. Start WordPress:" - echo " cd ${WP_PROJECT_DIR} && docker compose up -d" - echo "3. Run the WordPress setup script:" - echo " ./wp-setup.sh" - break - ;; - *) - echo -e "${RED}Invalid choice. Please enter 1 or 2.${NC}" - ;; - esac -done - -echo -e "\n${BLUE}WordPress Site Information:${NC}" -echo "----------------------------------------" -echo "Domain: https://$DOMAIN" -echo "Admin URL: https://$DOMAIN/wp-admin" -echo "Username: $ADMIN_USER" -if [ "$PASSWORD_CHOICE" = "2" ]; then - echo "Password: $ADMIN_PASSWORD (SAVE THIS PASSWORD!)" -fi -echo "Email: $ADMIN_EMAIL" -echo "----------------------------------------" - -save_credentials "$WP_PROJECT_DIR" "$DOMAIN" "$ADMIN_USER" "$ADMIN_PASSWORD" "$ADMIN_EMAIL" - -echo -e "\nCredentials have been saved to: ${WP_PROJECT_DIR}/credentials.txt" - -exit 0 \ No newline at end of file diff --git a/kazewp.sh b/kazewp.sh new file mode 100755 index 0000000..d66ffc0 --- /dev/null +++ b/kazewp.sh @@ -0,0 +1,257 @@ +#!/bin/bash +# Get the directory where the script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Source library files in specific order +source "${SCRIPT_DIR}/lib/colors.sh" +source "${SCRIPT_DIR}/lib/config.sh" +source "${SCRIPT_DIR}/lib/utils.sh" +source "${SCRIPT_DIR}/lib/validation.sh" +source "${SCRIPT_DIR}/lib/docker.sh" +source "${SCRIPT_DIR}/lib/caddy.sh" +source "${SCRIPT_DIR}/lib/wordpress.sh" + +echo "CaddyWP: WordPress Site Management Script" +echo "==========================" + + +FIRST_TIME=false +if ! check_container_running "caddy"; then + FIRST_TIME=true +fi + +setup_directories + + +# Function to install a new WordPress site +install_site() { + DOMAIN="$1" + #db_prefix="$(openssl rand -base64 6)"_ + + +while true; do + read -p "Enter admin email: " ADMIN_EMAIL + if validate_email "$ADMIN_EMAIL"; then + break + fi +done + +read -p "Enter admin username: " ADMIN_USER + +read -s -p "Enter password (press Enter for random password): " ADMIN_PASSWORD +echo + +if [ -z "$ADMIN_PASSWORD" ]; then + ADMIN_PASSWORD=$(generate_password) + echo "Generated password: $ADMIN_PASSWORD" +fi + +read -p "Enter site title: " SITE_TITLE + +MYSQL_ROOT_PASSWORD=$(openssl rand -base64 32) +MYSQL_PASSWORD=$(openssl rand -base64 32) + +WP_PROJECT_DIR="${WORDPRESS_DIR}/${DOMAIN}" +if [ -d "$WP_PROJECT_DIR" ]; then + echo -e "${RED}Directory ${WP_PROJECT_DIR} already exists!${NC}" + exit 1 +fi + +mkdir -p "$WP_PROJECT_DIR" +cd "$WP_PROJECT_DIR" + +create_docker_compose "$DOMAIN" "$MYSQL_ROOT_PASSWORD" "$MYSQL_PASSWORD" +create_caddy_config "$DOMAIN" +create_wp_setup "$DOMAIN" "$ADMIN_USER" "$ADMIN_PASSWORD" "$ADMIN_EMAIL" "$SITE_TITLE" +create_env_file "$DOMAIN" "$ADMIN_USER" "$ADMIN_PASSWORD" "$ADMIN_EMAIL" "$MYSQL_ROOT_PASSWORD" "$MYSQL_PASSWORD" + + + + + + while true; do + read -p "Do you want to (1) start services and set up WordPress automatically or (2) do it manually later? [1/2]: " SETUP_CHOICE + case $SETUP_CHOICE in + 1) + if start_services "$FIRST_TIME" "$DOMAIN"; then + if run_wp_setup "$DOMAIN"; then + echo -e "${GREEN}Complete setup finished successfully!${NC}" + else + echo -e "${RED}WordPress setup failed. You may need to run setup manually later.${NC}" + fi + else + echo -e "${RED}Service startup failed. You may need to start services manually.${NC}" + fi + break + ;; + 2) + echo -e "\n${BLUE}Manual setup instructions:${NC}" + if [ "$FIRST_TIME" = true ]; then + echo "1. Start Caddy:" + echo " cd ${CADDY_DIR} && docker compose up -d" + fi + reload_caddy + echo "2. Start WordPress:" + echo " cd ${WP_PROJECT_DIR} && docker compose up -d" + echo "3. Run the WordPress setup script:" + echo " ./wp-setup.sh" + break + ;; + *) + echo -e "${RED}Invalid choice. Please enter 1 or 2.${NC}" + ;; + esac + done + + echo -e "\n${BLUE}WordPress Site Information:${NC}" + echo "----------------------------------------" + echo "Domain: https://$DOMAIN" + echo "Admin URL: https://$DOMAIN/wp-admin" + echo "Username: $ADMIN_USER" + echo "Password: $ADMIN_PASSWORD (SAVE THIS PASSWORD!)" + echo "Email: $ADMIN_EMAIL" + echo "----------------------------------------" + +save_credentials "$WP_PROJECT_DIR" "$DOMAIN" "$ADMIN_USER" "$ADMIN_PASSWORD" "$ADMIN_EMAIL" + +echo -e "\nCredentials have been saved to: ${WP_PROJECT_DIR}/credentials.txt" + +exit 0 +} + +# Function to list all installed WordPress sites +list_sites() { + if [ ! -d "$WORDPRESS_DIR" ]; then + echo "There are no websites setup yet!" + exit 1 + fi + echo "Installed WordPress Sites:" + echo "-------------------------" + subfolders=($(find "$WORDPRESS_DIR" -mindepth 1 -maxdepth 1 -type d)) + if [ ${#subfolders[@]} -eq 0 ]; then + echo "There are no websites setup yet!" + else + for site in "$WORDPRESS_DIR"/*; do + if [ -d "$site" ]; then + DOMAIN=$(basename "$site") + if [ -f "$site/compose.yaml" ]; then + echo "Site: $DOMAIN" + echo "Path: $site" + get_containers_status "$site/compose.yaml" + #echo "Status: $(docker compose -f $site/compose.yaml ps --status running | grep -v 'Name' | wc -l) containers running" + echo "-------------------------" + fi + fi + done + fi +} + +# Function to delete a WordPress site +delete_site() { + DOMAIN="$1" + WP_PROJECT_DIR="${WORDPRESS_DIR}/${DOMAIN}" + + #echo $DOMAIN + #echo $WP_PROJECT_DIR + + if [ ! -d "$WP_PROJECT_DIR" ]; then + echo "Error: Site '$DOMAIN' not found" + return 1 + fi + + echo "Warning: This will permanently delete the site: $DOMAIN" + read -p "Are you sure you want to continue? (y/N): " confirm + + if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then + echo "Operation cancelled" + return 0 + fi + + echo "Stopping Docker containers..." + docker compose -f "$WP_PROJECT_DIR/compose.yaml" down + + echo "Removing site directory..." + rm -rf "$WP_PROJECT_DIR" + + echo "Removing Caddy configuration..." + rm -f "${CADDY_DIR}/sites/${DOMAIN}.caddy" + + echo "Reloading Caddy..." + reload_caddy + + echo "Site '$DOMAIN' has been successfully deleted" +} + +# Main script +case "$1" in + "install") + DOMAIN="$2" + if [ -z "$DOMAIN" ]; then + echo "Error: Please provide a domain" + while true; do + read -p "Enter domain (e.g., example.com): " DOMAIN + if validate_domain "$DOMAIN"; then + break + fi + done + fi + install_site "$DOMAIN" + ;; + "list") + list_sites + ;; + "delete") + + # Check if correct arguments are provided + if [ "$2" == "all" ]; then + # Ask for confirmation before proceeding with the uninstallation + read -p "Are you sure you want to uninstall everything? This will stop and remove all containers, and delete files. (Y/n): " confirm + + if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then + # Stop all running containers + echo "Stopping all containers..." + find . -name 'compose.yaml' -execdir docker compose down \; + + # Remove WordPress files + echo "Removing WordPress files..." + rm -rf wordpress + + # Remove Caddy files + echo "Removing Caddy files..." + rm -rf caddy + + docker system prune -af + + echo "Uninstallation complete." + else + echo "Uninstallation aborted." + fi + else + if [ -z "$2" ]; then + echo "Error: Please provide a site name to delete or using all to delete everything" + #list_sites + while true; do + read -p "Enter domain (e.g., example.com): " DOMAIN + if validate_domain "$DOMAIN"; then + break + fi + done + delete_site "$DOMAIN" + else + delete_site "$2" + fi + fi + + + ;; + + *) + echo "WordPress Site Manager" + echo "Usage:" + echo " $0 install - Install a new WordPress site" + echo " $0 list - List all installed WordPress sites" + echo " $0 delete - Delete a WordPress site" + echo " $0 delete all - Delete everything" + exit 1 + ;; +esac \ No newline at end of file diff --git a/lib/docker.sh b/lib/docker.sh index 7e13006..15bf450 100644 --- a/lib/docker.sh +++ b/lib/docker.sh @@ -46,4 +46,28 @@ start_services() { fi return 0 +} + +get_containers_status() { + local compose_file="$1" + local containers=() + local count=0 + + while IFS= read -r container; do + # Skip if empty line + [ -z "$container" ] && continue + containers+=("$container") + ((count++)) + done < <(docker compose -f "$compose_file" ps --status running --format '{{.Name}}') + + if [ $count -eq 0 ]; then + echo "Status: No container is running" + else + echo -n "Status: $count containers are running: " + printf "%s" "${containers[0]}" + for ((i=1; i<${#containers[@]}; i++)); do + printf " and %s" "${containers[$i]}" + done + echo + fi } \ No newline at end of file diff --git a/lib/wordpress.sh b/lib/wordpress.sh index 0bd69a6..070f24e 100644 --- a/lib/wordpress.sh +++ b/lib/wordpress.sh @@ -36,7 +36,7 @@ create_env_file() { ## Wordpress ## WORDPRESS_DB_USER=wordpress - WORDPRESS_DB_PASSWORD=${DB_PASSWORD} + WORDPRESS_DB_PASSWORD=${MYSQL_PASSWORD} WORDPRESS_DB_NAME=wordpress WORDPRESS_DB_HOST=db_${DOMAIN}:3306 diff --git a/templates/docker-compose.yml.template b/templates/docker-compose.yml.template index ccedac5..475bdaa 100644 --- a/templates/docker-compose.yml.template +++ b/templates/docker-compose.yml.template @@ -5,11 +5,8 @@ services: volumes: - ./db_data:/var/lib/mysql restart: always - environment: - MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} - MYSQL_DATABASE: wordpress - MYSQL_USER: wordpress - MYSQL_PASSWORD: ${MYSQL_PASSWORD} + env_file: + - .env healthcheck: test: ["CMD", "mariadb-admin", "ping", "-h", "localhost", "--silent"] interval: 10s @@ -25,13 +22,9 @@ services: image: wordpress:fpm-alpine volumes: - ./html/:/var/www/html - + env_file: + - .env restart: always - environment: - WORDPRESS_DB_HOST: db_${DOMAIN}:3306 - WORDPRESS_DB_USER: wordpress - WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} - WORDPRESS_DB_NAME: wordpress networks: - ${DOMAIN}_net - caddy_net @@ -40,11 +33,8 @@ services: depends_on: - db_${DOMAIN} - wordpress_${DOMAIN} - environment: - WORDPRESS_DB_HOST: db_${DOMAIN}:3306 - WORDPRESS_DB_USER: wordpress - WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} - WORDPRESS_DB_NAME: wordpress + env_file: + - .env image: wordpress:cli entrypoint: wp command: "--info" diff --git a/templates/wp-setup.sh.template b/templates/wp-setup.sh.template index 84b0665..2eb2e55 100644 --- a/templates/wp-setup.sh.template +++ b/templates/wp-setup.sh.template @@ -4,10 +4,8 @@ wpcli() { docker compose run --rm wpcli "$@" } -echo "Waiting for MySQL to be ready..." -#while ! docker exec db_${DOMAIN} mysqladmin ping -h localhost --silent; do -# sleep 1 -#done +echo "Waiting for MariaDB to be ready..." + while [ "$(docker inspect --format='{{.State.Health.Status}}' db_${DOMAIN})" != "healthy" ]; do echo "MariaDB is not healthy yet. Retrying..." sleep 5 diff --git a/uninstall.sh b/uninstall.sh deleted file mode 100755 index a7a60d6..0000000 --- a/uninstall.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -# Ask for confirmation before proceeding with the uninstallation -read -p "Are you sure you want to uninstall everything? This will stop and remove all containers, and delete files. (y/n): " confirm - -if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then - # Stop all running containers - echo "Stopping all containers..." - docker stop $(docker ps -a -q) - - # Remove all containers - echo "Removing all containers..." - docker rm $(docker ps -a -q) - - # Remove WordPress files - echo "Removing WordPress files..." - rm -rf wordpress - - # Remove Caddy files - echo "Removing Caddy files..." - rm -rf caddy - - echo "Uninstallation complete." -else - echo "Uninstallation aborted." -fi