Ubuntu 22.04 Server / Apache, PHP, MariaDB 설치하는 방법
Ubuntu 22.04 Server에서는 Apache, PHP용 Apache 모듈, MariaDB와 PHP 데이터베이스 확장 패키지를 설치하면 기본 웹 실행 환경을 구성할 수 있습니다. 설치 후에는 MariaDB 관리자 계정과 웹 애플리케이션 계정을 분리하고, PHP가 데이터베이스의 값을 읽는지 확인해야 합니다.
설치 범위와 패키지 준비
이 글은 Ubuntu 22.04 기본 저장소를 사용하는 새 서버 한 대에서 Apache와 MariaDB를 함께 실행하는 구성입니다. sudo 권한과 패키지 다운로드를 위한 인터넷 연결이 필요합니다. 기존 서버라면 웹 설정과 데이터베이스를 먼저 백업하고, 같은 이름의 파일·계정·데이터베이스가 없는지 확인하세요. 이미 PHP-FPM을 사용한다면 이 글의 Apache 모듈 방식과 섞어 적용하지 마세요.
- 패키지 목록을 갱신하고 필요한 구성 요소를 설치합니다.
libapache2-mod-php는 Apache에서 PHP를 처리하며,php-mysql은 MariaDB 연결에 사용할 확장을 제공합니다. 명령줄 검사에 필요한php-cli도 함께 설치합니다. 구성 방식은 Ubuntu의 PHP 설치 문서에서 확인할 수 있습니다.
sudo apt update
sudo apt install apache2 mariadb-server php php-cli libapache2-mod-php php-mysql
- 서비스를 시작하고 부팅 시 자동 실행을 설정합니다. Apache 설정 검사가
Syntax OK인지 확인한 뒤 Apache를 재시작하여 PHP 모듈을 반영합니다.
sudo systemctl enable --now apache2 mariadb
sudo apache2ctl configtest
sudo systemctl restart apache2
systemctl is-active apache2 mariadb
마지막 명령은 두 서비스가 실행 중이면 각각 active를 표시합니다. apache2 -v, php -v, mariadb --version으로 설치된 버전을 확인할 수 있습니다. 추가 저장소를 등록한 서버는 기본 저장소와 다른 PHP 버전이 설치될 수 있습니다.
MariaDB 관리자 인증 확인
Ubuntu의 기본 MariaDB 패키지는 일반적으로 로컬 관리자에게 Unix 소켓 인증을 사용합니다. 이는 운영체제 사용자 신원을 확인하는 방식이므로, root 비밀번호를 비워 둔 채 누구나 접속할 수 있다는 뜻이 아닙니다. 먼저 다음과 같이 관리자 셸로 접속하여 현재 계정과 설정을 확인합니다.
sudo mariadb --protocol=socket
SELECT VERSION(), CURRENT_USER();
SHOW CREATE USER 'root'@'localhost';
EXIT;
root 인증은 기존 설정에 따라 다를 수 있습니다. MariaDB 10.4 이후의 인증 설명처럼 소켓 인증을 유지하면서 별도의 애플리케이션 계정을 만드는 것이 이 예제의 전제입니다. mysql.user의 plugin 값을 직접 UPDATE하거나 웹 프로그램에 root 계정을 넣지 않습니다.
초기 설치의 보안 항목은 다음 도구로 점검할 수 있습니다. 질문 문구와 순서는 버전·현재 설정에 따라 달라지므로 모든 질문에 기계적으로 Y를 입력하지 마세요.
sudo mariadb-secure-installation
- 이미 소켓 인증으로 관리하고 있다면 이를 유지할 수 있습니다. MariaDB 공식 도구 설명에 따르면 이 구성에서는 보통 root 비밀번호를 새로 설정할 필요가 없습니다.
- 새 서버에서는 익명 사용자와 불필요한 test 데이터베이스를 제거하고 원격 root 로그인을 제한하는 선택이 적합합니다. 기존 서비스가 있다면 사용 여부를 확인한 뒤 결정하고, 권한 테이블 갱신 질문이 나오면 변경을 반영합니다.
애플리케이션 전용 데이터베이스와 계정 만들기
다시 sudo mariadb --protocol=socket으로 접속하여 다음 SQL을 실행합니다. lampdemo와 lamp_app은 이 실습에서 새로 만드는 이름입니다. 이미 존재하면 덮어쓰거나 삭제하지 말고 다른 이름을 정해 이후 예제에도 동일하게 적용하세요. 비밀번호 자리표시자는 길고 고유한 실제 비밀번호로 바꾸고, 다음 PHP 설정에도 같은 값을 입력합니다. 작은따옴표가 포함된 비밀번호는 SQL·PHP 각각의 문자열 이스케이프 규칙에 맞게 작성해야 합니다.
CREATE DATABASE lampdemo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'lamp_app'@'localhost' IDENTIFIED BY 'REPLACE_WITH_A_LONG_UNIQUE_PASSWORD';
GRANT SELECT, INSERT, UPDATE, DELETE ON lampdemo.* TO 'lamp_app'@'localhost';
CREATE TABLE lampdemo.health_check (
id INT PRIMARY KEY,
message VARCHAR(100) NOT NULL
);
INSERT INTO lampdemo.health_check (id, message) VALUES (1, 'database-ok');
EXIT;
테이블 생성은 관리자 계정으로 수행하고, 앱에는 해당 데이터베이스의 조회·추가·수정·삭제 권한만 부여합니다. 앱 설치 도구가 테이블 생성 권한을 요구하면 필요한 권한을 따로 검토해야 합니다. GRANT로 권한을 부여한 뒤 별도의 FLUSH PRIVILEGES는 필요하지 않습니다.
터미널에서 앱 계정으로 조회하여 database-ok가 나오는지 확인합니다. -p 뒤에 비밀번호를 쓰지 않고 입력 요청이 나올 때 입력합니다.
mariadb --protocol=socket -u lamp_app -p lampdemo -e "SELECT message FROM health_check WHERE id=1;"
PHP 연동 예제 파일 만들기
Ubuntu Apache 기본 사이트의 웹 문서 경로는 보통 /var/www/html입니다. 기존 가상 호스트를 사용한다면 sudo apache2ctl -S와 해당 사이트의 DocumentRoot 설정을 확인하여 예제 파일 경로를 맞추세요. 아래 경로의 파일이 이미 있으면 다른 이름을 사용합니다. 비밀번호가 담긴 설정 파일은 웹 문서 경로 밖에 보관합니다.
- 설정 디렉터리를 만들고 편집기를 엽니다. 아래 권한은 Apache 프로세스가 Ubuntu 기본 사용자·그룹인
www-data로 실행되는 구성을 전제로 합니다.
sudo install -d -o root -g www-data -m 0750 /etc/lamp-demo
sudoedit /etc/lamp-demo/database.php
/etc/lamp-demo/database.php에 다음 전체 내용을 저장합니다. password 값은 앞에서 설정한 앱 비밀번호로 바꾸세요. PHP의 PDO_MYSQL 연결 설명처럼 Unix 환경의 host=localhost는 소켓 연결을 사용합니다. 이를 127.0.0.1로 바꾸면 TCP 연결이 되어 계정·연결 조건이 달라질 수 있습니다.
<?php
return [
'dsn' => 'mysql:host=localhost;dbname=lampdemo;charset=utf8mb4',
'user' => 'lamp_app',
'password' => 'REPLACE_WITH_A_LONG_UNIQUE_PASSWORD',
];
- 설정 파일을 root 소유로 두고 Apache 그룹만 읽을 수 있게 합니다. 이어서 웹 확인 파일을 엽니다.
sudo chown root:www-data /etc/lamp-demo/database.php
sudo chmod 0640 /etc/lamp-demo/database.php
sudoedit /var/www/html/lamp-check.php
/var/www/html/lamp-check.php에 다음 전체 내용을 저장합니다. PDO(PHP Data Objects)는 PHP에서 데이터베이스에 접근하는 인터페이스이며, 이 코드는 실제 테이블 값을 확인한 뒤 성공 메시지를 출력합니다. 실패하면 HTTP 500과 일반 오류 문구를 보내고 상세 원인은 서버 로그에 기록합니다.
<?php
declare(strict_types=1);
header('Content-Type: text/plain; charset=UTF-8');
try {
$config = require '/etc/lamp-demo/database.php';
$pdo = new PDO($config['dsn'], $config['user'], $config['password'], [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$message = $pdo->query('SELECT message FROM health_check WHERE id = 1')->fetchColumn();
if ($message !== 'database-ok') {
throw new RuntimeException('Unexpected database result');
}
echo "PHP OK\nDatabase OK\n";
} catch (Throwable $e) {
http_response_code(500);
error_log('lamp-check failed: ' . $e->getMessage());
echo "Check failed; review server logs.\n";
}
- 웹 확인 파일은 읽기 가능한 권한으로 두고 두 파일의 PHP 문법을 검사합니다.
No syntax errors detected는 문법 검사 결과이며, 데이터베이스 연결 성공을 의미하지는 않습니다.
sudo chown root:root /var/www/html/lamp-check.php
sudo chmod 0644 /var/www/html/lamp-check.php
sudo php -l /etc/lamp-demo/database.php
php -l /var/www/html/lamp-check.php
설정 파일은 일반 사용자에게 읽기 권한이 없을 수 있으므로 해당 문법 검사는 sudo로 실행합니다. 웹 디렉터리 전체에 쓰기 권한을 주거나 chmod 777을 적용할 필요는 없습니다.
HTTP 응답과 데이터베이스 연결 확인
서버 안에서 다음 주소를 요청합니다. curl이 없다면 sudo apt install curl로 설치합니다. HTTP 상태가 200이고 본문에 아래 두 줄이 나오면 Apache가 PHP를 실행하고 PHP가 MariaDB의 예제 행을 읽은 것입니다.
curl -i http://127.0.0.1/lamp-check.php
PHP OK
Database OK
다른 컴퓨터에서는 브라우저에 http://서버-IP/lamp-check.php를 입력합니다. 가상 호스트를 사용하면 설정된 호스트 이름으로 접속해야 합니다. 기본 환영 페이지만 보거나 php -v만 실행하는 것으로는 이 연동이 확인되지 않습니다.
서버 내부에서는 되지만 외부에서 접속되지 않으면 sudo ufw status verbose, 클라우드 보안 그룹과 라우팅을 확인하세요. UFW가 이미 활성화된 사설망 실습 환경이라면 아래처럼 실제 접속할 대역에 HTTP 80번만 허용할 수 있습니다. 192.168.10.0/24는 예시이므로 자신의 신뢰할 수 있는 대역으로 바꿉니다. 이 테스트를 위해 방화벽을 끄거나 원격 SSH 허용 없이 새로 활성화하지 마세요.
sudo ufw allow from 192.168.10.0/24 to any port 80 proto tcp
이 구성에서는 PHP와 MariaDB가 같은 서버의 소켓으로 통신하므로 3306번 포트를 외부에 열 필요가 없습니다. HTTP 실습은 신뢰할 수 있는 환경에서 하고, 실제 서비스에서 로그인 정보 등을 주고받기 전에는 도메인·가상 호스트와 HTTPS 인증서를 별도로 구성해야 합니다.
오류 확인과 테스트 파일 정리
연결 실패는 서비스 상태, PHP 모듈, 계정, 파일 권한 순서로 좁혀 확인합니다. 다음 명령은 Apache 설정·모듈과 두 서비스의 최근 로그를 확인하는 용도입니다. 로그에는 운영 정보가 포함될 수 있으므로 공개 게시물에 그대로 올리지 마세요.
sudo apache2ctl configtest
sudo apache2ctl -M
sudo tail -n 50 /var/log/apache2/error.log
sudo journalctl -u apache2 -u mariadb -n 50 --no-pager
- PHP 원문이 표시되거나 다운로드됨: 공개 접근을 중단하고 Apache의 PHP 모듈 활성화와 재시작 여부부터 확인합니다.
libapache2-mod-php설치 후에도 문제가 있으면 기존 PHP-FPM·가상 호스트 구성을 함께 점검합니다. - could not find driver: Apache가 사용하는 PHP 버전에 맞는
php-mysql확장이 설치·활성화되었는지 확인하고 Apache를 재시작합니다. 명령줄 PHP와 Apache의 PHP는 설정이 다를 수 있습니다. - Access denied: 앱 비밀번호,
'lamp_app'@'localhost'계정과 권한을 확인합니다. root 인증을 바꾸거나 전역 권한을 주어 해결하지 마세요. 소켓을 찾지 못하면 MariaDB의SHOW VARIABLES LIKE 'socket';결과와 PHP 소켓 설정을 비교합니다. - Permission denied 또는 404: 설정 파일은 Apache 사용자가 읽을 수 있는지, 웹 파일은 요청한 사이트의 DocumentRoot에 있는지 확인합니다.
/etc/lamp-demo의 디렉터리 접근 권한도 함께 확인하세요.
확인이 끝나면 아래 명령으로 이 글에서 만든 웹 테스트 파일만 삭제하고 같은 주소가 더 이상 성공 메시지를 반환하지 않는지 확인합니다. 기존 phpinfo.php 같은 환경 정보 공개 파일도 남겨 두지 마세요. 설정 파일은 실제 앱에서 사용한다면 웹 경로 밖의 제한된 권한을 유지합니다.
sudo rm -- /var/www/html/lamp-check.php
실습용 데이터까지 정리하려면 다른 서비스가 사용하지 않는지 확인한 뒤 관리자 셸에서 아래 SQL을 실행합니다. 데이터베이스 삭제는 데이터를 되돌릴 수 없으므로 필요한 내용은 먼저 백업하세요. 이 글에서 새로 만든 이름에만 적용합니다.
DROP DATABASE lampdemo;
DROP USER 'lamp_app'@'localhost';
동일 서버 구성에서는 MariaDB의 로컬 바인딩 설정을 유지합니다. 원격 데이터베이스 연결이 별도로 필요하더라도 bind-address를 무조건 삭제하지 말고, 수신 주소·허용 출발지·전용 계정·암호화 연결을 함께 설계해야 합니다.




