์ฒ์์ ์ด ๋ฏธ์ ์ ๋ฐ์์ ๋ ์์งํ ์ข ๋ง๋งํ์ด์. “LEMP ์คํ์ผ๋ก WordPress ์๋ฒ๋ฅผ ์ง์ ๋ง๋ค์ด๋ณด์ธ์”๋ผ๋. ์นดํ24์์ ๋ฒํผ ๋ช ๋ฒ ํด๋ฆญํ๋ฉด ๋๋ ๊ฑธ ์ ์ง์ ํ๋๊ณ ์? ๊ทธ๋ฐ๋ฐ ์ด ๊ณผ์ ์ ์ง์ ํด๋ณด๊ณ ๋์ ์น์ฌ์ดํธ๊ฐ ์ด๋ป๊ฒ ๋์๊ฐ๋์ง๋ฅผ ๋น๋ก์ ์ดํดํ๊ฒ ๋์ต๋๋ค.
์ด๋ฒ ํฌ์คํ ์ ๊ทธ ์ ๊ณผ์ ์ ๊ธฐ๋กํ ๋ฅ๋ค์ด๋ธ ์ค์ต ํ๊ธฐ์ ๋๋ค.
๐ ๋ฏธ์ ๋ฐฐ๊ฒฝ๊ณผ ๋ชฉํ
์๋๋ฆฌ์ค: CEO๊ฐ ํ์ฌ ๊ธฐ์ ๋ธ๋ก๊ทธ๋ฅผ WordPress๋ก ๋ง๋ค์ด๋ฌ๋ผ๊ณ ์์ฒญํ์ต๋๋ค. ์์ฐ ์ ์ฝ์ ์ํด ์ง์ ๋ฆฌ๋ ์ค ์๋ฒ์ ๊ตฌ์ถํด์ผ ํฉ๋๋ค.
์ด ํ ์ค์ด ์ ๋ฅผ Nginx, PHP, MariaDB์ ์ธ๊ณ๋ก ๋์ด๋ค์์ต๋๋ค.
| ๊ตฌ์ฑ ์์ | ์ญํ | ๋น์ |
|---|---|---|
| Linux (Ubuntu) | ์ด์์ฒด์ , ๋ชจ๋ ๊ฒ์ ํ ๋ | ๋ |
| Nginx (E) | ์น ์๋ฒ, ์์ฒญ์ ์ ์ผ ๋จผ์ ๋ฐ์ | ์จ์ดํฐ |
| MariaDB (M) | ๋ฐ์ดํฐ๋ฒ ์ด์ค, ๊ธ/๋๊ธ/ํ์ ์ ์ฅ | ์์ฌ๋ฃ ์ฐฝ๊ณ |
| PHP-FPM (P) | ๋์ ์ฝํ ์ธ ์ฒ๋ฆฌ ์์ง | ์๋ฆฌ์ฌ |
์ด ๋ค ๊ฐ์ง ์กฐํฉ์ด ๋ฐ๋ก LEMP ์คํ์ ๋๋ค. (LAMP์์ Apache ๋์ Nginx๋ฅผ ์ฐ๊ธฐ ๋๋ฌธ์ E)


Step 1: Nginx ์น ์๋ฒ ์ค์ ๐
์น ์๋ฒ๋ ์ฌ์ฉ์์ ์์ฒญ์ ์ ์ผ ๋จผ์ ๋ฐ๋ ๊ด๋ฌธ์
๋๋ค. ์ฌ๊ธฐ์๋ minsooword.kro.kr ๋๋ฉ์ธ์ผ๋ก ๋ค์ด์ค๋ ์์ฒญ์ /var/www/wordpress ํด๋๋ก ์ฐ๊ฒฐํด ์ฃผ๋ ๊ฐ์ ํธ์คํธ(Virtual Host) ๋ฅผ ๋ง๋ค์์ต๋๋ค.


๋จผ์ nginx๊ฐ ์ ์คํ๋๊ณ ์๋์ง๋ถํฐ ํ์ธํฉ๋๋ค.



๊ทธ๋ค์, ์ฌ์ดํธ ์ค์ ํ์ผ์ ์์ฑํฉ๋๋ค.
server {
listen 80;
server_name minsooword.kro.kr www.minsooword.kro.kr;
root /var/www/wordpress;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}


