09. Ubuntu 24.04 + PHP Multi + Nginx + MariaDB

2026. 6. 8. 01:13Just do IT/Dev

반응형

현 시점에서 서버를 저렇게 셋팅하는 것은 기존의 PHP7.4 버전으로 운영되는 사이트도 함께 운영을 해야 되는 사항이라, 

Ubuntu 26.04에서는 ondrej PPA가 아직 지원되지 않아 Ubuntu 24.04로 셋팅을 진행하며, Multi Version 필요 없으신 분들은 

1단계 ~ 3단계는 건너뛰고 참조하시면 됩니다.

 

1단계 - 서버 기본 설정 상세

1) root 전환 : 이후 모든 명령어는 root로 실행합니다. sudo 없이 실행 가능해집니다.

sudo su -l root

 

2) 시스템 업데이트 및 재부팅

apt update && apt upgrade -y && apt autoremove -y

 

업데이트 및 재부팅 완료 후

reboot

 

재부팅 후 다시 SSH 접속해서 아래 다시 실행

sudo su -l root


1-3. 보안 강화 스크립트 적용 : SSH 포트 변경, 불필요한 서비스 차단 등 기본 보안 설정을 자동으로 적용합니다.

wget https://raw.githubusercontent.com/laelbe/linux-simple-scripts/refs/heads/main/_server_tools/ubuntu.2404.simplesecurity.sh -O /root/ubuntu.2404.simplesecurity.sh
bash /root/ubuntu.2404.simplesecurity.sh

 

보안스크립트 적용시 아래와 같은 메세지가 마지막에 보여도 신경쓰지 않아도 됩니다. 이는 새 서버에 셋팅을 하는 것이기 때문에 해당 경로가 없어서 나오는 메세지일뿐, 보안스크립트 자체는 정상적으로 실행된 것입니다.


1-4. 타임존 설정

ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
timedatectl set-timezone Asia/Seoul
timedatectl

위 코드를 실행하시면, 아래와 같이 나옵니다.


1-5. Swap 설정

**Swap(스왑)**은 RAM이 부족할 때 하드디스크 일부를 임시 메모리처럼 사용하는 공간입니다.
예시로 설명하면, 서버 RAM이 2GB인데 프로그램들이 2.5GB를 쓰려 한다면:

 

Swap 없음 → 프로그램 강제 종료 (서버 다운)
Swap 있음 → 부족한 0.5GB를 디스크에서 빌려서 사용 → 느리지만 유지

 

새 서버에 설정하는 이유는 AWS EC2는 기본적으로 Swap이 없습니다. 그래서 다음 상황에서 위험합니다:
nginx + PHP-FPM + MariaDB 동시 실행 시 메모리 사용량이 순간적으로 치솟을 때 대용량 DB 덤프 복원할 때, 트래픽이 갑자기 몰릴 때, Swap이 있으면 이런 상황에서 서버가 죽지 않고 버텨줍니다.

단점
디스크를 메모리처럼 쓰는 거라 RAM보다 훨씬 느립니다. 그래서 Swap에 너무 의존하게 되면 서버가 느려지는 증상이 나타납니다. 근본적인 해결책은 RAM 증설이고, Swap은 어디까지나 비상용입니다.

wget -q https://raw.githubusercontent.com/laelbe/linux-simple-scripts/main/_server_tools/add_swapfile -O /root/add_swapfile
bash /root/add_swapfile 1
free -m

free -m 결과에서 아래 그림과 같이 Swap 행에 1023 정도 표시되면 정상

 

2단계 - nginx 설치 상세

1) nginx 공식 저장소 추가 (stable)

curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | tee /etc/apt/sources.list.d/nginx.list
apt update && apt install -y nginx
service nginx start
nginx -v

위 코드를 순차적으로 실행하고 위와 같이 버전이 확인되면 정상적으로 nginx가 설치된 것입니다.


2) fastcgi_params 추가

echo 'fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;' >> /etc/nginx/fastcgi_params
echo 'fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;' >> /etc/nginx/fastcgi_params
echo 'fastcgi_param PATH_INFO $fastcgi_path_info;' >> /etc/nginx/fastcgi_params

 

3) nginx 기본 설정 (user, gzip, server_tokens)

