더 나은 프로그래머가 되자

Rocky Linux 9.6 Ningx+PHP+MariaDB 설치 본문

리눅스

Rocky Linux 9.6 Ningx+PHP+MariaDB 설치

greathuman 2025. 12. 1. 16:51

환경: Rocky Linux 9.6

스택: Nginx (Mainline) + PHP 8.4 (Remi) + MariaDB 11.4 (LTS)

주요 기능: SSL 최적화, 보안 헤더 적용, SFTP Chroot 격리, IP 접속 차단


1. 시스템 초기 설정 및 리포지토리 설치

최신 버전의 패키지를 설치하기 위해 공식 리포지토리를 등록합니다.

# 시스템 업데이트 및 필수 도구 설치

sudo dnf update -y

sudo dnf install epel-release vim curl wget unzip dnf-utils policycoreutils-python-utils -y


# 1. Nginx Mainline (최신) 리포지토리 설정

sudo vim /etc/yum.repos.d/nginx.repo

# [아래 내용 붙여넣기]

# [nginx-mainline]

# name=nginx mainline repo

# baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/

# gpgcheck=1

# enabled=1

# gpgkey=https://nginx.org/keys/nginx_signing.key

# module_hotfixes=true

 

# 2. MariaDB 11.4 LTS 리포지토리 설정

sudo vim /etc/yum.repos.d/mariadb.repo

# [아래 내용 붙여넣기]

# [mariadb]

# name = MariaDB

# baseurl = https://rpm.mariadb.org/11.4/rhel/$releasever/$basearch

# module_hotfixes = 1

# gpgkey = https://rpm.mariadb.org/RPM-GPG-KEY-MariaDB

# gpgcheck = 1

 

# 3. Remi PHP 리포지토리 설치

sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm -y

2. 패키지 설치 및 서비스 활성화

# Nginx 설치

sudo dnf install nginx -y

 

# MariaDB 설치

sudo dnf install MariaDB-server MariaDB-client -y

 

# PHP 8.4 활성화 및 설치 (필수 모듈 포함)

sudo dnf module reset php -y

sudo dnf module enable php:remi-8.4 -y

sudo dnf install php php-fpm php-mysqlnd php-gd php-opcache php-intl php-mbstring php-xml php-curl php-zip -y

 

# 서비스 자동 시작 등록 및 실행

sudo systemctl enable --now nginx mariadb php-fpm

 

 

 

3. 사용자 생성 및 SFTP(Chroot) 격리 설정

웹 루트 경로(/home/kecch/www)를 생성하고 사용자가 상위 폴더로 이동하지 못하도록 가둡니다.

# 사용자 생성

sudo useradd account

sudo passwd account

 

# 디렉토리 구조 생성 (Chroot 필수 조건: 상위 폴더는 root 소유)

sudo -u kecch mkdir -p /home/account/www

sudo chown root:root /home/account

sudo chmod 755 /home/account

sudo chown account:account /home/account/www

sudo chmod 755 /home/account/www

 

# SSH 설정 수정

sudo vim /etc/ssh/sshd_config

# [파일 맨 끝에 아래 내용 추가]

# Match User account

#     ChrootDirectory /home/kecch

#     ForceCommand internal-sftp

#     X11Forwarding no

#     AllowTcpForwarding no

 

# SSH 재시작

sudo systemctl restart sshd

 


4. MariaDB 설정 (외부 접속 및 DB 생성)

# 1. 초기 보안 설정 (Root 비밀번호 설정 등)

sudo mariadb-secure-installation

 

# 2. 외부 접속 허용 (Bind Address 수정)

sudo vim /etc/my.cnf.d/server.cnf

# [mysqld] 섹션 확인: bind-address = 0.0.0.0

 

# 3. MariaDB 재시작

sudo systemctl restart mariadb

 

# 4. DB 및 계정 생성 (Root 접속 후 SQL 실행)

sudo mariadb -u root -p

SQL

/* DB 생성 */

CREATE DATABASE IF NOT EXISTS account DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

 

/* 사용자 생성 (로컬 접속용 + 외부 특정 IP용) */

CREATE USER 'account'@'localhost' IDENTIFIED BY '비밀번호';

CREATE USER 'account'@'180.226.254.125' IDENTIFIED BY '비밀번호';

 

/* 권한 부여 */

GRANT ALL PRIVILEGES ON account.* TO 'account'@'localhost';

GRANT ALL PRIVILEGES ON account.* TO 'account'@'180.226.254.125';

FLUSH PRIVILEGES;

EXIT;

 


5. PHP 설정 (권한, 업로드, 세션)

PHP-FPM 실행 유저를 변경하고, 임시 폴더 권한 오류를 해결합니다.

# 1. 실행 사용자 변경 (apache -> nginx)

sudo vim /etc/php-fpm.d/www.conf

# user = nginx

# group = nginx

 

# 2. php.ini 설정 (버전 숨김, 임시 폴더 지정)

sudo vim /etc/php.ini