์ค์ ํ์ผ์ ๋ง๋ค์์ผ๋ฉด sites-enabled์ ์ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ๊ฑธ์ด์ ํ์ฑํํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ธฐ์กด default ์ค์ ์ ๊ผญ ํด์ ํด์ผ ์ถฉ๋์ด ๋์ง ์์ต๋๋ค.
sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/
sudo unlink /etc/nginx/sites-enabled/default
sudo nginx -t # ๋ฌธ๋ฒ ๊ฒ์ฌ
sudo systemctl reload nginx
Step 2: PHP-FPM ์ค์น โ ๋์ ์ฝํ ์ธ ์ ํต์ฌ โ๏ธ
Nginx๋ ์ ์ ํ์ผ(HTML, ์ด๋ฏธ์ง)์ ์ ์ฒ๋ฆฌํ์ง๋ง, PHP ์ฝ๋๋ ์ง์ ์คํํ์ง ๋ชปํฉ๋๋ค. ์ด๊ฑธ ๋์ ์ฒ๋ฆฌํด์ฃผ๋ ๊ฒ PHP-FPM์ ๋๋ค.
PHP๋ ์๋ฒ์์ ๋จผ์ ์คํ๋์ด HTML๋ก ๋ณํ๋ ํ ๋ธ๋ผ์ฐ์ ์ ์ ๋ฌ๋๋ ์๋ฒ ์ฌ์ด๋ ์ธ์ด์์. ๊ทธ๋์ ๋ก๊ทธ์ธํ ์ฌ๋๋ง๋ค ๋ค๋ฅธ ํ์ด์ง๊ฐ ๋ณด์ด๋ ๊ฒ ๊ฐ์ ๋์ ๊ธฐ๋ฅ์ด ๊ฐ๋ฅํด์ง๋๋ค.


Nginx ์ค์ ํ์ผ์ PHP ์ฒ๋ฆฌ ๋ธ๋ก์ ์ถ๊ฐํฉ๋๋ค.
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
}



Step 3: MariaDB โ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ์ฐฝ๊ณ ๐๏ธ
WordPress๋ ๊ธ, ๋๊ธ, ํ์ ์ ๋ณด๋ฅผ ๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํฉ๋๋ค. ์ด๋ฅผ ๋ด๋นํ๋ ๊ฒ MariaDB์ ๋๋ค.


์ค์น ํ ๋ณด์ ์ค์ ์ ๋ฐ๋์ ํด์ผ ํฉ๋๋ค.

๋ณด์ ์ค์ ์ ์ ํ ๊ฐ์ด๋:
Switch to unix_socket authentication?โ n (๋น๋ฐ๋ฒํธ ๋ฐฉ์ ์ฌ์ฉ)Remove anonymous users?โ yDisallow root login remotely?โ yRemove test database?โ y
์ดํ WordPress ์ ์ฉ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฌ์ฉ์๋ฅผ ๋ง๋ญ๋๋ค.
CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY '๋น๋ฐ๋ฒํธ';
GRANT ALL ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;