sed -i 's/^user[[:space:]]\+nginx/user www-data/' /etc/nginx/nginx.conf
sed -i 's/#gzip  on;/gzip on;/' /etc/nginx/nginx.conf
sed -i '/gzip  on;/a\    server_tokens off;' /etc/nginx/nginx.conf
service nginx restart
nginx -t

 

위 코드를 순차적으로 실행하고 아래 그림과 같이 nginx -t 했을때,

syntax is ok 와 test is successful 두줄이 나오면 정상적으로 적용완료된 것입니다.


3단계 - PHP 설치 상세

1) ondrej PPA 추가

add-apt-repository ppa:ondrej/php -y
apt update


2) PHP 7.4 설치 + 확장설치

apt install -y php7.4-fpm php7.4-mbstring php7.4-gd php7.4-curl php7.4-xml php7.4-bcmath php7.4-mysql php7.4-zip php7.4-intl php7.4-bz2 php7.4-opcache php7.4-readline

 

3) PHP 8.3 설치 + 확장설치

apt install -y php8.3-fpm php8.3-mbstring php8.3-gd php8.3-curl php8.3-xml php8.3-bcmath php8.3-mysql php8.3-zip php8.3-intl php8.3-bz2 php8.3-opcache php8.3-readline


PHP7, PHP8 모두 확장설치는 아래 항목들에 대한 설치가 진행되는 것이니 하단 이미지 내용 참조 바랍니다.

 

4) PHP timezone 설정

sed -i 's/;date.timezone =/date.timezone = Asia\/Seoul/g' /etc/php/7.4/fpm/php.ini
sed -i 's/;date.timezone =/date.timezone = Asia\/Seoul/g' /etc/php/7.4/cli/php.ini
sed -i 's/;date.timezone =/date.timezone = Asia\/Seoul/g' /etc/php/8.3/fpm/php.ini
sed -i 's/;date.timezone =/date.timezone = Asia\/Seoul/g' /etc/php/8.3/cli/php.ini
service php7.4-fpm restart
service php8.3-fpm restart

한줄씩 입력해도 되고 복사해서 한번에 입력해도 됩니다.

 

5) Custom 풀 생성 (PHP 8.3 기반)

 

아래 내용으로 custom.conf 를 생성합니다. 아래 코드 전체를 복사한 후 custom부분만 원하는 이름으로 변경하여 사용하시면 됩니다.

cat > /etc/php/8.3/fpm/pool.d/custom.conf << 'EOF'
; ============================================================
; custom PHP-FPM Pool 설정
; PHP 8.3 기반 | /run/php/custom.sock 소켓 사용
; ============================================================

[atlassoft]

; --- 프로세스 실행 유저/그룹 ---
; 웹루트 파일의 소유자와 일치시켜야 권한 오류가 없음
user = custom
group = custom

; --- 소켓 설정 ---
; nginx와 PHP-FPM이 통신하는 소켓 파일 경로
; PHP-FPM 시작 시 자동 생성됨
listen = /run/php/custom.sock

; nginx가 소켓에 접근할 수 있도록 권한 설정
listen.owner = custom
listen.group = www-data

; --- 프로세스 관리 방식 ---
; dynamic: 트래픽에 따라 프로세스 수를 자동 조절 (권장)
; static: 항상 고정된 수의 프로세스 유지
; ondemand: 요청 있을 때만 프로세스 생성 (저사양 서버용)
pm = dynamic

; 동시에 실행 가능한 최대 프로세스 수
pm.max_children = 9

; FPM 시작 시 초기 프로세스 수
pm.start_servers = 3

; 최소 대기 프로세스 수 (부하 낮을 때 유지)
pm.min_spare_servers = 2

; 최대 대기 프로세스 수 (이 이상은 종료)
pm.max_spare_servers = 4

; --- 보안 설정 ---
; 세션 쿠키를 JavaScript에서 접근 못하도록 차단 (XSS 방어)
php_admin_value[session.cookie_httponly] = 1

; --- 오류 처리 ---
; 운영서버에서 PHP 오류를 화면에 노출하면 보안 위험 → 반드시 off
php_flag[display_errors] = off