# expose_php = Off

# upload_tmp_dir = /var/lib/php/upload_tmp

# sys_temp_dir = /var/lib/php/upload_tmp

# upload_max_filesize = 50M

# post_max_size = 50M

 

# 3. 세션 및 업로드 임시 폴더 생성 및 권한 수정 (필수)

sudo mkdir -p /var/lib/php/upload_tmp

sudo chown -R nginx:nginx /var/lib/php/session /var/lib/php/upload_tmp /var/lib/php/wsdlcache /var/lib/php/opcache

sudo chmod 770 /var/lib/php/upload_tmp

 


6. SSL 인증서 적용

인증서 키 파일의 비밀번호를 제거하여 Nginx 자동 실행 시 문제가 없도록 합니다.

Bash

# 1. 인증서 파일 준비 (SFTP 업로드 경로: /home/account/cert/2025)

 

# 2. 키 파일 비밀번호 제거 (필수)

cd /home/account/cert/2025

openssl rsa -in key.pem -out key.pem.new

mv key.pem.new key.pem

 

# 3. 권한 설정 (보안)

sudo chgrp nginx cert.pem key.pem

sudo chmod 640 cert.pem key.pem

7. Nginx 설정 (최종)

설정 경로: /etc/nginx/conf.d/default.conf

(IP 접속 차단, SSL 최적화, 보안 헤더 9종 적용)

# 1. IP 직접 접속 및 허용되지 않은 도메인 차단 (응답 없음 처리)

server {

    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
   

    # SSL 설정 (443 포트 리스닝을 위해 필요)
    ssl_certificate      /home/account/cert/2025/cert.pem;
    ssl_certificate_key  /home/account/cert/2025/key.pem;

    return 444;

}


# 2. 실제 서비스 (HTTP -> HTTPS 리다이렉트)
server {
    listen 80;
    server_name example.com; # ★ 실제 도메인 입력
    return 301 https://$host$request_uri;
}

 

# 3. 실제 서비스 (HTTPS Main)

server {
    listen 443 ssl;
    server_name example.com; # ★ 실제 도메인 입력
 
    # 웹 루트 설정
    root   /home/account/www;
    index  index.php index.html;
 
    # SSL 인증서
    ssl_certificate      /home/account/cert/2025/cert.pem;
    ssl_certificate_key  /home/account/cert/2025/key.pem;

    # [SSL 최적화 설정]
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'HIGH:!aNULL:!MD5:!3DES:!RC4:!SHA1:!kRSA:!EXP:!LOW';
    ssl_prefer_server_ciphers on;
    ssl_session_timeout  5m;

    # [보안 헤더 설정]
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header Cache-Control "no-store, no-cache, must-revalidate" always;
    add_header Pragma "no-cache" always;
    add_header Cross-Origin-Opener-Policy "same-origin" always;
    add_header Permissions-Policy "geolocation=(self), camera=()" always;
    add_header Content-Security-Policy "default-src https:; script-src https: 'unsafe-inline' 'unsafe-eval'; style-src https: 'unsafe-inline';" always;

    # Nginx 버전 정보 숨김
    server_tokens off;

    # PHP 연동
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass   unix:/run/php-fpm/www.sock;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }

    # 기본 라우팅
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # 업로드 용량 제한
    client_max_body_size 50M;

}

 


8. 방화벽(Firewall) SELinux 설정

Rocky Linux 환경에서 권한 에러를 방지하기 위한 필수 설정입니다.

 

# 1. 방화벽 설정 (HTTP, HTTPS 허용 / DB는 특정 IP만 허용)

sudo firewall-cmd --permanent --add-service=http

sudo firewall-cmd --permanent --add-service=https

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="180.226.254.125" port port="3306" protocol="tcp" accept'

sudo firewall-cmd --reload

 

# 2. SELinux 설정 (권한 부여)

# 홈 디렉토리 웹 서비스 허용

sudo setsebool -P httpd_enable_homedirs 1

 

# 웹 루트(읽기 전용) 라벨링

sudo chcon -R -t httpd_sys_content_t /home/kecch/www

 

# 데이터 업로드 폴더 및 임시 폴더(쓰기 허용) 라벨링

# (경로가 존재해야 합니다: mkdir -p /home/kecch/www/data)

sudo mkdir -p /home/kecch/www/data

sudo chown -R nginx:nginx /home/kecch/www/data

sudo chcon -R -t httpd_sys_rw_content_t /home/kecch/www/data

sudo chcon -R -t httpd_sys_rw_content_t /var/lib/php/upload_tmp

 

# 인증서 폴더 라벨링

sudo chcon -R -t httpd_sys_content_t /home/kecch/cert

 


9. 최종 적용 및 확인

# 1. 설정 문법 검사 (successful 확인)

sudo nginx -t

 

# 2. 모든 서비스 재시작

sudo systemctl restart php-fpm

sudo systemctl restart mariadb

sudo systemctl restart nginx

 

 

 

Comments