Step 4: WordPress ์ค์น ๐
๋๋์ด ๋ณธ๋ก ! WordPress ํ์ผ์ ์๋ฒ์ ์ฌ๋ฆฌ๊ณ ์ค์ ํฉ๋๋ค.
cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
sudo cp -a /tmp/wordpress/. /var/www/wordpress/
๊ทธ๋ค์ wp-config.php ํ์ผ์ ์๊น ๋ง๋ DB ์ ๋ณด๋ฅผ ๋ฃ์ด์ค๋๋ค.
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', '๋น๋ฐ๋ฒํธ' );
์ดํ ๋ธ๋ผ์ฐ์ ์์ http://minsooword.kro.kr ์ ์ ์ํ๋ฉด WordPress ์ค์น ๋ง๋ฒ์ฌ๊ฐ ๋น๋๋ค. ์ธ์ด ์ ํํ๊ณ ๊ด๋ฆฌ์ ๊ณ์ ๋ง๋ค๋ฉด ๋!
Step 5: SSL ์ธ์ฆ์ ์ ์ฉ โ HTTPS๋ก ๋ณด์ ๊ฐํ ๐
HTTP๋ ๋ฐ์ดํฐ๊ฐ ์ํธํ๋์ง ์์ ์ค๊ฐ์ ๋๊ตฐ๊ฐ ํ์ณ๋ณผ ์ ์์ด์. HTTPS๋ ์ด ๋ฐ์ดํฐ๋ฅผ ์ํธํํฉ๋๋ค.
๊ณต์ธ IP๊ฐ ์๋ ํ๊ฒฝ์ด๋ผ Let’s Encrypt ๋์ OpenSSL ์ฌ์ค ์ธ์ฆ์๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
sudo mkdir -p /etc/nginx/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/wordpress.key \
-out /etc/nginx/ssl/wordpress.crt
Nginx ์ค์ ์ HTTPS๋ฅผ ์ถ๊ฐํ๊ณ , HTTP๋ก ๋ค์ด์ค๋ ๋ชจ๋ ์์ฒญ์ HTTPS๋ก ๊ฐ์ ๋ฆฌ๋ค์ด๋ ํธ(301)ํฉ๋๋ค.
server {
listen 80;
server_name minsooword.kro.kr;
return 301 https://$host$request_uri; # ์๊ตฌ ์ด์ ์ฒ๋ฆฌ
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/wordpress.crt;
ssl_certificate_key /etc/nginx/ssl/wordpress.key;
ssl_protocols TLSv1.2 TLSv1.3;
# ... (๋๋จธ์ง ์ค์ )
}
Step 6: UFW + Fail2Ban โ ๋ฐฉ์ด์ ๊ตฌ์ถ ๐ก๏ธ
SSL์ด ํต์ ์ํธํ๋ผ๋ฉด, UFW์ Fail2Ban์ ๋ฌธ ์ ๊ทธ๊ธฐ์ ์นจ์ ์ ์ก๊ธฐ์ ๋๋ค.
UFW (๋ฐฉํ๋ฒฝ): ํ์ฉ๋ ํฌํธ(22, 80, 443)๋ง ์ด๊ณ ๋๋จธ์ง๋ ์ ๋ถ ์ฐจ๋จํฉ๋๋ค.
Fail2Ban: ๋ก๊ทธ ํ์ผ์ ์ค์๊ฐ ๊ฐ์ํด์, ๋ก๊ทธ์ธ์ ๋ฐ๋ณต ์คํจํ๋ ์์ํ IP๋ฅผ ์๋์ผ๋ก ์ฐจ๋จํฉ๋๋ค. ๋ฌด์ฐจ๋ณ ๋์ ๊ณต๊ฒฉ(Brute-force)์ ๋ง๋ ํต์ฌ ๋๊ตฌ์์.
WordPress ์ ์ฉ ํํฐ๋ฅผ ๋ง๋ค์ด์ /wp-login.php๋ /xmlrpc.php์ ๋ฐ๋ณต ์ ๊ทผํ๋ IP๋ฅผ ์ก์ต๋๋ค.
# wp-login.php์ POST๋ก ๋ฐ๋ณต ์๋ํ๋ IP๋ฅผ ๊ณต๊ฒฉ์ผ๋ก ํ๋จ
failregex = ^<HOST> .* "POST /wp-login\.php
^<HOST> .* "POST /xmlrpc\.php



๐ ์ต์ข ์ ๊ฒ: ๋ชจ๋ ๊ฒ ์ ๋๋ก ๋์๊ฐ๋์ง ํ์ธ
# ํ ๋ฐฉ์ ์ ์ฒด ์ํ ํ์ธํ๊ธฐ
systemctl is-active nginx # Nginx ์คํ ์ค?
systemctl is-active php8.1-fpm # PHP-FPM ์คํ ์ค?
systemctl is-active mariadb # MariaDB ์คํ ์ค?
systemctl is-active fail2ban # Fail2Ban ์คํ ์ค?
curl -k -s -o /dev/null -w "%{http_code}" https://minsooword.kro.kr # 200์ด๋ฉด OK

๐ก ๋ฏธ์ ์ ๋ง์น๋ฉฐ
๋จ์ํ ์ค์น ๋ฒํผ ํด๋ฆญ์ผ๋ก ๋๋ด์ง ์๊ณ ์ง์ ํด๋ณด๋, ์ฌ์ฉ์์ ์์ฒญ์ด ์ด๋ค ๊ฒฝ๋ก๋ก ์ฒ๋ฆฌ๋๋์ง ๋ชธ์ผ๋ก ์ดํดํ๊ฒ ๋์ต๋๋ค.
์ฌ์ฉ์ ์์ฒญ โ
Nginx(์น ์๋ฒ) โPHP-FPM(์ฑ ์๋ฒ) โMariaDB(DB) โ ํ๋ฉด ์ถ๋ ฅ
์ด ํ๋ฆ ํ๋๋ฅผ ์๋ฒฝํ๊ฒ ์ดํดํ๊ณ ๋๋ฉด, ์์ผ๋ก ์ด๋์ ๋ฌธ์ ๊ฐ ์๊ฒจ๋ ์ด๋๋ฅผ ๋ฏ์ด๋ด์ผ ํ ์ง ์ ์ ์์ด์. ์ฒ์์ ๋ง๋งํ์ง๋ง, ๋๋๊ณ ๋๋ ๊ฐ์ฅ ๋ฟ๋ฏํ ๋ฏธ์ ์ด์์ต๋๋ค. ๐