SSD Nodes Learn Hosting plans →
가이드 Matt Connor작성자 Matt Connor

Ubuntu 24.04 LAMP 스택 PHP-FPM 구축 방법

Ubuntu 24.04에서 Apache, MariaDB, PHP 8.3과 PHP-FPM을 연결하고 이름 기반 가상 호스트와 Certbot 무료 HTTPS를 구성합니다. unix_socket 인증과 주요 오류 해결법도 설명합니다.

구축할 시스템

LAMP 스택은 Ubuntu 24.04 서버 한 대에서 작동하는 네 가지 구성 요소입니다. 기반이 되는 Linux, HTTP 요청을 처리하는 Apache, 데이터를 저장하는 MariaDB, 코드를 실행하는 PHP 8.3으로 이루어집니다. 이 과정을 마치면 실제 애플리케이션 디렉터리를 서비스하는 이름 기반 가상 호스트, 최소 권한을 가진 전용 사용자가 관리하는 데이터베이스, PHP-FPM을 통해 Apache와 연결된 PHP, 그리고 Let's Encrypt에서 발급받은 무료 인증서가 적용된 환경을 갖추게 됩니다.

설치 과정은 apt 명령 네 개로 완료됩니다. 이 가이드의 대부분은 각 구성 요소를 연결하는 설정과, 새로 구축한 스택에서 빈 페이지가 출력되거나, 소스 코드가 브라우저로 다운로드되거나, 데이터베이스 접속이 거부되는 등의 흔한 오류를 해결하는 데 할애합니다. 이러한 문제들은 각각 고유한 징후가 있으며, 아래에 각 오류 상황에서 나타나는 정확한 메시지와 함께 설명되어 있습니다.

사전 요구 사항 및 주의 사항

Ubuntu 24.04 기반의 신규 KVM VPS와 sudo 권한을 가진 사용자 또는 root 계정, 그리고 공인 IPv4 주소가 준비되어 있다고 가정합니다. 최소 사양의 스택은 1 GB RAM으로도 실행 가능하지만, 실제 데이터베이스 기반 애플리케이션을 운영하려면 2 GB로 증설하십시오. MariaDB의 기본 버퍼와 몇 개의 PHP-FPM 워커만으로도 첫 1 GB는 금방 소진되기 때문입니다.

마지막 단계에서 Certbot이 정상적으로 작동하려면 두 가지 조건이 충족되어야 하므로 지금 미리 준비하십시오. 첫째, VPS의 공인 IP를 가리키는 A 레코드가 포함된 도메인 이름이 필요합니다. Let's Encrypt는 해당 도메인 이름으로 HTTP 검증을 수행하므로, IP 주소만으로는 인증서를 발급받을 수 없습니다. 둘째, 80번과 443번 포트가 외부 인터넷에서 접속 가능해야 합니다. 많은 클라우드 제공업체에서는 서버 내부의 ufw 설정뿐만 아니라 제어판의 네트워크 방화벽에서도 해당 포트를 개방해야 합니다. DNS 변경 사항이 전파되는 데 최대 1시간이 소요될 수 있으므로, A 레코드를 먼저 설정해 두면 인증서 발급 시점에는 정상적으로 반영될 것입니다.

1단계 - Apache 설치 및 기본 페이지 확인

sudo apt update
sudo apt install -y apache2

apt은 서비스를 시작하고 활성화합니다. 다음 명령으로 확인하십시오.

systemctl status apache2

active (running)라는 문구가 포함된 줄을 확인해야 합니다. 이제 브라우저에서 http://YOUR_SERVER_IP/을 엽니다. "It works!"라는 큰 배너가 있는 Apache2 Ubuntu Default Page가 나타나면 정상입니다. 이는 Apache가 오류 없이 서비스를 제공하고 있다는 증거입니다. 해당 페이지는 /var/www/html/index.html에 위치하며, 기본으로 제공되는 가상 호스트인 000-default.conf를 통해 서비스됩니다. 두 항목 모두 나중에 비활성화할 예정이지만, 지금은 이 페이지가 표시되는 것이 정상입니다.

페이지가 전혀 로드되지 않지만 systemctl에서 프로세스가 실행 중이라고 표시된다면, 방화벽이 차단하고 있는 것입니다. 다음 단계에서 이를 해결합니다.

2단계 - HTTP 및 HTTPS를 위한 방화벽 개방

