| Server IP : 119.195.102.159 / Your IP : 216.73.217.134 Web Server : nginx/1.18.0 System : Linux picell 5.15.0-181-generic #191-Ubuntu SMP Fri May 22 19:09:02 UTC 2026 x86_64 User : altablue ( 1000) PHP Version : 8.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /tmp/ |
Upload File : |
#!/usr/bin/env bash
set -Eeuo pipefail
readonly ADMIN_USER="altablue"
readonly WP_SOURCE="/home2/wordpress"
readonly PHP_VERSION="8.3"
readonly CERT_EMAIL="admin@picell.biz"
readonly CREDENTIAL_DIR="/home/altablue/.site-credentials"
usage() {
cat <<USAGE
사용법:
sudo $0 example.com /home2/example
sudo $0 example.com -d www.example.com /home2/example
환경변수:
STAGING=1 Let's Encrypt 시험 인증서 사용
USAGE
exit 1
}
fail() {
echo "❌ $*" >&2
exit 1
}
on_exit() {
local status=$?
unset MYSQL_PWD MYSQL_ADMIN_PASSWORD 2>/dev/null || true
if [[ -n "${ACME_TEST_FILE:-}" ]]; then
rm -f -- "$ACME_TEST_FILE" 2>/dev/null || true
fi
if (( status != 0 )); then
echo "❌ 설정이 중단되었습니다. 위 오류를 확인하세요." >&2
echo " 기존 사이트나 DB는 자동 삭제하지 않았습니다." >&2
fi
}
trap on_exit EXIT
require_command() {
command -v "$1" >/dev/null 2>&1 || fail "필수 명령이 없습니다: $1"
}
valid_domain() {
[[ "$1" =~ ^([A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$ ]]
}
trim_argument() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
printf '%s' "$value"
}
mysql_root() {
case "${MYSQL_AUTH_MODE:-password}" in
login-path) mysql --login-path=setup-host "$@" ;;
socket) mysql --protocol=socket -uroot "$@" ;;
password) MYSQL_PWD="${MYSQL_ADMIN_PASSWORD:-}" mysql --protocol=socket -uroot "$@" ;;
*) fail "알 수 없는 MySQL 인증 방식입니다." ;;
esac
}
if (( EUID != 0 )); then
fail "sudo로 실행해야 합니다."
fi
if [[ $# -eq 2 ]]; then
DOMAIN="$1"
ROOT_INPUT="$2"
ADD_DOMAIN=""
elif [[ $# -eq 4 && "$2" == "-d" ]]; then
DOMAIN="$1"
ADD_DOMAIN="$3"
ROOT_INPUT="$4"
else
usage
fi
DOMAIN="$(trim_argument "$DOMAIN")"
ADD_DOMAIN="$(trim_argument "$ADD_DOMAIN")"
ROOT_INPUT="$(trim_argument "$ROOT_INPUT")"
valid_domain "$DOMAIN" || fail "올바르지 않은 도메인입니다: $DOMAIN"
if [[ -n "$ADD_DOMAIN" ]]; then
valid_domain "$ADD_DOMAIN" || fail "올바르지 않은 추가 도메인입니다: $ADD_DOMAIN"
fi
for command_name in certbot curl find getent groupadd nginx openssl php php-fpm8.3 \
readlink systemctl useradd usermod wp mysql; do
require_command "$command_name"
done
getent passwd "$ADMIN_USER" >/dev/null || fail "관리 사용자가 없습니다: $ADMIN_USER"
ROOT_DIR="$(readlink -m -- "$ROOT_INPUT")"
[[ "$ROOT_DIR" != *[[:space:]]* ]] || fail "공백이 포함된 웹루트 경로는 지원하지 않습니다: $ROOT_DIR"
case "$ROOT_DIR" in
/home/*|/home2/*) ;;
*) fail "웹루트는 /home 또는 /home2 아래여야 합니다: $ROOT_DIR" ;;
esac
[[ "$ROOT_DIR" != "/home" && "$ROOT_DIR" != "/home2" ]] || fail "상위 홈 디렉터리는 웹루트로 사용할 수 없습니다."
SITE_KEY="$(basename -- "$ROOT_DIR" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '_' | sed 's/^_*//; s/_*$//' | cut -c1-24)"
[[ -n "$SITE_KEY" ]] || fail "경로에서 사이트 식별자를 만들 수 없습니다."
PHP_USER="wp_${SITE_KEY}"
SITE_GROUP="site_${SITE_KEY}"
DB_NAME="wp_${SITE_KEY}"
DB_USER="wp_${SITE_KEY}"
POOL_NAME="site_${SITE_KEY}"
POOL_FILE="/etc/php/${PHP_VERSION}/fpm/pool.d/${POOL_NAME}.conf"
PHP_SOCKET="/run/php/php${PHP_VERSION}-fpm-${SITE_KEY}.sock"
NGINX_SNIPPET="/etc/nginx/snippets/${POOL_NAME}.conf"
CONF_FILE="/etc/nginx/sites-available/${DOMAIN}.conf"
ENABLED_FILE="/etc/nginx/sites-enabled/${DOMAIN}.conf"
ACCESS_LOG="/var/log/nginx/${DOMAIN}.access.log"
ERROR_LOG="/var/log/nginx/${DOMAIN}.error.log"
PHP_ERROR_LOG="/var/log/php${PHP_VERSION}-fpm-${SITE_KEY}.log"
ACME_DIR="${ROOT_DIR}/.well-known/acme-challenge"
ACME_TEST_FILE="${ACME_DIR}/setup-test.txt"
STAGING="${STAGING:-0}"
SERVER_NAMES="$DOMAIN"
CERT_DOMAINS=(-d "$DOMAIN")
ALL_DOMAINS=("$DOMAIN")
if [[ -n "$ADD_DOMAIN" ]]; then
SERVER_NAMES+=" $ADD_DOMAIN"
CERT_DOMAINS+=(-d "$ADD_DOMAIN")
ALL_DOMAINS+=("$ADD_DOMAIN")
fi
# DNS/인증서 조건을 가장 먼저 확인하여 사용자, 그룹, 웹루트 또는 임시
# Nginx 설정만 남는 부분 설치를 방지한다. Cloudflare 프록시 IP도 정상이다.
for check_domain in "${ALL_DOMAINS[@]}"; do
getent ahostsv4 "$check_domain" >/dev/null 2>&1 \
|| fail "DNS A 레코드를 확인할 수 없습니다: $check_domain"
done
if [[ -e "$ROOT_DIR" ]] && find "$ROOT_DIR" -mindepth 1 \
! -path "$ROOT_DIR/.well-known" \
! -path "$ROOT_DIR/.well-known/*" -print -quit | grep -q .; then
fail "웹루트가 비어 있지 않습니다. 기존 파일 보호를 위해 중단합니다: $ROOT_DIR"
fi
ADOPT_EXISTING_NGINX=0
if [[ -e "$CONF_FILE" ]]; then
[[ -f "$CONF_FILE" && ! -L "$CONF_FILE" ]] || fail "기존 Nginx 설정이 일반 파일이 아닙니다: $CONF_FILE"
mapfile -t EXISTING_ROOTS < <(
awk '$1 == "root" { gsub(/;/, "", $2); print $2 }' "$CONF_FILE" |
tr -d '\r' | sort -u
)
(( ${#EXISTING_ROOTS[@]} > 0 )) || fail "기존 Nginx 설정에서 root를 확인할 수 없습니다: $CONF_FILE"
for existing_root in "${EXISTING_ROOTS[@]}"; do
existing_root="$(readlink -m -- "$existing_root")"
[[ "$existing_root" == "$ROOT_DIR" ]] \
|| fail "기존 Nginx root가 요청 경로와 다릅니다: $existing_root != $ROOT_DIR"
done
EXISTING_SERVER_NAMES="$(
awk '$1 == "server_name" { for (i = 2; i <= NF; i++) { gsub(/;/, "", $i); print $i } }' "$CONF_FILE" |
tr -d '\r' | sort -u
)"
for requested_name in "${ALL_DOMAINS[@]}"; do
grep -Fxq "$requested_name" <<<"$EXISTING_SERVER_NAMES" \
|| fail "기존 Nginx 설정에 요청 도메인이 없습니다: $requested_name"
done
ADOPT_EXISTING_NGINX=1
fi
if [[ -e "$ENABLED_FILE" || -L "$ENABLED_FILE" ]]; then
[[ -L "$ENABLED_FILE" ]] || fail "sites-enabled 항목이 심볼릭 링크가 아닙니다: $ENABLED_FILE"
[[ "$(readlink -f -- "$ENABLED_FILE")" == "$(readlink -f -- "$CONF_FILE")" ]] \
|| fail "sites-enabled 링크가 다른 설정을 가리킵니다: $ENABLED_FILE"
(( ADOPT_EXISTING_NGINX == 1 )) || fail "sites-enabled 링크만 존재하고 원본 설정이 없습니다."
fi
[[ ! -e "$POOL_FILE" && ! -e "$NGINX_SNIPPET" ]] || fail "사이트 PHP-FPM 설정이 이미 존재합니다: $SITE_KEY"
# 직전 실행이 인증서 단계에서 멈춘 경우, 스크립트가 만든 계정/그룹을 검증 후 재사용한다.
if getent group "$SITE_GROUP" >/dev/null; then
[[ "$(getent group "$SITE_GROUP" | cut -d: -f3)" -lt 1000 ]] \
|| fail "기존 사이트 그룹이 시스템 그룹이 아닙니다: $SITE_GROUP"
fi
if getent passwd "$PHP_USER" >/dev/null; then
[[ "$(getent passwd "$PHP_USER" | cut -d: -f6)" == "$ROOT_DIR" ]] \
|| fail "기존 PHP 사용자의 홈 경로가 다릅니다: $PHP_USER"
[[ "$(id -gn "$PHP_USER")" == "$SITE_GROUP" ]] \
|| fail "기존 PHP 사용자의 기본 그룹이 다릅니다: $PHP_USER"
[[ "$(getent passwd "$PHP_USER" | cut -d: -f7)" == "/usr/sbin/nologin" ]] \
|| fail "기존 PHP 사용자의 셸이 안전하지 않습니다: $PHP_USER"
fi
read -r -p "WordPress를 설치하시겠습니까? [y/N]: " WP_ANSWER
case "$WP_ANSWER" in
y|Y|yes|YES) INSTALL_WORDPRESS=1 ;;
*) INSTALL_WORDPRESS=0 ;;
esac
if (( INSTALL_WORDPRESS )); then
[[ -f "$WP_SOURCE/wp-includes/version.php" ]] || fail "WordPress 원본이 없습니다: $WP_SOURCE"
WP_VERSION="$(php -r 'include $argv[1]; echo $wp_version;' "$WP_SOURCE/wp-includes/version.php")"
echo "🔎 WordPress ${WP_VERSION} 원본 체크섬을 확인합니다."
wp core verify-checksums \
--path="$WP_SOURCE" \
--version="$WP_VERSION" \
--locale=ko_KR \
--allow-root >/dev/null || fail "WordPress 원본 체크섬이 일치하지 않습니다."
if mysql --login-path=setup-host -NBe 'SELECT 1' >/dev/null 2>&1; then
MYSQL_AUTH_MODE="login-path"
MYSQL_ADMIN_PASSWORD=""
elif mysql --protocol=socket -uroot -NBe 'SELECT 1' >/dev/null 2>&1; then
MYSQL_AUTH_MODE="socket"
MYSQL_ADMIN_PASSWORD=""
else
MYSQL_AUTH_MODE="password"
read -r -s -p "MySQL root 비밀번호: " MYSQL_ADMIN_PASSWORD
echo
mysql_root -NBe 'SELECT 1' >/dev/null 2>&1 || fail "MySQL root 인증에 실패했습니다."
fi
mysql_root -NBe "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='${DB_NAME}'" | grep -q . \
&& fail "데이터베이스가 이미 존재합니다: $DB_NAME"
mysql_root -NBe "SELECT User FROM mysql.user WHERE User='${DB_USER}' AND Host='localhost'" | grep -q . \
&& fail "DB 사용자가 이미 존재합니다: ${DB_USER}@localhost"
fi
echo "----------------------------------------------------"
echo "도메인 : $SERVER_NAMES"
echo "웹루트 : $ROOT_DIR"
echo "PHP 사용자 : $PHP_USER"
echo "사이트 그룹 : $SITE_GROUP"
echo "WordPress : $([[ $INSTALL_WORDPRESS -eq 1 ]] && echo yes || echo no)"
echo "----------------------------------------------------"
if (( ADOPT_EXISTING_NGINX )); then
EXISTING_CONF_BACKUP="${CONF_FILE}.$(date +%Y%m%d-%H%M%S).adopt.bak"
cp -a -- "$CONF_FILE" "$EXISTING_CONF_BACKUP"
chmod 0640 "$EXISTING_CONF_BACKUP"
echo "ℹ️ 기존 Nginx 설정을 인계합니다. 백업: $EXISTING_CONF_BACKUP"
fi
# 사이트 전용 계정과 공유 그룹. altablue와 이 사이트 PHP만 쓰기 권한을 공유한다.
getent group "$SITE_GROUP" >/dev/null || groupadd --system "$SITE_GROUP"
getent passwd "$PHP_USER" >/dev/null \
|| useradd --system --gid "$SITE_GROUP" --home-dir "$ROOT_DIR" --shell /usr/sbin/nologin "$PHP_USER"
usermod -aG "$SITE_GROUP" "$ADMIN_USER"
install -d -m 2775 -o "$PHP_USER" -g "$SITE_GROUP" "$ROOT_DIR"
install -d -m 2775 -o "$PHP_USER" -g "$SITE_GROUP" "$ACME_DIR"
# 그룹 협업 파일이 FTP/PHP 어느 쪽에서 생성되어도 664/775가 되도록 한다.
install -d -m 0755 /etc/systemd/system/php${PHP_VERSION}-fpm.service.d
cat > "/etc/systemd/system/php${PHP_VERSION}-fpm.service.d/20-site-group-umask.conf" <<'UMASK_EOF'
[Service]
UMask=0002
UMASK_EOF
# 인증서 발급을 위한 임시 HTTP 가상호스트.
cat > "$CONF_FILE" <<NGINX_HTTP
server {
listen 80;
listen [::]:80;
server_name $SERVER_NAMES;
root $ROOT_DIR;
access_log $ACCESS_LOG combined;
error_log $ERROR_LOG warn;
location ^~ /.well-known/acme-challenge/ {
root $ROOT_DIR;
default_type text/plain;
try_files \$uri =404;
allow all;
}
location / { return 301 https://\$host\$request_uri; }
}
NGINX_HTTP
ln -sfn "$CONF_FILE" "$ENABLED_FILE"
nginx -t
systemctl reload nginx
printf '%s\n' "acme-local-ok" > "$ACME_TEST_FILE"
chown "$PHP_USER:$SITE_GROUP" "$ACME_TEST_FILE"
chmod 0664 "$ACME_TEST_FILE"
LOCAL_RESULT=""
for _ in {1..12}; do
LOCAL_RESULT="$(curl -fsS --resolve "${DOMAIN}:80:127.0.0.1" \
"http://${DOMAIN}/.well-known/acme-challenge/setup-test.txt" 2>/dev/null || true)"
[[ "$LOCAL_RESULT" == "acme-local-ok" ]] && break
sleep 0.25
done
[[ "$LOCAL_RESULT" == "acme-local-ok" ]] || fail "ACME 로컬 경로 테스트에 실패했습니다."
CERTBOT_EXTRA_ARGS=()
[[ "$STAGING" == "1" ]] && CERTBOT_EXTRA_ARGS+=(--staging)
certbot certonly \
"${CERTBOT_EXTRA_ARGS[@]}" \
--webroot -w "$ROOT_DIR" \
"${CERT_DOMAINS[@]}" \
--email "$CERT_EMAIL" \
--agree-tos --no-eff-email --keep-until-expiring
CERT_DIR="/etc/letsencrypt/live/${DOMAIN}"
[[ -f "$CERT_DIR/fullchain.pem" && -f "$CERT_DIR/privkey.pem" ]] || fail "인증서 파일을 찾을 수 없습니다: $CERT_DIR"
if (( INSTALL_WORDPRESS )); then
echo "📦 WordPress 원본을 복사합니다: $WP_SOURCE"
cp -a "$WP_SOURCE"/. "$ROOT_DIR"/
DB_PASSWORD="$(openssl rand -hex 24)"
AUTH_KEY="$(openssl rand -hex 32)"
SECURE_AUTH_KEY="$(openssl rand -hex 32)"
LOGGED_IN_KEY="$(openssl rand -hex 32)"
NONCE_KEY="$(openssl rand -hex 32)"
AUTH_SALT="$(openssl rand -hex 32)"
SECURE_AUTH_SALT="$(openssl rand -hex 32)"
LOGGED_IN_SALT="$(openssl rand -hex 32)"
NONCE_SALT="$(openssl rand -hex 32)"
mysql_root <<SQL
CREATE DATABASE \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASSWORD}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
FLUSH PRIVILEGES;
SQL
cat > "$ROOT_DIR/wp-config.php" <<WP_CONFIG
<?php
define( 'DB_NAME', '${DB_NAME}' );
define( 'DB_USER', '${DB_USER}' );
define( 'DB_PASSWORD', '${DB_PASSWORD}' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
define( 'AUTH_KEY', '${AUTH_KEY}' );
define( 'SECURE_AUTH_KEY', '${SECURE_AUTH_KEY}' );
define( 'LOGGED_IN_KEY', '${LOGGED_IN_KEY}' );
define( 'NONCE_KEY', '${NONCE_KEY}' );
define( 'AUTH_SALT', '${AUTH_SALT}' );
define( 'SECURE_AUTH_SALT', '${SECURE_AUTH_SALT}' );
define( 'LOGGED_IN_SALT', '${LOGGED_IN_SALT}' );
define( 'NONCE_SALT', '${NONCE_SALT}' );
\$table_prefix = 'wp_';
define( 'WP_DEBUG', false );
define( 'DISALLOW_FILE_EDIT', true );
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';
WP_CONFIG
install -d -m 0700 -o "$ADMIN_USER" -g "$ADMIN_USER" "$CREDENTIAL_DIR"
CREDENTIAL_FILE="${CREDENTIAL_DIR}/${DOMAIN}.conf"
cat > "$CREDENTIAL_FILE" <<CREDENTIALS
DOMAIN=${DOMAIN}
WEB_ROOT=${ROOT_DIR}
PHP_USER=${PHP_USER}
SITE_GROUP=${SITE_GROUP}
DB_NAME=${DB_NAME}
DB_USER=${DB_USER}
DB_PASSWORD=${DB_PASSWORD}
CREDENTIALS
chown "$ADMIN_USER:$ADMIN_USER" "$CREDENTIAL_FILE"
chmod 0600 "$CREDENTIAL_FILE"
fi
install -d -m 2770 -o "$PHP_USER" -g "$SITE_GROUP" "$ROOT_DIR/.php-tmp" "$ROOT_DIR/.php-sessions"
# 복사 원본의 777 권한을 사용하지 않고, FTP와 WordPress가 공유할 그룹 쓰기 권한만 둔다.
chown -R "$PHP_USER:$SITE_GROUP" "$ROOT_DIR"
find "$ROOT_DIR" -xdev -type d -exec chmod 2775 {} +
find "$ROOT_DIR" -xdev -type f -exec chmod 0664 {} +
chmod 2770 "$ROOT_DIR/.php-tmp" "$ROOT_DIR/.php-sessions"
if [[ -f "$ROOT_DIR/wp-config.php" ]]; then
chmod 0640 "$ROOT_DIR/wp-config.php"
fi
install -m 0640 -o "$PHP_USER" -g "$SITE_GROUP" /dev/null "$PHP_ERROR_LOG"
cat > "$POOL_FILE" <<FPM_POOL
[$POOL_NAME]
user = $PHP_USER
group = $SITE_GROUP
listen = $PHP_SOCKET
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 20s
pm.max_requests = 500
chdir = $ROOT_DIR
clear_env = yes
catch_workers_output = yes
security.limit_extensions = .php
php_admin_value[open_basedir] = $ROOT_DIR:/tmp:/var/tmp
php_admin_value[upload_tmp_dir] = $ROOT_DIR/.php-tmp
php_admin_value[session.save_path] = $ROOT_DIR/.php-sessions
php_admin_flag[log_errors] = on
php_admin_value[error_log] = $PHP_ERROR_LOG
FPM_POOL
if (( INSTALL_WORDPRESS )); then
cat > "$NGINX_SNIPPET" <<NGINX_SNIPPET_WP
charset utf-8;
location / {
try_files \$uri \$uri/ /index.php?\$args;
}
location = /wp-config.php { deny all; }
location ~ /\.(?!well-known) { deny all; }
location ~* ^/wp-content/(?:uploads|cache|upgrade)/.*\.(?:php|phtml|php5|phar|cgi|pl|py|sh)$ {
deny all;
access_log off;
log_not_found off;
}
location ~ \.php(?:\$|/) {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:$PHP_SOCKET;
fastcgi_param HTTP_AUTHORIZATION \$http_authorization;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
}
location ~* ^/wp-json/ {
rewrite ^/wp-json/(.*?)\$ /index.php?rest_route=/\$1 last;
}
location ~* \.(?:jpg|jpeg|png|gif|css|js|ico|svg|ttf|woff2?|eot)\$ {
charset utf-8;
try_files \$uri =404;
access_log off;
expires 30d;
}
NGINX_SNIPPET_WP
else
cat > "$NGINX_SNIPPET" <<NGINX_SNIPPET_GENERIC
charset utf-8;
location / {
try_files \$uri \$uri/ =404;
}
location ~ /\.(?!well-known) { deny all; }
location ~ \.php(?:\$|/) {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:$PHP_SOCKET;
fastcgi_connect_timeout 60s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300s;
}
NGINX_SNIPPET_GENERIC
fi
cat > "$CONF_FILE" <<NGINX_FINAL
server {
listen 80;
listen [::]:80;
server_name $SERVER_NAMES;
root $ROOT_DIR;
access_log $ACCESS_LOG combined;
error_log $ERROR_LOG warn;
location ^~ /.well-known/acme-challenge/ {
root $ROOT_DIR;
default_type text/plain;
try_files \$uri =404;
allow all;
}
location / { return 301 https://\$host\$request_uri; }
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name $SERVER_NAMES;
root $ROOT_DIR;
index index.php index.html index.htm;
access_log $ACCESS_LOG combined;
error_log $ERROR_LOG warn;
ssl_certificate $CERT_DIR/fullchain.pem;
ssl_certificate_key $CERT_DIR/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
include $NGINX_SNIPPET;
}
NGINX_FINAL
php-fpm8.3 -t
systemctl daemon-reload
systemctl restart "php${PHP_VERSION}-fpm"
nginx -t
systemctl reload nginx
rm -f -- "$ACME_TEST_FILE"
echo
echo "✅ 신규 사이트 설정이 완료되었습니다."
echo "도메인 : $SERVER_NAMES"
echo "웹루트 : $ROOT_DIR"
echo "PHP 사용자 : $PHP_USER"
echo "사이트 그룹 : $SITE_GROUP"
echo "PHP 소켓 : $PHP_SOCKET"
if (( INSTALL_WORDPRESS )); then
echo "DB 정보 : ${CREDENTIAL_DIR}/${DOMAIN}.conf (altablue 전용 600)"
echo "WordPress : https://${DOMAIN}/wp-admin/install.php 에서 관리자 계정을 만드세요."
fi
echo "FTP/SFTP를 다시 연결하면 altablue의 새 그룹 권한이 적용됩니다."