setup_hosting.sh
· 12 KiB · Bash
Исходник
#!/bin/bash
# =============================================================================
# Настройка на Хостинг сървър с Cloudflare Tunnel
# Автор: Федя Серафиев | itpraktika.com
# =============================================================================
set -euo pipefail
# ── Цветове ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m'
info() { echo -e "${CYAN}ℹ️ $*${RESET}"; }
success() { echo -e "${GREEN}✅ $*${RESET}"; }
warn() { echo -e "${YELLOW}⚠️ $*${RESET}"; }
error() { echo -e "${RED}❌ $*${RESET}" >&2; exit 1; }
# ── Генериране на парола ─────────────────────────────────────────────────────
gen_pass() {
openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 24
}
# ── Валидация ─────────────────────────────────────────────────────────────────
validate_yn() {
local val="$1"
[[ "$val" =~ ^[yYnN]$ ]] || error "Въведи 'y' или 'n'."
}
validate_count() {
local val="$1"
[[ "$val" =~ ^[0-2]$ ]] || error "Въведи 0, 1 или 2."
}
# =============================================================================
echo -e "\n${BOLD}════════════════════════════════════════════════════${RESET}"
echo -e "${BOLD} 🚀 Настройка на Хостинг с Cloudflare Tunnel ${RESET}"
echo -e "${BOLD}════════════════════════════════════════════════════${RESET}\n"
# ── 1. Избор на метод за Cloudflare Tunnel ────────────────────────────────────
echo -e "${BOLD}[1/4] Cloudflare Tunnel — метод на свързване${RESET}"
echo " 1) Token — въвеждаш готов токен от Cloudflare Dashboard"
echo " 2) Login — cloudflared се логва сам (ще отвори браузър / URL)"
echo ""
read -rp "Избери метод [1/2]: " cf_method
case "$cf_method" in
1)
read -rp " Въведи Tunnel Token: " cf_token
[[ -n "$cf_token" ]] || error "Токенът не може да е празен."
CLOUDFLARED_CMD='tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}'
CF_ENV_LINE=" - TUNNEL_TOKEN=\${TUNNEL_TOKEN}"
CF_TOKEN_IN_ENV="TUNNEL_TOKEN=$cf_token"
;;
2)
info "При стартиране cloudflared ще изведе URL за автентикация."
CLOUDFLARED_CMD='tunnel --no-autoupdate login'
CF_ENV_LINE=""
CF_TOKEN_IN_ENV="# TUNNEL_TOKEN= (използва се login метод)"
cf_token=""
;;
*)
error "Невалиден избор. Въведи 1 или 2."
;;
esac
# ── 2. Uptime Kuma ────────────────────────────────────────────────────────────
echo -e "\n${BOLD}[2/4] Uptime Kuma${RESET}"
read -rp "Инсталирай Uptime Kuma? (y/n): " install_kuma
validate_yn "$install_kuma"
install_kuma="${install_kuma,,}" # lowercase
# ── 3. WordPress сайтове ──────────────────────────────────────────────────────
echo -e "\n${BOLD}[3/4] WordPress сайтове${RESET}"
read -rp "Брой WordPress сайтове? (0/1/2): " wp_count
validate_count "$wp_count"
# ── 4. Генериране на пароли ───────────────────────────────────────────────────
echo -e "\n${BOLD}[4/4] Генериране на пароли...${RESET}"
DB_ROOT_PASS=$(gen_pass)
WP1_DB_PASS=$(gen_pass)
WP2_DB_PASS=$(gen_pass)
# =============================================================================
# .env файл
# =============================================================================
cat > .env <<EOF
# ── Cloudflare ────────────────────────────────────────────────────
$CF_TOKEN_IN_ENV
# ── База данни ────────────────────────────────────────────────────
DB_ROOT_PASSWORD=$DB_ROOT_PASS
WP1_DB_PASSWORD=$WP1_DB_PASS
WP2_DB_PASSWORD=$WP2_DB_PASS
EOF
chmod 600 .env
success ".env създаден (права: 600)"
# =============================================================================
# Генериране на init SQL за базите данни
# =============================================================================
mkdir -p db-init
SQL_CONTENT=""
if [[ "$wp_count" -ge 1 ]]; then
SQL_CONTENT+="CREATE DATABASE IF NOT EXISTS wp1_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n"
SQL_CONTENT+="CREATE USER IF NOT EXISTS 'wp1_user'@'%' IDENTIFIED BY '${WP1_DB_PASS}';\n"
SQL_CONTENT+="GRANT ALL PRIVILEGES ON wp1_db.* TO 'wp1_user'@'%';\n"
fi
if [[ "$wp_count" -ge 2 ]]; then
SQL_CONTENT+="CREATE DATABASE IF NOT EXISTS wp2_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n"
SQL_CONTENT+="CREATE USER IF NOT EXISTS 'wp2_user'@'%' IDENTIFIED BY '${WP2_DB_PASS}';\n"
SQL_CONTENT+="GRANT ALL PRIVILEGES ON wp2_db.* TO 'wp2_user'@'%';\n"
fi
SQL_CONTENT+="FLUSH PRIVILEGES;\n"
printf "%b" "$SQL_CONTENT" > db-init/01-init.sql
success "db-init/01-init.sql създаден"
# =============================================================================
# docker-compose.yml
# =============================================================================
cat > docker-compose.yml <<EOF
services:
# ── Cloudflare Tunnel ───────────────────────────────────────────
cloudflared:
image: cloudflare/cloudflared:latest
restart: always
command: $CLOUDFLARED_CMD
networks:
- internal
EOF
# Добавяне на environment само при token метод
if [[ -n "$CF_ENV_LINE" ]]; then
cat >> docker-compose.yml <<EOF
environment:
$CF_ENV_LINE
EOF
fi
# ── MariaDB ────────────────────────────────────────────────────────────────
cat >> docker-compose.yml <<EOF
# ── База данни ──────────────────────────────────────────────────
db:
image: mariadb:10.6
restart: always
environment:
MYSQL_ROOT_PASSWORD: \${DB_ROOT_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./db-init:/docker-entrypoint-initdb.d:ro
networks:
- internal
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
EOF
# ── Uptime Kuma ────────────────────────────────────────────────────────────
if [[ "$install_kuma" == "y" ]]; then
cat >> docker-compose.yml <<EOF
# ── Uptime Kuma ─────────────────────────────────────────────────
uptime-kuma:
image: louislam/uptime-kuma:latest
container_name: uptime-kuma
restart: always
volumes:
- kuma_data:/app/data
networks:
- internal
EOF
fi
# ── WordPress 1 ────────────────────────────────────────────────────────────
if [[ "$wp_count" -ge 1 ]]; then
cat >> docker-compose.yml <<EOF
# ── WordPress 1 ─────────────────────────────────────────────────
wp1:
image: wordpress:latest
restart: always
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp1_user
WORDPRESS_DB_PASSWORD: \${WP1_DB_PASSWORD}
WORDPRESS_DB_NAME: wp1_db
volumes:
- wp1_data:/var/www/html
networks:
- internal
EOF
fi
# ── WordPress 2 ────────────────────────────────────────────────────────────
if [[ "$wp_count" -ge 2 ]]; then
cat >> docker-compose.yml <<EOF
# ── WordPress 2 ─────────────────────────────────────────────────
wp2:
image: wordpress:latest
restart: always
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp2_user
WORDPRESS_DB_PASSWORD: \${WP2_DB_PASSWORD}
WORDPRESS_DB_NAME: wp2_db
volumes:
- wp2_data:/var/www/html
networks:
- internal
EOF
fi
# ── Networks & Volumes ─────────────────────────────────────────────────────
cat >> docker-compose.yml <<EOF
networks:
internal:
driver: bridge
volumes:
db_data:
EOF
[[ "$install_kuma" == "y" ]] && echo " kuma_data:" >> docker-compose.yml
[[ "$wp_count" -ge 1 ]] && echo " wp1_data:" >> docker-compose.yml
[[ "$wp_count" -ge 2 ]] && echo " wp2_data:" >> docker-compose.yml
success "docker-compose.yml създаден"
# =============================================================================
# Резюме
# =============================================================================
echo ""
echo -e "${BOLD}════════════════════════════════════════════════════${RESET}"
echo -e "${BOLD} 📋 Резюме на конфигурацията ${RESET}"
echo -e "${BOLD}════════════════════════════════════════════════════${RESET}"
echo -e " Cloudflare метод : ${CYAN}$([ "$cf_method" == "1" ] && echo "Token" || echo "Login")${RESET}"
echo -e " Uptime Kuma : ${CYAN}$([ "$install_kuma" == "y" ] && echo "Да" || echo "Не")${RESET}"
echo -e " WordPress сайтове: ${CYAN}$wp_count${RESET}"
echo ""
echo -e "${BOLD} Файлове:${RESET}"
echo " 📄 .env (chmod 600)"
echo " 📄 docker-compose.yml"
echo " 📄 db-init/01-init.sql"
echo ""
echo -e "${BOLD} Следваща стъпка:${RESET}"
echo -e " ${GREEN}docker compose up -d${RESET}"
echo ""
warn "Запази .env файла на сигурно място — съдържа паролите!"
echo -e "${BOLD}════════════════════════════════════════════════════${RESET}\n"
| 1 | #!/bin/bash |
| 2 | # ============================================================================= |
| 3 | # Настройка на Хостинг сървър с Cloudflare Tunnel |
| 4 | # Автор: Федя Серафиев | itpraktika.com |
| 5 | # ============================================================================= |
| 6 | |
| 7 | set -euo pipefail |
| 8 | |
| 9 | # ── Цветове ────────────────────────────────────────────────────────────────── |
| 10 | RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' |
| 11 | CYAN='\033[0;36m'; BOLD='\033[1m'; RESET='\033[0m' |
| 12 | |
| 13 | info() { echo -e "${CYAN}ℹ️ $*${RESET}"; } |
| 14 | success() { echo -e "${GREEN}✅ $*${RESET}"; } |
| 15 | warn() { echo -e "${YELLOW}⚠️ $*${RESET}"; } |
| 16 | error() { echo -e "${RED}❌ $*${RESET}" >&2; exit 1; } |
| 17 | |
| 18 | # ── Генериране на парола ───────────────────────────────────────────────────── |
| 19 | gen_pass() { |
| 20 | openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 24 |
| 21 | } |
| 22 | |
| 23 | # ── Валидация ───────────────────────────────────────────────────────────────── |
| 24 | validate_yn() { |
| 25 | local val="$1" |
| 26 | [[ "$val" =~ ^[yYnN]$ ]] || error "Въведи 'y' или 'n'." |
| 27 | } |
| 28 | |
| 29 | validate_count() { |
| 30 | local val="$1" |
| 31 | [[ "$val" =~ ^[0-2]$ ]] || error "Въведи 0, 1 или 2." |
| 32 | } |
| 33 | |
| 34 | # ============================================================================= |
| 35 | echo -e "\n${BOLD}════════════════════════════════════════════════════${RESET}" |
| 36 | echo -e "${BOLD} 🚀 Настройка на Хостинг с Cloudflare Tunnel ${RESET}" |
| 37 | echo -e "${BOLD}════════════════════════════════════════════════════${RESET}\n" |
| 38 | |
| 39 | # ── 1. Избор на метод за Cloudflare Tunnel ──────────────────────────────────── |
| 40 | echo -e "${BOLD}[1/4] Cloudflare Tunnel — метод на свързване${RESET}" |
| 41 | echo " 1) Token — въвеждаш готов токен от Cloudflare Dashboard" |
| 42 | echo " 2) Login — cloudflared се логва сам (ще отвори браузър / URL)" |
| 43 | echo "" |
| 44 | read -rp "Избери метод [1/2]: " cf_method |
| 45 | |
| 46 | case "$cf_method" in |
| 47 | 1) |
| 48 | read -rp " Въведи Tunnel Token: " cf_token |
| 49 | [[ -n "$cf_token" ]] || error "Токенът не може да е празен." |
| 50 | CLOUDFLARED_CMD='tunnel --no-autoupdate run --token ${TUNNEL_TOKEN}' |
| 51 | CF_ENV_LINE=" - TUNNEL_TOKEN=\${TUNNEL_TOKEN}" |
| 52 | CF_TOKEN_IN_ENV="TUNNEL_TOKEN=$cf_token" |
| 53 | ;; |
| 54 | 2) |
| 55 | info "При стартиране cloudflared ще изведе URL за автентикация." |
| 56 | CLOUDFLARED_CMD='tunnel --no-autoupdate login' |
| 57 | CF_ENV_LINE="" |
| 58 | CF_TOKEN_IN_ENV="# TUNNEL_TOKEN= (използва се login метод)" |
| 59 | cf_token="" |
| 60 | ;; |
| 61 | *) |
| 62 | error "Невалиден избор. Въведи 1 или 2." |
| 63 | ;; |
| 64 | esac |
| 65 | |
| 66 | # ── 2. Uptime Kuma ──────────────────────────────────────────────────────────── |
| 67 | echo -e "\n${BOLD}[2/4] Uptime Kuma${RESET}" |
| 68 | read -rp "Инсталирай Uptime Kuma? (y/n): " install_kuma |
| 69 | validate_yn "$install_kuma" |
| 70 | install_kuma="${install_kuma,,}" # lowercase |
| 71 | |
| 72 | # ── 3. WordPress сайтове ────────────────────────────────────────────────────── |
| 73 | echo -e "\n${BOLD}[3/4] WordPress сайтове${RESET}" |
| 74 | read -rp "Брой WordPress сайтове? (0/1/2): " wp_count |
| 75 | validate_count "$wp_count" |
| 76 | |
| 77 | # ── 4. Генериране на пароли ─────────────────────────────────────────────────── |
| 78 | echo -e "\n${BOLD}[4/4] Генериране на пароли...${RESET}" |
| 79 | DB_ROOT_PASS=$(gen_pass) |
| 80 | WP1_DB_PASS=$(gen_pass) |
| 81 | WP2_DB_PASS=$(gen_pass) |
| 82 | |
| 83 | # ============================================================================= |
| 84 | # .env файл |
| 85 | # ============================================================================= |
| 86 | cat > .env <<EOF |
| 87 | # ── Cloudflare ──────────────────────────────────────────────────── |
| 88 | $CF_TOKEN_IN_ENV |
| 89 | |
| 90 | # ── База данни ──────────────────────────────────────────────────── |
| 91 | DB_ROOT_PASSWORD=$DB_ROOT_PASS |
| 92 | WP1_DB_PASSWORD=$WP1_DB_PASS |
| 93 | WP2_DB_PASSWORD=$WP2_DB_PASS |
| 94 | EOF |
| 95 | chmod 600 .env |
| 96 | success ".env създаден (права: 600)" |
| 97 | |
| 98 | # ============================================================================= |
| 99 | # Генериране на init SQL за базите данни |
| 100 | # ============================================================================= |
| 101 | mkdir -p db-init |
| 102 | |
| 103 | SQL_CONTENT="" |
| 104 | if [[ "$wp_count" -ge 1 ]]; then |
| 105 | SQL_CONTENT+="CREATE DATABASE IF NOT EXISTS wp1_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n" |
| 106 | SQL_CONTENT+="CREATE USER IF NOT EXISTS 'wp1_user'@'%' IDENTIFIED BY '${WP1_DB_PASS}';\n" |
| 107 | SQL_CONTENT+="GRANT ALL PRIVILEGES ON wp1_db.* TO 'wp1_user'@'%';\n" |
| 108 | fi |
| 109 | if [[ "$wp_count" -ge 2 ]]; then |
| 110 | SQL_CONTENT+="CREATE DATABASE IF NOT EXISTS wp2_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n" |
| 111 | SQL_CONTENT+="CREATE USER IF NOT EXISTS 'wp2_user'@'%' IDENTIFIED BY '${WP2_DB_PASS}';\n" |
| 112 | SQL_CONTENT+="GRANT ALL PRIVILEGES ON wp2_db.* TO 'wp2_user'@'%';\n" |
| 113 | fi |
| 114 | SQL_CONTENT+="FLUSH PRIVILEGES;\n" |
| 115 | |
| 116 | printf "%b" "$SQL_CONTENT" > db-init/01-init.sql |
| 117 | success "db-init/01-init.sql създаден" |
| 118 | |
| 119 | # ============================================================================= |
| 120 | # docker-compose.yml |
| 121 | # ============================================================================= |
| 122 | cat > docker-compose.yml <<EOF |
| 123 | services: |
| 124 | |
| 125 | # ── Cloudflare Tunnel ─────────────────────────────────────────── |
| 126 | cloudflared: |
| 127 | image: cloudflare/cloudflared:latest |
| 128 | restart: always |
| 129 | command: $CLOUDFLARED_CMD |
| 130 | networks: |
| 131 | - internal |
| 132 | EOF |
| 133 | |
| 134 | # Добавяне на environment само при token метод |
| 135 | if [[ -n "$CF_ENV_LINE" ]]; then |
| 136 | cat >> docker-compose.yml <<EOF |
| 137 | environment: |
| 138 | $CF_ENV_LINE |
| 139 | EOF |
| 140 | fi |
| 141 | |
| 142 | # ── MariaDB ──────────────────────────────────────────────────────────────── |
| 143 | cat >> docker-compose.yml <<EOF |
| 144 | |
| 145 | # ── База данни ────────────────────────────────────────────────── |
| 146 | db: |
| 147 | image: mariadb:10.6 |
| 148 | restart: always |
| 149 | environment: |
| 150 | MYSQL_ROOT_PASSWORD: \${DB_ROOT_PASSWORD} |
| 151 | volumes: |
| 152 | - db_data:/var/lib/mysql |
| 153 | - ./db-init:/docker-entrypoint-initdb.d:ro |
| 154 | networks: |
| 155 | - internal |
| 156 | healthcheck: |
| 157 | test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] |
| 158 | interval: 10s |
| 159 | timeout: 5s |
| 160 | retries: 5 |
| 161 | EOF |
| 162 | |
| 163 | # ── Uptime Kuma ──────────────────────────────────────────────────────────── |
| 164 | if [[ "$install_kuma" == "y" ]]; then |
| 165 | cat >> docker-compose.yml <<EOF |
| 166 | |
| 167 | # ── Uptime Kuma ───────────────────────────────────────────────── |
| 168 | uptime-kuma: |
| 169 | image: louislam/uptime-kuma:latest |
| 170 | container_name: uptime-kuma |
| 171 | restart: always |
| 172 | volumes: |
| 173 | - kuma_data:/app/data |
| 174 | networks: |
| 175 | - internal |
| 176 | EOF |
| 177 | fi |
| 178 | |
| 179 | # ── WordPress 1 ──────────────────────────────────────────────────────────── |
| 180 | if [[ "$wp_count" -ge 1 ]]; then |
| 181 | cat >> docker-compose.yml <<EOF |
| 182 | |
| 183 | # ── WordPress 1 ───────────────────────────────────────────────── |
| 184 | wp1: |
| 185 | image: wordpress:latest |
| 186 | restart: always |
| 187 | depends_on: |
| 188 | db: |
| 189 | condition: service_healthy |
| 190 | environment: |
| 191 | WORDPRESS_DB_HOST: db |
| 192 | WORDPRESS_DB_USER: wp1_user |
| 193 | WORDPRESS_DB_PASSWORD: \${WP1_DB_PASSWORD} |
| 194 | WORDPRESS_DB_NAME: wp1_db |
| 195 | volumes: |
| 196 | - wp1_data:/var/www/html |
| 197 | networks: |
| 198 | - internal |
| 199 | EOF |
| 200 | fi |
| 201 | |
| 202 | # ── WordPress 2 ──────────────────────────────────────────────────────────── |
| 203 | if [[ "$wp_count" -ge 2 ]]; then |
| 204 | cat >> docker-compose.yml <<EOF |
| 205 | |
| 206 | # ── WordPress 2 ───────────────────────────────────────────────── |
| 207 | wp2: |
| 208 | image: wordpress:latest |
| 209 | restart: always |
| 210 | depends_on: |
| 211 | db: |
| 212 | condition: service_healthy |
| 213 | environment: |
| 214 | WORDPRESS_DB_HOST: db |
| 215 | WORDPRESS_DB_USER: wp2_user |
| 216 | WORDPRESS_DB_PASSWORD: \${WP2_DB_PASSWORD} |
| 217 | WORDPRESS_DB_NAME: wp2_db |
| 218 | volumes: |
| 219 | - wp2_data:/var/www/html |
| 220 | networks: |
| 221 | - internal |
| 222 | EOF |
| 223 | fi |
| 224 | |
| 225 | # ── Networks & Volumes ───────────────────────────────────────────────────── |
| 226 | cat >> docker-compose.yml <<EOF |
| 227 | |
| 228 | networks: |
| 229 | internal: |
| 230 | driver: bridge |
| 231 | |
| 232 | volumes: |
| 233 | db_data: |
| 234 | EOF |
| 235 | |
| 236 | [[ "$install_kuma" == "y" ]] && echo " kuma_data:" >> docker-compose.yml |
| 237 | [[ "$wp_count" -ge 1 ]] && echo " wp1_data:" >> docker-compose.yml |
| 238 | [[ "$wp_count" -ge 2 ]] && echo " wp2_data:" >> docker-compose.yml |
| 239 | |
| 240 | success "docker-compose.yml създаден" |
| 241 | |
| 242 | # ============================================================================= |
| 243 | # Резюме |
| 244 | # ============================================================================= |
| 245 | echo "" |
| 246 | echo -e "${BOLD}════════════════════════════════════════════════════${RESET}" |
| 247 | echo -e "${BOLD} 📋 Резюме на конфигурацията ${RESET}" |
| 248 | echo -e "${BOLD}════════════════════════════════════════════════════${RESET}" |
| 249 | echo -e " Cloudflare метод : ${CYAN}$([ "$cf_method" == "1" ] && echo "Token" || echo "Login")${RESET}" |
| 250 | echo -e " Uptime Kuma : ${CYAN}$([ "$install_kuma" == "y" ] && echo "Да" || echo "Не")${RESET}" |
| 251 | echo -e " WordPress сайтове: ${CYAN}$wp_count${RESET}" |
| 252 | echo "" |
| 253 | echo -e "${BOLD} Файлове:${RESET}" |
| 254 | echo " 📄 .env (chmod 600)" |
| 255 | echo " 📄 docker-compose.yml" |
| 256 | echo " 📄 db-init/01-init.sql" |
| 257 | echo "" |
| 258 | echo -e "${BOLD} Следваща стъпка:${RESET}" |
| 259 | echo -e " ${GREEN}docker compose up -d${RESET}" |
| 260 | echo "" |
| 261 | warn "Запази .env файла на сигурно място — съдържа паролите!" |
| 262 | echo -e "${BOLD}════════════════════════════════════════════════════${RESET}\n" |
| 263 |