LXC / APM 메모
1) (호스트) dataset 만들기 — 용량 생략 가능
zfs create rpool/data/ct200-mysql
zfs create rpool/data/ct200-www
2) (호스트) LXC에 붙이기 — 용량 입력 없음
/usr/sbin/pct set 200 -mp0 /rpool/data/ct200-mysql,mp=/var/lib/mysql,backup=1
/usr/sbin/pct set 200 -mp1 /rpool/data/ct200-www,mp=/srv/www,backup=1
2-1) (호스트) 권한 부여
# 1) 컨테이너 root(=100000)에게 소유권 넘기기
chown 100000:100000 /rpool/data/ct200-mysql /rpool/data/ct200-www
# 2) 권한(디렉토리 퍼미션) 잡기
chmod 700 /rpool/data/ct200-mysql
chmod 755 /rpool/data/ct200-www
# 확인
ls -ld /rpool/data/ct200-mysql /rpool/data/ct200-www
3) 마운트 확인(가장 중요)
컨테이너 안에서:
df -hT /var/lib/mysql /srv/www
mount | egrep '/var/lib/mysql|/srv/www'
4) 기본 업데이트 + 필수 도구
apt update
apt install curl ca-certificates gnupg sudo git ufw acl
5) apache2, php8.4-fpm
apt install apache2 libapache2-mod-fcgid
a2enmod proxy_fcgi setenvif rewrite headers ssl http2 expires
add-apt-repository ppa:ondrej/php -y
apt update
apt install \
php8.4-fpm php8.4-cli php8.4-common php8.4-intl php8.4-redis php8.4-memcached \
php8.4-mysql php8.4-imagick php8.4-apcu php8.4-igbinary php8.4-opcache \
php8.4-mbstring php8.4-zip php8.4-gd php8.4-bz2 php8.4-gmp php8.4-bcmath \
php8.4-curl php8.4-xml php8.4-redis
6) vi /etc/php/8.4/fpm/conf.d/99-8G.ini
; /etc/php/8.4/fpm/conf.d/99-8G.ini
; sudo ln -s /etc/php/8.4/fpm/conf.d/99-8G.ini /etc/php/8.4/cli/conf.d/99-8G.ini
; ---------- Global settings ----------
date.timezone = Asia/Seoul
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off ; CLI에서만 필요하면 cli 전용 파일에 On
display_startup_errors = Off
log_errors = On
;allow_url_fopen = Off
post_max_size = 128M
upload_max_filesize = 128M
memory_limit = 256M
; ---------- APCu ----------
[apc]
apc.gc_ttl = 7200
apc.shm_size = 768M
apc.serializer = igbinary
; ---------- Session ----------
[session]
;session.save_path = /var/lib/php/sessions-8.4
session.gc_maxlifetime = 86400
session.gc_probability = 1
session.serialize_handler = igbinary
; ---------- OPcache ----------
[opcache]
opcache.enable = 1
opcache.enable_cli = 1
opcache.max_accelerated_files = 100000
opcache.save_comments = 0 ; 1 if you need annotations
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.revalidate_freq = 5
7) vi /etc/apache2/conf-available/zz-custom.conf
# ===== 보안/정보 노출 최소화 =====
ServerTokens Prod
ServerSignature Off
# ===== 기본 문자셋 =====
AddDefaultCharset UTF-8
# ===== HTTP/2 =====
Protocols h2 http/1.1
# ===== 전송 최적화 =====
# LXC에서 /srv/www 처럼 로컬 ZFS면 On이 무난.
# 만약 Samba/NFS 같은 "원격/네트워크 FS"로 웹루트를 붙이면 Off 권장.
EnableSendfile On
# ETag: inode 포함(FileETag INode)되면 클러스터/복제/복원 시 캐시 문제 생길 수 있어
FileETag MTime Size
# ===== 접근 로그 줄이기 (env 기반) =====
# robots.txt, wpad, 정적 파일, 로컬호스트는 로그 제외
SetEnvIf Request_URI "^/robots\.txt$" dontlog
SetEnvIf Request_URI "^/wpad\.dat$" dontlog
SetEnvIf Request_URI "\.(?:gif|png|jpe?g|ico|webp|avif|svg|css|js|map|woff2?|ttf|otf)$" dontlog
SetEnvIf Remote_Addr "^(127\.0\.0\.1|::1)$" dontlog
# access.log 쪽에서 CustomLog ... env=!dontlog 로 적용 필요
# (기본 설정에 이미 있다면 그대로 두면 됨)
# ===== 압축 제외(이미지/폰트) =====
# mod_deflate 사용 중일 때만 의미 있음
SetEnvIfNoCase Request_URI "\.(?:gif|jpe?g|png|webp|avif|ico|woff2?|ttf|otf)$" no-gzip=1
# /srv/www 전체는 웹에서 접근 금지
<Directory "/srv/www">
Require all denied
Options -Indexes
</Directory>
# 민감한 VCS 디렉토리 차단(.git/.svn 등)
<DirectoryMatch "/\.git(?:/|$)|/\.svn(?:/|$)|/\.hg(?:/|$)">
Require all denied
</DirectoryMatch>
7-1) vi /etc/php/8.4/fpm/pool.d/_common.inc
user = $pool
group = $pool
listen = /run/php/php8.4-fpm-$pool.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 2
pm.process_idle_timeout = 10s
pm.max_requests = 500
php_admin_value[open_basedir] = /srv/www/$pool:/tmp:/var/tmp
php_admin_value[session.save_path] = /var/lib/php/sessions/$pool
; (권장) PHP 에러 로그는 계정별로
php_admin_flag[log_errors] = on
php_admin_flag[display_errors] = off
php_admin_value[error_log] = /srv/www/$pool/logs/php-error.log
; (권장) 느린 요청만 잡기
slowlog = /srv/www/$pool/logs/php-fpm-slow.log
request_slowlog_timeout = 2s
7-2) bash 스크립트
sudo install -d -o root -g root -m 0711 /srv/www
vi /root/siteadd.sh
#!/usr/bin/env bash
set -euo pipefail
read -rp "계정명: " U
id "$U" >/dev/null 2>&1 || { echo "없는 계정: $U"; exit 1; }
read -rp "도메인(예: example.com): " D
[[ "$D" =~ ^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]] || { echo "도메인 형식 오류: $D"; exit 1; }
# Apache 모듈 (이미 enable이면 무시)
sudo a2enmod proxy_fcgi setenvif >/dev/null 2>&1 || true
# (참고) /srv/www 상위는 통과만 가능(목록 숨김) — 최초 1회만
# sudo install -d -o root -g root -m 0711 /srv/www
# dirs
sudo install -d -o "$U" -g "$U" -m 0700 "/var/lib/php/sessions/$U"
sudo install -d -o "$U" -g "$U" -m 0755 "/srv/www/$U/public_html"
sudo install -d -o "$U" -g "$U" -m 0750 "/srv/www/$U/logs"
# private runtime dir (not web-exposed)
sudo install -d -o "$U" -g "$U" -m 0700 "/srv/www/$U/var"
sudo setfacl -m g:www-data:rwx -m m::rwx "/srv/www/$U/logs"
sudo setfacl -d -m g:www-data:rwx -m m::rwx "/srv/www/$U/logs"
# logrotate
LR="/etc/logrotate.d/site-$U"
sudo test ! -e "$LR" || { echo "이미 존재: $LR"; exit 1; }
sudo tee "$LR" >/dev/null <<EOF
/srv/www/$U/logs/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
su $U $U
dateext
dateformat -%Y%m%d
}
EOF
sudo chmod 0644 "$LR"
# (선택) 테스트는 원할 때만
# sudo logrotate -d "$LR"
# sudo logrotate -f "$LR"
# php-fpm pool
FPM="/etc/php/8.4/fpm/pool.d/$U.conf"
sudo test ! -e "$FPM" || { echo "이미 존재: $FPM"; exit 1; }
sudo tee "$FPM" >/dev/null <<EOF
[$U]
include = /etc/php/8.4/fpm/pool.d/_common.inc
EOF
sudo chmod 0644 "$FPM"
# apache vhost
SITE="500-$U.conf"
AV="/etc/apache2/sites-available/$SITE"
SOCK="/run/php/php8.4-fpm-$U.sock"
sudo test ! -e "$AV" || { echo "이미 존재: $AV"; exit 1; }
sudo tee "$AV" >/dev/null <<EOF
<VirtualHost *:80>
ServerName $D
ServerAlias *.$D
DocumentRoot "/srv/www/$U/public_html"
ErrorLog "/srv/www/$U/logs/apache-error.log"
CustomLog "/srv/www/$U/logs/apache-access.log" combined
<Directory "/srv/www/$U/public_html">
Require all granted
AllowOverride FileInfo Options Limit
Options -Indexes +FollowSymLinks -MultiViews
<FilesMatch "\.php$">
SetHandler "proxy:unix:$SOCK|fcgi://localhost/"
</FilesMatch>
</Directory>
<Directory "/srv/www/$U">
Require all denied
</Directory>
</VirtualHost>
EOF
sudo chmod 0644 "$AV"
if [ ! -e "/etc/apache2/sites-enabled/$SITE" ]; then
sudo a2ensite "$SITE" >/dev/null
fi
echo "OK:"
echo " /var/lib/php/sessions/$U"
echo " /srv/www/$U/public_html"
echo " /srv/www/$U/logs"
echo " /srv/www/$U/var"
echo " $LR"
echo " $FPM"
echo " $AV (enabled: $SITE)"
echo "다음:"
echo " sudo php-fpm8.4 -t && sudo systemctl reload php8.4-fpm"
echo " sudo apache2ctl -t && sudo systemctl reload apache2"
8) 테스트
a2enconf zz-custom
apache2ctl configtest
systemctl reload apache2
9) mariadb 11.8 lts
cd /
apt update
apt -y install curl ca-certificates gnupg lsb-release
# MariaDB Community Server 서명키(필수)
curl -fLsS https://r.mariadb.com/downloads/mariadb_repo_setup -o /tmp/mariadb_repo_setup
bash /tmp/mariadb_repo_setup --mariadb-server-version="mariadb-11.8"
apt update
apt-cache policy mariadb-server | sed -n '1,60p'
apt install mariadb-server mariadb-client mariadb-backup
10) vi /etc/mysql/mariadb.conf.d/99-8G.cnf
[mysqld]
# 기본
user = mysql
bind-address = 127.0.0.1
pid-file=/run/mysqld/mysqld.pid
socket=/run/mysqld/mysqld.sock
datadir=/var/lib/mysql
log-error=/var/log/mysql/error.log
# ===== 메모리 (8GB / 웹+노드 동시 기준) =====
innodb_buffer_pool_size = 3G
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 1
innodb_flush_method = O_DIRECT
# ===== 연결 / 캐시 =====
max_connections = 150
table_open_cache = 2048
table_definition_cache = 2048
open_files_limit = 65535
thread_cache_size = 64
# ===== 정렬 / 임시 테이블 (연결당 메모리 폭발 방지) =====
sort_buffer_size = 2M
join_buffer_size = 2M
tmp_table_size = 64M
max_heap_table_size = 64M
# 디스크 임시테이블이 너무 빨리 생기면 아래를 128M로 올려도 됨.
# tmp_table_size = 128M
# max_heap_table_size = 128M
# ===== 문자셋 =====
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
# ===== 슬로우 쿼리 =====
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
# ===== Binary log =====
skip-log-bin
10-1) 데이터 단순 초기화 (선택)
systemctl stop mariadb
rm -rf /var/lib/mysql/*
install -d -o mysql -g mysql -m 750 /var/lib/mysql
mariadb-install-db --user=mysql --datadir=/var/lib/mysql
systemctl start mariadb
mariadb -e "SELECT VERSION();"
10-2) 보안 설치 (필수)
mariadb-secure-installation
11) 끝.
systemctl enable --now mariadb
systemctl enable --now php8.4-fpm
systemctl enable --now apache2