apache2 패키지는 세 가지 ufw 애플리케이션 프로필을 등록합니다. 다음 명령으로 목록을 확인하십시오:

sudo ufw app list

Apache, Apache Full, Apache Secure이 표시될 것입니다. Apache는 80번 포트 전용이며, Apache Secure은 443번 포트 전용입니다. Apache Full는 두 포트를 모두 포함하므로, 마지막 단계에서 TLS를 추가할 때 이 프로필을 사용해야 합니다.

sudo ufw allow OpenSSH
sudo ufw allow "Apache Full"
sudo ufw enable

ufw enable을 실행하기 전에 OpenSSH를 허용하십시오. ufw은 기본적으로 모든 수신 트래픽을 거부합니다. SSH 규칙 없이 방화벽을 활성화하면 즉시 연결이 끊어집니다. 현재 세션은 유지되더라도 다시는 재접속할 수 없게 됩니다. sudo ufw status로 설정을 확인하십시오. OpenSSH, Apache Full 및 해당 v6 버전이 모두 ALLOW 상태로 표시되어야 합니다.

3단계 - MariaDB 설치 및 보안 설정

sudo apt install -y mariadb-server
systemctl status mariadb

Ubuntu 24.04는 장기 지원(LTS) 릴리스인 MariaDB 10.11을 기본 제공하므로 외부 저장소를 추가할 필요가 없습니다. 서비스가 실행 중인 상태에서 다음 명령으로 보안을 강화합니다.

sudo mysql_secure_installation

설정 과정에서 나타나는 질문들은 Enter 키를 연타하기보다 읽어보는 것이 좋습니다. current root password를 물으면 Enter를 누르십시오. 아직 설정된 비밀번호가 없습니다. "Switch to unix_socket authentication?" 질문은 이 패키지에서 이미 활성화되어 있으므로 어떤 선택을 하든 결과는 같습니다. 따라서 n를 입력하십시오. 다음 단락에서 설명할 이유로 "Change the root password?"에는 n이라고 답하십시오. 그 후 나머지 질문인 익명 사용자 제거, 원격 root 로그인 차단, 테스트 데이터베이스 삭제, 권한 테이블 새로고침에는 모두 Y를 선택하십시오.

많은 사용자가 혼란스러워하는 부분은 다음과 같습니다. Ubuntu의 MariaDB에서 root 데이터베이스 계정은 비밀번호가 아닌 unix_socket 인증을 사용합니다. 이는 데이터베이스가 이미 인증을 마친 운영체제 사용자를 신뢰한다는 의미입니다. 따라서 root 셸에서 다음 명령을 실행하면 정상적으로 작동합니다.

sudo mysql

...그러면 비밀번호를 묻지 않고 바로 MariaDB [(none)]> 프롬프트로 진입합니다. 권한이 없는 일반 사용자로 같은 명령을 실행하면 거부되는데, 이것이 바로 핵심입니다. 데이터베이스 root 접근 권한은 서버의 sudo 계정과 연동되어 있으며, 탈취하거나 피싱하거나 무차별 대입 공격을 할 비밀번호 자체가 존재하지 않습니다. 이는 비밀번호보다 훨씬 안전하므로 설정을 변경하지 마십시오. 여기서 도출되는 규칙은 다음과 같습니다. 애플리케이션을 root 계정에 연결하지 마십시오. 애플리케이션마다 전용 사용자를 생성하십시오(7단계). TCP를 통해 사용자 이름과 비밀번호로 접속하는 애플리케이션은 어차피 소켓 인증을 사용할 수 없으며, 각 애플리케이션은 자신의 데이터베이스에만 접근하도록 제한하는 것이 바람직하기 때문입니다.

단계 4 - PHP 8.3 및 PHP-FPM 설치

Ubuntu 24.04의 기본 PHP 버전은 8.3입니다. FPM 프로세스 관리자와 일반적인 애플리케이션에 필요한 확장 기능을 설치합니다.

sudo apt install -y php8.3-fpm php8.3-mysql php8.3-cli \
  php8.3-curl php8.3-xml php8.3-mbstring php8.3-zip