; 오류를 로그 파일에 기록 (문제 추적을 위해 활성화 권장)
php_admin_flag[log_errors] = on

; 오류 로그 파일 경로
php_admin_value[error_log] = /var/log/php8.3-fpm-custom.log

; 워커 프로세스 출력을 메인 로그에 포함
; 디버깅 시 유용하나 로그가 많아질 수 있어 기본 비활성화
;catch_workers_output = yes

; --- 리소스 제한 ---
; PHP 프로세스당 최대 메모리 사용량
; WordPress는 128M으로 부족한 경우가 많아 256M 권장
php_admin_value[memory_limit] = 256M

; PHP 스크립트 최대 실행 시간 (초)
; 대용량 데이터 처리나 외부 API 연동 시 필요
php_admin_value[max_execution_time] = 120

; 파일 업로드/POST 데이터 수신 최대 시간 (초)
php_admin_value[max_input_time] = 300

; POST 데이터 최대 크기 (upload_max_filesize보다 크거나 같아야 함)
php_admin_value[post_max_size] = 25M

; 업로드 파일 최대 크기
php_admin_value[upload_max_filesize] = 25M
EOF


6) 사용자 추가 : custom에 해당하는 사용자가 추가되지 않은 경우, 에러가 발생합니다. 해당 풀을 사용할 사용자를 먼저 추가합니다.

adduser custom

비밀번호만 생성하고 나머지는 입력 없이 그냥 넘기시면 됩니다.

※ 에러가 나는 이유는, PHP-FPM이 custom 리눅스 계정으로 프로세스를 실행하고, 웹 파일도 custom 계정이 소유해야 권한 오류 없이 동작합니다.

 

7) custom.sock 생성 확인

service php8.3-fpm restart
ls -la /run/php/custom.sock

결과 화면에 custom.sock 파일이 보이면 정상적으로 생성 성공한 것입니다.

※ 특정 사이트가 PHP7.4를 사용해야 한다면, conf파일에서 기본 폴인 php7.4-fpm.sock를 연동하여 사용하면 됩니다.

 

※ 참고 : Custom은 Linux관리자를 지정한 것이며, root로 SSH 접속하는 경우(보안상 미추천)라면 Custom 계정은 SSH 접속을 아래 코드로 막을 수 있습니다.

usermod -s /usr/sbin/nologin custom

 

굳이 root로 서버에 접속해서 linux관리를 하고자 하신다면, 마지막의 root SSH 로그인 설정 부분을 참고하시면 됩니다.

4단계 - MariaDB 설치

1) MariaDB 설치

usermod -s /usr/sbin/nologin custom
apt install -y mariadb-server mariadb-client
service mariadb start
mariadb --version

위 그림과 같이 MariaDB의 Version이 확인이 되면 정상적으로 설치가 된 것입니다.

 

2) utf8mb4 charset 설정

sed -i '/\[mysqld\]/a character-set-server = utf8mb4\ncollation-server = utf8mb4_unicode_ci' /etc/mysql/mariadb.conf.d/50-server.cnf
service mariadb restart

 

3) 관리자 계정 생성

mariadb

위 명령어 실행 후, mariadb 쉘에서:

CREATE USER 'admin'@'localhost' IDENTIFIED BY '비밀번호입력';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;

비밀번호 입력 칸에 원하시는 비밀번호를 입력하시면 됩니다.

 

※ 여기서 설정한 계정은 MariaDB 전체를 관리하는 관리자를 설정한 것으로 이 상태에서는 시스템 DB이외에는 존재하지 않습니다. 추후 서비스를 위해서는 사용자 추가 - 사용자DB (이름 동일하게 하는 것을 추천)를 생성하고, 관리하면 됩니다.

5단계 - certbot 설치 상세

snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot
certbot --version

위 그림과 같이 Certbot Version이 확인되면 정상적으로 설치가 된 것입니다.

6. 신규 서비스 생성시

신규 웹 서비스를 진행하고자 한다면, 아래의 순서에 따라 다시 진행하시면 됩니다. 

 

1) 리눅스 사용자 계정이 필요한 경우 ( PHP-FPM 프로세스 실행용 )

# 리눅스 계정 생성

adduser guest

 

# 웹루트 생성

