diff --git a/.env.example b/.env.example index 3bff736..b512ac8 100644 --- a/.env.example +++ b/.env.example @@ -2,9 +2,6 @@ # Core application settings # -------------------------------------------------- -# Docker container name prefix -CONTAINER_NAME=app - # -------------------------------------------------- # Database (MySQL) # -------------------------------------------------- diff --git a/README.md b/README.md index d8acc24..2db71df 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,6 @@ The stack is driven by environment variables defined in the `.env` file. This ap | Variable | Description | | :--- | :--- | -| `CONTAINER_NAME` | Prefix used for all containers in the stack (e.g., `app`). | | `SERVER_NAME` | Domain or hostname for the application (e.g., `localhost`). | | `HTTP_PORT` | Host port mapped to the Nginx entry point (e.g., `8000`). | diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index ab0de4f..55ae02b 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -31,7 +31,6 @@ services: depends_on: - wordpress - database - container_name: ${CONTAINER_NAME}-wp-cli image: wordpress:cli env_file: .env environment: @@ -51,7 +50,6 @@ services: db-cli: depends_on: - database - container_name: ${CONTAINER_NAME}-db-cli image: mysql:8.4.7 env_file: .env environment: @@ -72,7 +70,6 @@ services: phpmyadmin: depends_on: - database - container_name: ${CONTAINER_NAME}-phpmyadmin image: phpmyadmin:5.2.3 restart: unless-stopped env_file: .env diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index fb7b5d5..15083ca 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -83,7 +83,6 @@ services: certbot: <<: *default-logging image: certbot/certbot:v5.2.2 - container_name: ${CONTAINER_NAME}-certbot env_file: .env environment: SERVER_NAME: ${SERVER_NAME} diff --git a/docker-compose.yml b/docker-compose.yml index 208b721..eb2b9e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,5 @@ services: database: - container_name: ${CONTAINER_NAME}-database image: mysql:8.4.7 restart: unless-stopped env_file: .env @@ -23,7 +22,6 @@ services: wordpress: depends_on: - database - container_name: ${CONTAINER_NAME}-wordpress image: wordpress:6.9.0-fpm-alpine restart: unless-stopped env_file: .env @@ -40,7 +38,6 @@ services: nginx: depends_on: - wordpress - container_name: ${CONTAINER_NAME}-nginx image: nginx:1.29.2-alpine restart: unless-stopped env_file: .env @@ -55,7 +52,6 @@ services: depends_on: - wordpress - database - container_name: ${CONTAINER_NAME}-wp-init image: wordpress:cli env_file: .env environment: @@ -72,7 +68,6 @@ services: db-backup: depends_on: - database - container_name: ${CONTAINER_NAME}-db-backup image: mysql:8.4.7 env_file: .env environment: diff --git a/nginx/dev.conf.template b/nginx/dev.conf.template index 64a0e44..faf13c1 100644 --- a/nginx/dev.conf.template +++ b/nginx/dev.conf.template @@ -1,31 +1,31 @@ server { - listen 80; - server_name ${SERVER_NAME}; + listen 80; + server_name ${SERVER_NAME}; - root /var/www/html; - index index.php index.html; + root /var/www/html; + index index.php index.html; - add_header X-Frame-Options "SAMEORIGIN"; - add_header X-Content-Type-Options "nosniff"; - add_header X-XSS-Protection "1; mode=block"; + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + add_header X-XSS-Protection "1; mode=block"; - location / { - try_files $uri $uri/ /index.php?$args; - } + location / { + try_files $uri $uri/ /index.php?$args; + } - location ~ \.php$ { - include fastcgi_params; - try_files $uri =404; + location ~ \.php$ { + include fastcgi_params; + try_files $uri =404; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass wordpress:9000; - fastcgi_index index.php; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass wordpress:9000; + fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - } + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } - location ~ /\.ht { - deny all; - } -} \ No newline at end of file + location ~ /\.ht { + deny all; + } +} diff --git a/nginx/prod.conf.template b/nginx/prod.conf.template index ce89145..2aa53d7 100644 --- a/nginx/prod.conf.template +++ b/nginx/prod.conf.template @@ -1,56 +1,56 @@ server { - listen 80; - server_name ${SERVER_NAME}; + listen 80; + server_name ${SERVER_NAME}; - location /.well-known/acme-challenge/ { - root /var/www/certbot; - } + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } - location / { - return 301 https://$host$request_uri; - } + location / { + return 301 https://$host$request_uri; + } } server { - listen 443 ssl; - http2 on; - server_name ${SERVER_NAME}; + listen 443 ssl; + http2 on; + server_name ${SERVER_NAME}; - root /var/www/html; - index index.php; + root /var/www/html; + index index.php; - ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; + ssl_certificate /etc/letsencrypt/live/${SERVER_NAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${SERVER_NAME}/privkey.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers off; - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 10m; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - add_header X-Content-Type-Options nosniff; - add_header X-Frame-Options SAMEORIGIN; - add_header X-XSS-Protection "1; mode=block"; - add_header Referrer-Policy strict-origin-when-cross-origin; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options SAMEORIGIN; + add_header X-XSS-Protection "1; mode=block"; + add_header Referrer-Policy strict-origin-when-cross-origin; - location / { - try_files $uri $uri/ /index.php?$args; - } + location / { + try_files $uri $uri/ /index.php?$args; + } - location ~ \.php$ { - include fastcgi_params; + location ~ \.php$ { + include fastcgi_params; - fastcgi_pass wordpress:9000; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_pass wordpress:9000; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_buffers 16 16k; - fastcgi_buffer_size 32k; - fastcgi_read_timeout 60s; - } + fastcgi_buffers 16 16k; + fastcgi_buffer_size 32k; + fastcgi_read_timeout 60s; + } - location ~ /\.(?!well-known) { - deny all; - } + location ~ /\.(?!well-known) { + deny all; + } } diff --git a/scripts/db-backup/entrypoint.sh b/scripts/db-backup/entrypoint.sh index 59f4260..a9fe2e0 100644 --- a/scripts/db-backup/entrypoint.sh +++ b/scripts/db-backup/entrypoint.sh @@ -7,7 +7,7 @@ if [ "${SKIP_DB_BACKUP}" = "true" ]; then fi if [ ! -x /scripts/db-backup/run-db-backup-periodic.sh ]; then - echo "Error: run-db-backup-periodic.sh not found or not executable" + echo "Error: run-db-backup-periodic.sh not found or not executable" >&2 exit 1 fi diff --git a/scripts/db-backup/lib/backup.sh b/scripts/db-backup/lib/backup.sh index 8d80024..db5f180 100644 --- a/scripts/db-backup/lib/backup.sh +++ b/scripts/db-backup/lib/backup.sh @@ -1,14 +1,14 @@ #!/bin/sh do_backup() { - _db_name=$1 - _backup_dir=$2 + _db_name=$1 + _backup_dir=$2 - _timestamp=$(date +"%Y%m%d-%H%M%S") - _file="$_backup_dir/backup-$_timestamp.sql" + _timestamp=$(date +"%Y%m%d-%H%M%S") + _file="$_backup_dir/backup-$_timestamp.sql" - echo "Executing backup: $_file" - mysqldump --no-tablespaces "$_db_name" > "$_file" + echo "Executing backup: $_file" + mysqldump --no-tablespaces "$_db_name" > "$_file" - echo "Backup completed: $_file" + echo "Backup completed: $_file" } diff --git a/scripts/db-backup/lib/rotation.sh b/scripts/db-backup/lib/rotation.sh index bce77d8..ab371ba 100644 --- a/scripts/db-backup/lib/rotation.sh +++ b/scripts/db-backup/lib/rotation.sh @@ -1,20 +1,20 @@ #!/bin/sh rotate_backups() { - _backup_dir="$1" - _max_files="$2" + _backup_dir="$1" + _max_files="$2" - _count=$(find "$_backup_dir" -maxdepth 1 -type f -name '*.sql' | wc -l | tr -d ' ') + _count=$(find "$_backup_dir" -maxdepth 1 -type f -name '*.sql' | wc -l | tr -d ' ') - if [ "$_count" -gt "$_max_files" ]; then - _remove=$((_count - _max_files)) - echo "Limit exceeded ($_count > $_max_files). Removing $_remove oldest backup(s)" + if [ "$_count" -gt "$_max_files" ]; then + _remove=$((_count - _max_files)) + echo "Limit exceeded ($_count > $_max_files). Removing $_remove oldest backup(s)" - find "$_backup_dir" -maxdepth 1 -type f -name '*.sql' -print0 \ - | xargs -0 stat --printf '%Y %n\n' \ - | sort -n \ - | head -n "$_remove" \ - | cut -d' ' -f2- \ - | xargs rm -f - fi + find "$_backup_dir" -maxdepth 1 -type f -name '*.sql' -print0 \ + | xargs -0 stat --printf '%Y %n\n' \ + | sort -n \ + | head -n "$_remove" \ + | cut -d' ' -f2- \ + | xargs rm -f + fi } diff --git a/scripts/db-backup/run-db-backup-periodic.sh b/scripts/db-backup/run-db-backup-periodic.sh index bdc67f6..2aca747 100644 --- a/scripts/db-backup/run-db-backup-periodic.sh +++ b/scripts/db-backup/run-db-backup-periodic.sh @@ -20,9 +20,9 @@ echo "Initial delay: $(format_interval "$BACKUP_INITIAL_DELAY_SEC")" sleep "$BACKUP_INITIAL_DELAY_SEC" while true; do - do_backup "$DB_NAME" "$BACKUP_DIR" - rotate_backups "$BACKUP_DIR" "$BACKUP_MAX_FILES" + do_backup "$DB_NAME" "$BACKUP_DIR" + rotate_backups "$BACKUP_DIR" "$BACKUP_MAX_FILES" - echo "Waiting $(format_interval "$BACKUP_INTERVAL_SEC") until next backup..." - sleep "$BACKUP_INTERVAL_SEC" + echo "Waiting $(format_interval "$BACKUP_INTERVAL_SEC") until next backup..." + sleep "$BACKUP_INTERVAL_SEC" done diff --git a/scripts/db-cli/run-db-restore.sh b/scripts/db-cli/run-db-restore.sh index 4c5bfd5..c61c0df 100644 --- a/scripts/db-cli/run-db-restore.sh +++ b/scripts/db-cli/run-db-restore.sh @@ -6,16 +6,16 @@ set -e FILE="$1" if [ -z "$FILE" ]; then - echo "ERROR: No SQL file provided" - exit 1 + echo "Error: no SQL file provided" >&2 + exit 1 fi BASE="/db/init" SQL_PATH="$BASE/$FILE" if [ ! -f "$SQL_PATH" ]; then - echo "ERROR: SQL file not found: $SQL_PATH" - exit 1 + echo "Error: SQL file not found: $SQL_PATH" >&2 + exit 1 fi echo "Creating DB client config" diff --git a/scripts/db-common/create-db-client-config.sh b/scripts/db-common/create-db-client-config.sh index 317ceac..5af8284 100644 --- a/scripts/db-common/create-db-client-config.sh +++ b/scripts/db-common/create-db-client-config.sh @@ -1,16 +1,12 @@ #!/bin/sh -. /scripts/utils/check-required-vars.sh - create_db_client_config() { - _db_host="${1:-database}" - _db_port="${2:-3306}" - _db_user="${3}" - _db_password="${4}" - - check_required_vars "_db_user _db_password" + _db_host="${1:-database}" + _db_port="${2:-3306}" + _db_user="${3}" + _db_password="${4}" - cat > /root/.my.cnf < /root/.my.cnf </dev/null 2>&1; do + retries=$((retries - 1)) + if [ "$retries" -le 0 ]; then + echo "Error: database not reachable at ${_db_host}:${_db_port}" >&2 + return 1 + fi echo "Database not ready, retrying in 3 seconds..." sleep 3 done diff --git a/scripts/utils/check-required-vars.sh b/scripts/utils/check-required-vars.sh index fd6cbf2..300c1c6 100644 --- a/scripts/utils/check-required-vars.sh +++ b/scripts/utils/check-required-vars.sh @@ -1,11 +1,18 @@ #!/bin/sh check_required_vars() { - REQUIRED_VARS="$1" - for VAR in $REQUIRED_VARS; do - if [ -z "$(eval echo \$"$VAR")" ]; then - echo "Error: missing required variable: $VAR" - exit 1 - fi + for VAR in $1; do + case "$VAR" in + *[!a-zA-Z0-9_]*) + echo "Error: invalid variable name: $VAR" >&2 + return 1 + ;; + esac + + eval "val=\${$VAR}" + [ -n "$val" ] || { + echo "Error: missing required variable: $VAR" >&2 + return 1 + } done } diff --git a/scripts/utils/interval.sh b/scripts/utils/interval.sh index 086342d..fab60d5 100644 --- a/scripts/utils/interval.sh +++ b/scripts/utils/interval.sh @@ -1,25 +1,25 @@ #!/bin/sh parse_interval() { - _value="$1" - case "$_value" in - *s) echo "${_value%s}" ;; - *m) echo "$(( ${_value%m} * 60 ))" ;; - *h) echo "$(( ${_value%h} * 3600 ))" ;; - *d) echo "$(( ${_value%d} * 86400 ))" ;; - *) echo "$_value" ;; - esac + _value="$1" + case "$_value" in + *s) echo "${_value%s}" ;; + *m) echo "$(( ${_value%m} * 60 ))" ;; + *h) echo "$(( ${_value%h} * 3600 ))" ;; + *d) echo "$(( ${_value%d} * 86400 ))" ;; + *) echo "$_value" ;; + esac } format_interval() { - _seconds="$1" - if [ "$_seconds" -lt 60 ]; then - echo "${_seconds}s" - elif [ "$_seconds" -lt 3600 ]; then - echo "$((_seconds / 60))m" - elif [ "$_seconds" -lt 86400 ]; then - echo "$((_seconds / 3600))h" - else - echo "$((_seconds / 86400))d" - fi + _seconds="$1" + if [ "$_seconds" -lt 60 ]; then + echo "${_seconds}s" + elif [ "$_seconds" -lt 3600 ]; then + echo "$((_seconds / 60))m" + elif [ "$_seconds" -lt 86400 ]; then + echo "$((_seconds / 3600))h" + else + echo "$((_seconds / 86400))d" + fi } diff --git a/scripts/wp-cli/check-wp-cli.sh b/scripts/wp-cli/check-wp-cli.sh index 4636ef2..927c575 100644 --- a/scripts/wp-cli/check-wp-cli.sh +++ b/scripts/wp-cli/check-wp-cli.sh @@ -6,8 +6,8 @@ check_wp_cli() { fi if ! command -v wp >/dev/null 2>&1; then - echo "Error: WP-CLI is not installed or not in PATH" - exit 1 + echo "Error: WP-CLI is not installed or not in PATH" >&2 + return 1 fi export WP_CLI_READY=true diff --git a/scripts/wp-cli/check-wp-installed.sh b/scripts/wp-cli/check-wp-installed.sh index 54fb4e3..eceac09 100644 --- a/scripts/wp-cli/check-wp-installed.sh +++ b/scripts/wp-cli/check-wp-installed.sh @@ -12,5 +12,4 @@ check_wp_installed() { export WP_INSTALLED_READY=true echo "WordPress database is available" - return 0 } diff --git a/scripts/wp-cli/check-wp-path.sh b/scripts/wp-cli/check-wp-path.sh index e0c83e4..9320813 100644 --- a/scripts/wp-cli/check-wp-path.sh +++ b/scripts/wp-cli/check-wp-path.sh @@ -2,14 +2,14 @@ check_wp_path() { if [ -z "$WORDPRESS_PATH" ]; then - echo "Error: WORDPRESS_PATH is not set" - exit 1 + echo "Error: WORDPRESS_PATH is not set" >&2 + return 1 fi if [ ! -d "$WORDPRESS_PATH" ]; then - echo "Error: WordPress path '$WORDPRESS_PATH' does not exist" - exit 1 + echo "Error: WordPress path '$WORDPRESS_PATH' does not exist" >&2 + return 1 fi - cd "$WORDPRESS_PATH" || exit 1 + cd "$WORDPRESS_PATH" || return 1 } diff --git a/scripts/wp-init/entrypoint.sh b/scripts/wp-init/entrypoint.sh index dfdfe12..c24d0ed 100644 --- a/scripts/wp-init/entrypoint.sh +++ b/scripts/wp-init/entrypoint.sh @@ -7,7 +7,7 @@ if [ "${SKIP_WP_INIT}" = "true" ]; then fi if [ ! -x /scripts/wp-init/run-wp-init.sh ]; then - echo "Error: run-wp-init.sh not found or not executable" + echo "Error: run-wp-init.sh not found or not executable" >&2 exit 1 fi diff --git a/scripts/wp-init/site-url/get-current-site-url.sh b/scripts/wp-init/site-url/get-current-site-url.sh index 4560f31..ab894d0 100644 --- a/scripts/wp-init/site-url/get-current-site-url.sh +++ b/scripts/wp-init/site-url/get-current-site-url.sh @@ -16,7 +16,7 @@ check_wp_installed || exit 0 CURRENT_SITE_URL=$(wp option get siteurl --allow-root 2>/dev/null || true) if [ -z "$CURRENT_SITE_URL" ]; then - echo "Error: unable to detect current site URL from database" + echo "Error: unable to detect current site URL from database" >&2 exit 1 fi diff --git a/scripts/wp-init/site-url/update-site-url.sh b/scripts/wp-init/site-url/update-site-url.sh index 64d6b46..4cbf2cc 100644 --- a/scripts/wp-init/site-url/update-site-url.sh +++ b/scripts/wp-init/site-url/update-site-url.sh @@ -35,6 +35,6 @@ if wp search-replace "$CURRENT_SITE_URL" "$SITE_URL" \ --allow-root; then echo "Site URL update completed successfully" else - echo "Error: WP-CLI command failed" + echo "Error: WP-CLI command failed" >&2 exit 1 fi