목록에 포함되지 않은 libapache2-mod-php에 유의하십시오. 해당 구형 패키지는 모든 Apache 프로세스 내부에 PHP 인터프리터를 포함합니다. 구성은 간단하지만, 스크립트를 처리하든 정적 이미지를 전송하든 모든 워커가 PHP 복사본을 유지해야 하며, 두 프로세스의 수명 주기가 결합되어 있습니다. 또한 이는 가장 효율성이 낮은 Apache의 prefork MPM에서만 작동합니다. 반면 PHP-FPM은 PHP를 별도의 프로세스 풀로 실행하며, Apache는 소켓을 통해 이와 통신합니다. 이를 통해 Apache는 정적 파일 처리에 스레드 기반의 event MPM을 사용하고 PHP 요청만 FPM으로 전달할 수 있습니다. 프로세스 풀은 웹 서버와 독립적으로 튜닝할 수 있으며, 나중에 nginx로 전환하더라도 동일한 FPM 설정을 그대로 사용할 수 있습니다. 이것이 현재 기본값으로 채택된 이유입니다.

Apache는 proxy_fcgi 모듈을 통해 FPM에 접근합니다. 해당 모듈을 활성화하고 FPM 패키지가 생성한 설정을 적용한 뒤 재시작합니다.

sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl restart apache2

a2enconf php8.3-fpm은 PHP 파일을 FPM 소켓으로 라우팅하는 규칙이 포함된 /etc/apache2/conf-available/php8.3-fpm.conf를 활성화합니다. 이 설정의 핵심은 모든 .php 파일을 찾아 /run/php/php8.3-fpm.sock에 위치한 소켓으로 전달하는 것입니다.

<FilesMatch ".+\.ph(ar|p|tml)$">
    SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>

이 파일은 올바르게 제공되므로 직접 수정할 필요가 없습니다. 하지만 소켓 경로를 파악하고 있으면 나중에 발생할 수 있는 "PHP가 실행되지 않고 다운로드됨" 오류나 "Primary script unknown" 오류를 진단할 수 있습니다. 두 오류 모두 Apache와 FPM이 해당 소켓이나 그 뒤의 파일에 대해 서로 다르게 인식할 때 발생합니다.

5단계 - 애플리케이션을 위한 이름 기반 가상 호스트 설정

이름 기반 가상 호스팅을 사용하면 하나의 IP 주소로 여러 사이트를 서비스할 수 있습니다. Apache는 요청에 포함된 Host: 헤더를 확인하여 사이트를 구분합니다. 기본 경로인 /var/www/html에서 벗어난 곳에 애플리케이션을 위한 디렉터리를 생성하십시오.

sudo mkdir -p /var/www/testapp
sudo chown -R www-data:www-data /var/www/testapp
sudo chmod -R 755 /var/www/testapp

소유권 설정이 중요합니다. Ubuntu에서 Apache와 PHP-FPM은 모두 www-data 사용자로 실행됩니다. 따라서 웹 서버가 읽어야 하는 파일과 업로드 폴더처럼 애플리케이션이 쓰기 작업을 수행해야 하는 디렉터리는 www-data가 소유해야 합니다. 로그인한 사용자로 파일을 직접 수정해야 한다면, 파일을 본인 소유로 두고 사용자를 www-data 그룹에 추가하는 방식이 일반적입니다. 단순 배포 환경이라면 www-data:www-data로 설정하는 것이 가장 직관적입니다.

/etc/apache2/sites-available/testapp.conf 경로에 가상 호스트 파일을 생성하십시오.

<VirtualHost *:80>
    ServerName app.example.com
    DocumentRoot /var/www/testapp

    <Directory /var/www/testapp>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/testapp-error.log
    CustomLog ${APACHE_LOG_DIR}/testapp-access.log combined
</VirtualHost>

ServerName를 실제 도메인으로 설정하십시오. Options -Indexes는 인덱스 파일이 없을 때 Apache가 디렉터리 목록을 노출하지 않도록 방지합니다. 이 설정을 하지 않으면 방문자가 소스 트리 구조를 열람할 수 있습니다. AllowOverride All은 대부분의 PHP 애플리케이션이 깔끔한 URL을 위해 요구하는 .htaccess 파일의 동작을 허용합니다. 애플리케이션에서 해당 기능이 필요 없다면 성능 향상을 위해 None로 변경하십시오. 사이트를 활성화하고, 기본 사이트를 비활성화한 뒤, 설정을 검사하고 다시 불러오십시오.

sudo a2ensite testapp
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2