mkdir -p /home/guest/www


# DB + DB유저 (mariadb 접속 후) : guest 계정생성, guest DB 생성

CREATE DATABASE guest_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER ' guest '@'localhost' IDENTIFIED BY '비밀번호';
GRANT ALL PRIVILEGES ON guest _db.* TO ' guest '@'localhost';
FLUSH PRIVILEGES;


2) 리눅스 사용자 계정이 별도로 필요하지 않은 경우

단독 관리 - 서비스 계정은 위 3단계에서 custom으로 만들었으니 참조 (서비스당 계정을 하나씩 만드는 것은 장.단점이 있습니다.)

- 이 단계는 생략하고 기존 5)에서 만들었던, custom과 custom 풀을 사용하셔도 무관합니다.

# 1. 디렉토리 생성 (root로)

mkdir -p /home/newsite.com/www


# 2. 소유권 변경 : custom으로 / 소유권이 맞지 않으면 위 3단계에서 설명한 것과 같이 PHP-FPM이 custom 리눅스 계정으로 프로세스를 실행하고, 웹 파일을 호출하지 못하려 에러가 발생합니다.

chown -R custom:custom /home/newsite.com

 

#3. nginx conf 파일 생성

- 도메인 설정 ( 위 3단계에서 설명 드린 것처럼 여러 버전의 php를 운영해야 하는 경우 /etc/nginx/conf.d/xxx.conf 파일은 서비스별로 따로 작성하는 것을 추천 드립니다. )

vi /etc/nginx/conf.d/newsite.com.conf


# 4. DB 생성 (필요시) : 위 4단계에서 설명드린 바와 같이, 사용계정을 생성해서 DB를 만들 수 있습니다.

DB유저 관련해서는 4단계 부터 진행하시면 되고, 서비스별로 DB를 구분하여 운영하려면, DB사용자 계정 및 별도의 DB를 생성하는 것을 추천 드립니다.
mariadb -u root -p
# CREATE DATABASE newsite_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# GRANT ALL PRIVILEGES ON newsite_db.* TO 'guest'@'localhost';

 

# 5. nginx 리로드
nginx -t && systemctl reload nginx

# 6. SSL 인증서 발급
certbot --nginx -d newsite.com -d http://www.newsite.com                              

 

7. root SSH Login

root

1. root 비밀번호 설정  - 없으면 설정. SSH접속외 비밀번호 변경을 사용하지 않으려면 미설정.

passwd root


2. PermitRootLogin 확인 - "PermitRootLogin yes" 이면 OK

grep PermitRootLogin /etc/ssh/sshd_config

 

3. 서버의 SSH 공개키가 등록되어 있는지 확인

cat /root/.ssh/authorized_keys

 

4. 서버에 SSH공개키가 등록되어 있지 않다면, 공개키가 없으면 현재 서버에서 공개키를 복사해서 넣어주면 됩니다.
# 현재 서버에서 공개키 확인

cat ~/.ssh/id_rsa.pub


# 또는

cat ~/.ssh/id_ed25519.pub


나온 키를 새 서버의 /root/.ssh/authorized_keys에 붙여넣으면 됩니다.

2. 신규 설정하는 서버에 3번에서 확인한  SSH 공개키가 등록되어 있다면, 키 앞에 아래 이미지와 같은 제한이 붙어 있을 것입니다.

이건 AWS EC2 기본 설정으로, root로 접속하면 자동으로 차단하고 ubuntu 계정으로 쓰라는 메시지를 출력합니다.
이 제한을 제거해야 root 접속이 됩니다.

no-port-forwarding,no-agent-forwarding,no-X11-forwarding,
command="echo 'Please login as the user \"ubuntu\" rather than the user \"root\".'..."

 

아래 코드로 편집기를 열고 앞부분 제한 옵션 전부 지우고 키만 남기세요. ssh-rsa 부분 부터 마지막까지 남긴 후, 저장하시면

ssh키 부분만 남게 됩니다.

vi /root/.ssh/authorized_keys

 

그럼 신규 설정한 서버를 새창으로 접속하시고 접속하실때, 계정을 root로 접속하여도 접속이 잘 되시는 것을 확인할 수 있습니다.

반응형