apache2ctl configtest 명령을 실행하면 Syntax OK이 출력되어야 합니다. a2dissite 000-default 줄은 사용자가 자주 누락하는 부분이며, 나중에 기본 페이지가 그대로 유지되는 것처럼 보이는 원인이 됩니다. 자세한 내용은 실패 해결 섹션을 참조하십시오.

6단계 - PHP 실행 확인 및 테스트 파일 삭제

애플리케이션 루트 디렉터리에 한 줄짜리 PHP 파일을 생성합니다.

echo "<?php phpinfo();" | sudo tee /var/www/testapp/info.php

http://app.example.com/info.php에 접속합니다. 정상적인 결과라면 로드된 모듈이 나열된 보라색과 회색의 긴 PHP Version 8.3.x 표가 나타나며, Server API 줄에 FPM/FastCGI라고 표시되어야 합니다. 이 마지막 줄은 요청이 mod_php가 아닌 PHP-FPM을 통해 처리되고 있음을 의미합니다.

이제 즉시 파일을 삭제합니다.

sudo rm /var/www/testapp/info.php

phpinfo()는 정확한 PHP 버전, 로드된 모든 확장 모듈, 파일 경로, 환경 설정 정보를 노출하므로, 서버의 취약점을 찾는 공격자에게는 좋은 정보원이 됩니다. 이는 기능이 아니라 테스트용 파일입니다. 페이지를 확인한 즉시 삭제하십시오. 만약 브라우저에서 표가 나타나지 않고 info.php 파일을 다운로드하겠냐고 묻는다면, PHP가 Apache와 올바르게 연결되지 않은 것입니다. 다른 작업을 수행하기 전에 먼저 실패 해결 섹션으로 이동하십시오.

7단계 - 애플리케이션 데이터베이스 및 최소 권한 사용자 생성

소켓 인증을 사용하는 root 계정으로 데이터베이스에 접속합니다.

sudo mysql

그런 다음 데이터베이스 하나와 해당 데이터베이스에만 권한이 제한된 사용자 하나를 생성합니다.

CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

여기에는 세 가지 의도적인 선택이 포함되어 있습니다. utf8mb4은 실제 4바이트 UTF-8을 지원합니다. 구형 utf8 별칭은 이모지나 일부 CJK 문자를 자동으로 잘라내므로 항상 utf8mb4를 사용해야 합니다. 권한 부여는 *.*이 아닌 appdb.*에 수행합니다. 이렇게 하면 해당 사용자는 자신의 데이터베이스만 접근할 수 있으므로, 애플리케이션에서 SQL 인젝션 취약점이 발생해도 다른 사이트의 테이블을 읽을 수 없습니다. 또한 'appuser'@'localhost'는 해당 계정의 접속을 서버 내부에서 발생하는 연결로만 제한합니다.

해당 사용자로 접속을 테스트합니다.

mysql -u appuser -p appdb

비밀번호를 입력하면 MariaDB [appdb]> 프롬프트가 나타납니다. -h 플래그가 없다는 점에 유의하십시오. 이 플래그를 생략하면 클라이언트는 로컬 Unix 소켓을 통해 연결하며, MariaDB는 이를 정확히 localhost로 간주합니다. 알아두어야 할 주의 사항이 있습니다. MySQL과 MariaDB에서 localhost은 Unix 소켓을 의미하고 127.0.0.1은 TCP 연결을 의미합니다. 기본 Ubuntu 24.04 MariaDB 환경에서는 서버가 127.0.0.1에서 오는 TCP 연결을 localhost로 해석하므로 두 경우 모두 계정이 일치합니다. 하지만 skip-name-resolve이 활성화된 서버(일반적인 성능 최적화 설정이며 많은 컨테이너 이미지의 기본값)에서는 두 연결이 서로 다른 호스트로 간주됩니다. 따라서 127.0.0.1로 접속하는 애플리케이션은 비밀번호가 정확하더라도 ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1' (using password: YES) 오류로 인해 거부됩니다.

따라서 애플리케이션의 호스트 설정은 root이 아닌 localhost, 사용자 appuser, 데이터베이스 appdb로 지정하십시오. PHP의 mysqli 및 PDO는 호스트가 문자열 localhost일 때 자동으로 Unix 소켓을 사용하며, 이는 방금 생성한 계정과 일치합니다. 만약 프레임워크가 반드시 숫자 형태의 TCP 호스트를 요구한다면, 실제 연결 방식에 맞춰 'appuser'@'127.0.0.1'로 사용자를 생성하십시오. 다른 머신에서 데이터베이스에 접근해야 하는 경우에만 방화벽 규칙과 함께 @'%'을 사용하십시오.

8단계 - Certbot으로 HTTPS 추가

일반 HTTP로 로그인 양식을 제공하면 암호가 평문으로 전송되고, 모든 최신 브라우저가 해당 페이지를 "안전하지 않음"으로 표시한다. Certbot을 사용하면 한 번의 명령으로 이 문제를 해결할 수 있다. Apache 플러그인과 함께 설치한다.

sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache

여기서는 Certbot의 두 플러그인을 사용한다. apache authenticator는 실행 중인 Apache를 통해 잠시 challenge 파일을 제공하여 도메인을 제어하고 있음을 증명한다. 이어서 apache installer가 virtual host를 다시 작성하여 443 블록을 추가하고, 새 인증서를 지정하며, 기본적으로 모든 HTTP 트래픽을 HTTPS로 리디렉션한다. Certbot은 version 1.4.0 (May 2020)부터 리디렉션 여부를 묻지 않으므로, 일반 HTTP 제공을 유지해야 한다면 --no-redirect를 전달한다. Step 5에서 실제 ServerName를 설정했으므로 Certbot이 도메인을 자동으로 감지한다. 현재 발급되는 인증서의 유효 기간은 90 days이다 (Let's Encrypt는 10 February 2027에 기본 유효 기간을 64 days로, 16 February 2028에 45 days로 줄인다). 패키지는 인증서를 갱신하는 systemd timer도 설치한다. sudo certbot renew --dry-run로 timer를 확인하면 출력이 Congratulations, all simulated renewals succeeded로 끝나야 한다.

challenge, 갱신 timer, DNS 및 방화벽 요구 사항을 처음부터 끝까지 확인하려면 Apache에서 Certbot으로 무료 Let's Encrypt TLS 인증서 발급 동반 안내서를 참조한다.

백업, 업그레이드 및 보안 강화

상태를 보존하는 두 가지 요소인 데이터베이스와 웹 루트를 백업한다. 매일 밤 수행하는 논리적 덤프가 가장 간단하고 신뢰할 수 있는 방법이며, sudo sh -c 'mysqldump --all-databases --single-transaction | gzip > /root/db-$(date +%F).sql.gz', 이후 서버 외부로 복사한다. 전체 파이프라인을 sudo sh -c로 감싸는 것이 중요하다. 그렇게 하지 않으면 셸이 > /root/... 리디렉션을 현재 사용자 권한으로 실행하므로 Permission denied 오류가 발생한다. mysqldump만 sudo을 상속하기 때문이다. --single-transaction를 사용하면 테이블을 잠그지 않고 InnoDB 테이블의 일관된 스냅샷을 생성할 수 있다. 여기에 tar의 /var/www 및 /etc/apache2/sites-available를 함께 백업하면 해당 파일만으로 새 VPS에서 전체 스택을 다시 구축할 수 있다.

업그레이드는 일반적인 sudo apt update && sudo apt upgrade이다. 릴리스 업그레이드에서 문제가 되는 부분은 PHP 버전 변경이다. Ubuntu 26.04 LTS는 기본 PHP로 PHP 8.5를 제공한다. 여기에서 설치한 php8.3-* 패키지는 해당 릴리스에 존재하지 않는다. 따라서 업그레이드 후에는 php8.5-fpm을 실행하게 되고, 소켓은 /run/php/php8.5-fpm.sock가 되지만 Apache 설정은 여전히 8.3 소켓을 가리킨다. 새 conf를 활성화하고(sudo a2enconf php8.5-fpm) 이전 conf를 비활성화해야 한다. 그렇지 않으면 다른 문제 없이 진행된 업그레이드 후에도 사이트가 Primary script unknown을 반환하기 시작한다. PHP 릴리스는 LTS 배포판보다 빠르게 변경되므로 패치 버전을 고정하기보다 현재 PHP 릴리스 노트를 확인한다.

첫날 수행할 만한 보안 강화 작업은 두 가지다. 첫째, 서버에 SSH를 감시하는 Fail2Ban을 설치한다. 공용 VPS는 몇 분 안에 자동화된 로그인 시도를 받기 시작한다. 간단한 jail을 설정하면 차단하기 전에 수천 건의 시도를 몇 건으로 줄일 수 있다. 둘째, 파일을 직접 편집하는 대신 브라우저에서 Apache virtual host, MariaDB 데이터베이스 및 사용자를 관리하고 싶다면 Webmin 웹 기반 제어판을 사용할 수 있다. 이 제어판은 바로 이 스택 위에서 동작하며 방금 작성한 동일한 설정 파일을 관리한다. 어느 것도 각 구성 요소에 대한 이해를 대신할 수는 없지만, 둘 다 일상적인 운영 부담을 줄여 준다.

문제 상황과 표시되는 메시지

기본 페이지가 사라지지 않습니다. 가상 호스트를 수정하고 Apache를 reload했지만 브라우저에 여전히 "Apache2 Ubuntu Default Page"와 "It works!" 배너가 표시됩니다. Apache는 처음으로 일치하는 가상 호스트를 제공하며, 요청과 일치하는 ServerName가 없으면 알파벳순으로 가장 앞선 설정이 선택됩니다. 000-default.conf이 testapp.conf보다 먼저 정렬됩니다. 요청의 호스트 이름이 ServerName와 일치하지 않거나 sudo a2dissite 000-default을 실행하지 않은 것입니다. 기본 설정을 비활성화하고 sudo systemctl reload apache2을 실행한 뒤 apache2ctl -S로 확인합니다. 이 명령은 가상 호스트 매핑을 출력하고 기본 가상 호스트를 소유한 설정을 보여줍니다. 브라우저 캐시도 삭제합니다. 이전 페이지에서 받은 200 응답이 캐시에 남아 계속 표시될 수 있습니다.

.php 파일이 실행되지 않고 다운로드됩니다. info.php을 열었을 때 브라우저가 원시 <?php 소스가 들어 있는 파일을 다운로드하거나 일반 텍스트로 표시하고 실행하지 않습니다. PHP handler가 연결되지 않아 Apache가 파일을 정적 자산으로 제공하고 있기 때문입니다. sudo a2enmod proxy_fcgi을 건너뛰었거나 sudo a2enconf php8.3-fpm을 실행하지 않았거나, 이후 Apache를 restart하지 않았을 수도 있습니다. 세 작업을 모두 실행합니다(Step 4). 그런 다음 다시 로드합니다. apache2ctl -M | grep fcgi으로 모듈이 로드되었는지 확인합니다. 출력에 proxy_fcgi_module가 표시되어야 합니다. 이는 단순한 표시 문제가 아니라 소스 코드가 유출되는 문제이므로, 실제 서비스를 서버에 올리기 전에 수정해야 합니다.

ERROR 1698 (28000): Access denied for user 'root'@'localhost'. sudo 없이 mysql -u root 또는 mariadb -u root을 실행했습니다. root 계정은 unix_socket 인증을 사용하므로 OS 사용자가 실제로 root인 경우에만 인증을 허용합니다. 해결 방법은 sudo mysql입니다. -u root도 필요 없고 비밀번호도 필요 없습니다. 이 메시지는 socket 인증이 정상적으로 작동할 때 나타나는 예상된 동작이며, 설치가 손상되었다는 뜻이 아닙니다.

애플리케이션에서 올바른 비밀번호를 사용했는데도 ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1'가 표시됩니다. 계정은 'appuser'@'localhost'로 존재하지만, 애플리케이션이 호스트 이름 확인이 비활성화된 서버(skip-name-resolve)에서 127.0.0.1로 TCP 연결을 시도하고 있습니다. 따라서 MariaDB는 두 호스트를 서로 다른 호스트로 처리합니다. localhost은 Unix socket이고 127.0.0.1은 TCP입니다. 애플리케이션의 host를 localhost로 지정해 socket을 사용하고 해당 계정과 일치시키거나, framework가 TCP만 사용할 수 있다면 두 번째 계정 'appuser'@'127.0.0.1'를 생성합니다.

브라우저에 File not found.가 표시되면서 /var/log/apache2/testapp-error.log에 AH01071: Got error 'Primary script unknown'이 표시됩니다. Apache가 요청을 PHP-FPM에 전달했지만 FPM이 Apache가 전달한 경로에서 스크립트를 찾지 못했습니다. 일반적인 원인은 2가지입니다. 설정의 FPM socket이 설치되지 않은 PHP 버전을 가리키는 경우입니다. 예를 들어 release upgrade 후 PHP 8.5로 변경되었는데 8.3 socket 설정이 그대로 남아 있을 수 있습니다. 또는 DocumentRoot 때문에 실제로 파일이 없고 설정의 디렉터리와 실제 디렉터리가 서로 다른 경우입니다. ls -l /run/php/으로 socket이 존재하는지 확인하고, DocumentRoot가 파일이 있는 위치와 일치하는지 확인합니다. 그런 다음 php8.3-fpm(또는 실제로 설치된 PHP-FPM 버전)을 restart하고 apache2도 restart합니다.

재시작할 때마다 AH00558: apache2: Could not reliably determine the server's fully qualified domain name이 표시됩니다. 이는 오류가 아니라 무해한 경고입니다. Apache에 전역 ServerName가 설정되지 않았다는 뜻입니다. ServerName your.domain을 /etc/apache2/conf-available/servername.conf에 작성하고 sudo a2enconf servername를 실행하면 이 경고가 표시되지 않습니다.

Apache가 시작될 때 (98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80이 표시됩니다. 다른 웹 서버가 이미 port 80을 사용하고 있는 것입니다. 이전 실험에서 남은 nginx가 원인인 경우가 많습니다. sudo ss -ltnp | grep :80로 해당 프로세스를 찾은 다음, Apache를 시작하기 전에 다른 서비스를 stop하고 disable합니다.

FAQ

mod_php와 PHP-FPM 중 무엇을 사용해야 합니까?

PHP-FPM을 사용하십시오. mod_php은 모든 Apache 프로세스에 인터프리터를 내장하며 느린 prefork MPM 사용을 강제하므로, 정적 이미지를 서비스할 때도 Apache가 PHP 오버헤드를 짊어지게 됩니다. PHP-FPM은 PHP를 별도의 독립적으로 튜닝된 풀로 실행하며, Apache는 소켓을 통해 이 풀에 접근합니다. 이는 더 빠른 스레드 기반 event MPM과 함께 작동하며, 나중에 nginx로 전환할 때도 그대로 사용할 수 있습니다. 이것이 현대적인 기본 설정입니다. mod_php는 프로세스 내부 동작에 의존하는 레거시 애플리케이션을 운영할 때만 의미가 있습니다.

브라우저에서 PHP 파일을 실행하지 않고 다운로드하는 이유는 무엇입니까?

Apache가 .php 파일을 PHP 핸들러가 연결되지 않은 정적 다운로드 파일로 처리하고 있기 때문입니다. FPM을 사용하는 Ubuntu 24.04 환경에서 이런 현상이 발생한다면 sudo a2enmod proxy_fcgi, sudo a2enconf php8.3-fpm 중 하나를 누락했거나 Apache 재시작을 수행하지 않은 것입니다. 세 가지 명령을 모두 실행하고 리로드한 뒤, apache2ctl -M | grep fcgi 명령으로 proxy_fcgi_module가 목록에 있는지 확인하십시오. 이 문제를 해결하기 전까지 서버는 소스 코드를 그대로 노출하므로 긴급하게 처리해야 합니다.

올바른 비밀번호를 입력해도 MariaDB에서 root 접근이 거부되는 이유는 무엇입니까?

Ubuntu의 MariaDB는 비밀번호가 설정되어 있지 않을 경우 root 계정을 unix_socket으로 인증하며, 이를 운영체제의 root 사용자와 연결하기 때문입니다. 일반 셸에서 mysql -u root을 실행하면 설계상 ERROR 1698 (28000): Access denied for user 'root'@'localhost'이 반환됩니다. 대신 sudo mysql로 접속하고, root 계정을 재사용하는 대신 애플리케이션용으로 별도의 비밀번호 인증 사용자를 생성하십시오.

LAMP 사이트에 HTTPS를 추가하려면 어떻게 해야 합니까?

certbot와 python3-certbot-apache을 설치하고, 도메인의 A 레코드를 서버 IP로 지정한 뒤 sudo certbot --apache을 실행하십시오. Apache 인증기는 실행 중인 Apache를 통해 도메인 소유권을 증명하며, 설치 프로그램이 포트 443에 대한 가상 호스트를 재작성하고 자동 갱신을 설정합니다. Certbot과 Apache 전체 가이드에서 챌린지 과정, 갱신 타이머, 일반적인 실패 사례를 확인할 수 있습니다.

#lamp#apache#mariadb#php-fpm#ubuntu