수동 설치

완전 수동 설치: 방금 구입한 VPS부터 작동하는 대시보드까지 단계별로 안내합니다. 서버 준비, 사이트 생성, 데이터베이스, config.php, SSL을 여기서 다룹니다. 각 보안 도구와 cron 관련 명령은 FAQ 레퍼런스에 있으며, 중간에 링크로 안내합니다.

핵심 규칙: SSH나 방화벽을 변경할 때는 별도 창에서 새 설정을 확인하기 전까지 현재 연결을 끊지 마세요. 그래도 접속이 끊겼다면, 대부분의 호스팅 업체는 관리 패널에서 긴급 콘솔(VNC/Recovery)을 제공합니다.

01. Ubuntu/Debian이 설치된 VPS를 구매했다면 — 시작하기

구매 후 호스팅 업체에서 IP 주소, 사용자 이름(보통 root), 비밀번호(또는 SSH 키)를 보내줍니다. 로그인에는 이 정보로 충분합니다. 작업 순서(각 단계는 아래 항목 참조):

  1. SSH로 서버에 접속합니다;
  2. 시스템을 업데이트하고 호스트 이름과 시간대를 설정합니다;
  3. sudo 권한을 가진 일반 사용자를 생성합니다(root로 작업하지 않기);
  4. SSH 키 로그인을 설정하고 비밀번호 로그인을 비활성화합니다;
  5. 방화벽과 자동 보호를 활성화합니다;
  6. (선택 사항) 관리 패널 HestiaCP를 설치합니다 — 웹 서버, DB, 메일을 기본 제공합니다.

02. SSH로 첫 접속하기

SSH는 서버에 접속하는 보안 터미널입니다. 203.0.113.10 대신 본인의 IP를 입력하세요.

203.0.113.10예시일 뿐이며 존재하지 않는 주소입니다(문서용으로 예약된 주소). 그대로 입력하지 말고 호스팅 업체 메일에 있는 실제 서버 IP로 바꾸세요. 그렇지 않으면 접속되지 않습니다.

Windows 10/11: PowerShell 또는 "터미널"을 열고 내장된 ssh를 사용하세요(또는 PuTTY / MobaXterm 클라이언트).
macOS / Linux: "터미널"을 여세요.

# root로 로그인(비밀번호는 호스팅 업체가 보냄): ssh root@203.0.113.10 # 호스팅 업체가 비밀번호 대신 키 파일을 준 경우: ssh -i 키/파일/경로 root@203.0.113.10
처음 접속하면 SSH가 "authenticity of host"에 대해 물어봅니다. yes를 입력하세요. 비밀번호는 입력해도 화면에 표시되지 않습니다(정상입니다). 호스팅 업체가 임시 비밀번호를 준 경우 passwd 명령으로 변경하세요.

03. 시스템 업데이트 및 기본 설정

가장 먼저 모든 패키지를 업데이트하고 호스트 이름과 시간대를 설정하세요.

# 시스템 업데이트: apt update && apt upgrade -y # 기본 유틸리티: apt install -y curl wget ufw fail2ban unattended-upgrades # 시간대(예시)와 호스트 이름: timedatectl set-timezone Asia/Seoul hostnamectl set-hostname myserver # 자동 보안 업데이트: dpkg-reconfigure -plow unattended-upgrades
시간대 목록은 timedatectl list-timezones로 확인합니다. 업데이트 종료 시 “Daemons using outdated libraries” 파란색 창이 나타나면 모든 서비스를 선택(스페이스바)하고 OK를 누르세요. 안전합니다.

04. sudo 권한 사용자 생성

항상 root로 작업하는 것은 안전하지 않습니다. 일반 사용자를 만들고 sudo 권한(필요할 때 관리자 권한으로 명령 실행)을 부여하세요. deploy는 원하는 이름으로 바꾸면 됩니다.

# 사용자 생성 (비밀번호 설정 및 정보 입력 요청 — Enter로 넘어갈 수 있음): adduser deploy # sudo 그룹에 추가: usermod -aG sudo deploy # 확인 (root 권한으로): su - deploy sudo whoami # 출력되어야 함: root exit
이후에는 이 사용자로 서버에 접속하세요: ssh deploy@203.0.113.10. 관리자 명령은 sudo 접두사를 붙여 실행하세요.

05. SSH 키와 비밀번호 로그인 비활성화

키 로그인은 비밀번호보다 안전합니다. 비밀번호는 추측이 가능하지만 키는 사실상 불가능합니다. 먼저 본인 컴퓨터에서 키를 생성하고 서버로 복사한 뒤 로그인을 확인하고, 그다음에야 비밀번호를 비활성화합니다.

1단계. 본인 컴퓨터에서 키 생성(Windows PowerShell / macOS / Linux):

ssh-keygen -t ed25519 -C "my-laptop" # 모든 질문에 Enter (키는 ~/.ssh/id_ed25519에 저장됨)

2단계. 공개 키를 서버로 복사:

# macOS / Linux: ssh-copy-id deploy@203.0.113.10 # Windows (PowerShell): type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh deploy@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

3단계. 창에서 키 로그인을 확인 — 비밀번호 없이 접속되어야 합니다:

ssh deploy@203.0.113.10
키 로그인을 검증하고 정상 작동을 확인하기 전(1~3단계)에는 옵션 B를 실행하지 말고, 작업 중인 세션도 닫지 마세요. 이 옵션은 root를 포함한 모든 사용자의 비밀번호 로그인을 비활성화합니다. 작동하는 키가 없으면 서버 접근 권한을 완전히 잃게 되며 — 그때는 호스팅 콘솔로만 복구할 수 있습니다. 키가 없으면 옵션 A를 선택하세요.

4단계. SSH 접근을 강화합니다. 설정은 별도의 파일에 두고 기본 설정은 건드리지 않습니다. 상황에 맞는 옵션을 선택하세요:

옵션 A — root만 차단하고 비밀번호는 유지. 키가 필요 없고 접근 권한도 잃지 않습니다:

echo 'PermitRootLogin no' | sudo tee /etc/ssh/sshd_config.d/00-hardening.conf >/dev/null sudo systemctl restart ssh

옵션 B — 완전한 하드닝. 비밀번호 로그인을 비활성화하고 root는 키로만 접속하도록 남깁니다. 키 로그인이 작동함을 확인한 경우에 실행하세요:

sudo tee /etc/ssh/sshd_config.d/00-hardening.conf >/dev/null <<'EOF' PubkeyAuthentication yes PasswordAuthentication no PermitRootLogin prohibit-password KbdInteractiveAuthentication no EOF sudo systemctl restart ssh
두 옵션 모두 root의 비밀번호 로그인을 차단합니다. PermitRootLogin no는 root를 완전히 금지하고, prohibit-password는 키 로그인만 남깁니다(관리 시에는 deploy로 로그인하고 sudo를 사용). SSH 포트를 변경하려면 Port 2222 줄을 추가하되, 먼저 방화벽에서 새 포트를 열고(다음 섹션) 로그인을 확인하세요. 그렇지 않으면 접근이 막힙니다.

06. 기본 방화벽 및 자동 보호

방화벽으로 불필요한 것을 모두 차단하고 fail2ban(SSH 비밀번호 무차별 대입을 차단)을 활성화하세요. 먼저 SSH를 허용하세요. 그렇지 않으면 UFW 활성화 후 접속이 끊깁니다.

# SSH(포트를 변경했다면 해당 포트)와 웹 허용: sudo ufw allow OpenSSH sudo ufw allow 80,443/tcp # 방화벽 활성화: sudo ufw enable sudo ufw status verbose # fail2ban — SSH 무차별 대입 방어(기본 프로필이 즉시 활성화됨): sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd
이것은 최소 구성입니다. 실전용 fail2ban 설정, ipsum 차단 목록, 확장된 UFW 및 기타 도구는 설명서의 “보안 도구” 그룹에 있습니다. Arcivéo Monitor 패널이 이 모든 상태를 한눈에 보여줍니다.

07. HestiaCP 패널 설치 (선택)

HestiaCP는 무료 호스팅 관리 패널입니다. 웹 서버(nginx + apache), PHP, 데이터베이스(MariaDB), 메일, DNS, SSL 인증서를 설치·구성하고 사이트용 웹 인터페이스를 제공합니다. 모든 것을 수동으로 설정하지 않고 사이트(Arcivéo Monitor 패널 자체 포함)를 운영하려는 경우 편리합니다.

HestiaCP는 깨끗한 서버에(지원되는 최신 Ubuntu/Debian, 최소 ~1~2GB RAM), 다른 웹 서버와 DB를 설치하기 전에 설치하세요. 그렇지 않으면 충돌이 발생합니다. 설치에는 10~20분이 걸리며 서버가 재부팅됩니다.
# 설치 프로그램 다운로드 후 실행: wget https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install.sh sudo bash hst-install.sh

설치 프로그램이 이메일과 호스트 이름을 물은 다음 전체 스택을 설치합니다. 재부팅 후 패널은 https://YOUR_IP:8083 주소로 접속할 수 있습니다(로그인과 비밀번호는 설치 프로그램이 마지막에 표시합니다).

HestiaCP는 UFW와 fail2ban을 직접 관리하므로 따로 설정할 필요 없이 자동으로 처리합니다. SSH 키와 비밀번호 비활성화(이전 섹션)는 그래도 진행하세요.

08. 시스템 요구 사항 및 ionCube

대시보드는 일반적인 LAMP/LEMP 스택에서 동작하는 PHP 애플리케이션입니다:

  • OS: Linux (Ubuntu/Debian 권장);
  • 웹 서버: nginx 또는 PHP-FPM을 갖춘 Apache;
  • PHP 8.0+ 및 확장: pdo_mysql, openssl, curl, json, mbstring;
  • ionCube Loader — 대시보드 동작에 필요한 PHP 확장;
  • DB: MySQL 5.7+ 또는 MariaDB 10.3+;
  • HTTPS — 필수 (로그인 및 WebAuthn은 https에서만 동작);
  • 웹 서버 사용자를 위한 sudo (제한된 범위 — 13단계).
# PHP 버전 및 확장 확인: php -v php -m | grep -iE 'pdo_mysql|openssl|curl|mbstring|ioncube'

ionCube Loader 설치 (아직 설치되지 않은 경우). 제어판이 있는 호스팅(HestiaCP, cPanel)에서는 PHP 설정의 체크박스로 ionCube를 활성화합니다. Ubuntu/Debian에서 수동으로:

# PHP 버전 및 확장 디렉터리 확인: php -v EXTDIR=$(php -r 'echo ini_get("extension_dir");'); PHPVER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;') # 로더 다운로드 및 압축 해제 (64-bit): cd /tmp wget -q https://downloads.ioncube.com/loader_downloads/ioncube_loaders_lin_x86-64.tar.gz tar xzf ioncube_loaders_lin_x86-64.tar.gz # 사용하는 PHP 버전에 맞는 로더를 확장 디렉터리로 복사: sudo cp ioncube/ioncube_loader_lin_${PHPVER}.so "$EXTDIR"/ # 연결 (CLI + PHP-FPM) 후 재시작: echo "zend_extension=ioncube_loader_lin_${PHPVER}.so" | sudo tee /etc/php/${PHPVER}/mods-available/ioncube.ini sudo phpenmod ioncube sudo systemctl restart php${PHPVER}-fpm # 확인 — 출력에 "with the ionCube PHP Loader" 줄이 나타납니다: php -v
로더 버전은 PHP 버전과 일치해야 합니다 (예: PHP 8.1의 경우 ioncube_loader_lin_8.1.so). 여러 PHP 버전을 사용한다면 각 버전에 맞는 로더를 연결하세요.

09. 도메인과 DNS

monitor.example.com 같은 주소로 대시보드를 열고 무료 SSL을 받으려면 서버를 가리키는 도메인이 필요합니다. DNS 관리 패널에서 A 레코드를 생성하세요:

유형: A 이름: monitor (서브도메인 → monitor.example.com) 또는 @ (도메인 루트 → example.com) 값: 203.0.113.10 ← 서버의 IP TTL: 3600

몇 분 후 도메인이 서버를 가리키는지 확인하세요:

dig +short monitor.example.com # 서버의 IP가 반환되어야 함 # 또는 dig가 없으면: getent hosts monitor.example.com
Let's Encrypt SSL 인증서는 도메인에만 발급됩니다 — 인증서 발급 전에 DNS가 서버를 가리키고 있어야 합니다.

10. 사이트 생성 및 패널 파일 업로드

Apache: DocumentRoot는 패널 루트로 지정하고, public/이 아닙니다. 스타일(CSS/JS), sw.js, manifest.jsonpublic/ 옆의 assets/에 있으며 사이트 루트에서 요청됩니다. 루트의 .htaccess가 프런트 컨트롤러입니다. Apache에서 DocumentRoot를 public/으로 지정하면 패널이 스타일 없이 열립니다. 순수 nginx는 반대입니다. 루트로 public/을 사용하고 assets/는 별도 규칙으로 제공합니다(아래 nginx 블록 참고).
패널 파일(배포판 아카이브)은 구매 후 my.arciveo.com 계정의 → “다운로드”에서 받습니다. 업로드하기 전에 아카이브를 압축 해제하세요.

1) 패널 디렉터리를 생성하고 그 안에 배포판 내용물을 올려서 public/, assets/, config.php 등이 들어가도록 하세요:

sudo mkdir -p /var/www/monitor # 그런 다음 배포판 파일을 /var/www/monitor에 업로드 (FileZilla / WinSCP / scp)

2) 웹 서버를 설정하세요. Apache: DocumentRoot는 패널 루트로(/public이 아님); AllowOverride All은 필수입니다. PHP-FPM 소켓 경로는 자동으로 판별됩니다. 블록은 전체를 터미널에 붙여 넣습니다:

PHPSOCK=$(ls -1 /run/php/php*-fpm.sock 2>/dev/null | head -1) # PHP-FPM 소켓 자동 판별 sudo tee /etc/apache2/sites-available/monitor.conf > /dev/null <<'EOF' <VirtualHost *:80> ServerName monitor.example.com DocumentRoot /var/www/monitor <Directory /var/www/monitor> AllowOverride All Require all granted </Directory> <FilesMatch \.php$> SetHandler "proxy:unix:__PHPSOCK__|fcgi://localhost" </FilesMatch> </VirtualHost> EOF sudo sed -i "s#__PHPSOCK__#${PHPSOCK}#" /etc/apache2/sites-available/monitor.conf sudo a2dissite 000-default.conf sudo a2ensite monitor.conf sudo apache2ctl configtest sudo systemctl reload apache2

nginx: nginx에는 .htaccess가 없으므로 루트로 public/을 사용하고, (한 단계 위에 있는) assets/, sw.js, manifest.json은 별도 규칙으로 제공합니다:

PHPSOCK=$(ls -1 /run/php/php*-fpm.sock 2>/dev/null | head -1) # PHP-FPM 소켓 자동 판별 sudo tee /etc/nginx/sites-available/monitor.conf > /dev/null <<'EOF' server { listen 80; server_name monitor.example.com; root /var/www/monitor/public; index index.php; # assets, service worker, manifest는 public/보다 한 단계 위에 있음 location ~ ^/(assets/|sw\.js|manifest\.json) { root /var/www/monitor; } location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:__PHPSOCK__; } } EOF sudo sed -i "s#__PHPSOCK__#${PHPSOCK}#" /etc/nginx/sites-available/monitor.conf sudo ln -s /etc/nginx/sites-available/monitor.conf /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx

파일 업로드 — SFTP/SCP(FileZilla, WinSCP) 또는 scp:

# 로컬 컴퓨터에서 scp를 이용한 예시: scp -r ./monitor/* deploy@203.0.113.10:/var/www/monitor/
파일 권한을 설정하세요 — 필수 단계입니다. root로 업로드했거나 SFTP로 올렸다면 파일 소유자가 root가 되어 웹 서버(www-data)가 읽을 수 없고, 패널이 빈 화면이나 403 오류로 열립니다(로그: .htaccess unreadable / directory not executable). 아래 명령이 이를 해결합니다:
# 웹 루트 전체의 권한을 정규화: root가 만든 디렉터리는 # 웹 서버(www-data)가 접근할 수 없음 — 없으면 패널이 빈 페이지나 403을 반환. # Apache는 www-data로 동작; 다른 웹 사용자를 쓴다면 교체하세요. cd /var/www/monitor # 작업 폴더는 chown 전에 생성 — 그렇지 않으면 새 디렉터리가 root:root로 남고 # chmod 750일 때 웹 서버(www-data)가 쓸 수 없습니다. sudo mkdir -p data/lynis data/logwatch tmp logs sudo chown -R www-data:www-data /var/www/monitor sudo find /var/www/monitor -type d -exec chmod 755 {} \; sudo find /var/www/monitor -type f -exec chmod 644 {} \; sudo chmod 640 /var/www/monitor/config.php sudo chmod 750 data tmp logs

3) SFTP 업로드 권한을 본인에게 열어 주세요. 위 명령 이후 모든 파일의 소유자는 www-data인데, FileZilla / WinSCP는 본인 계정으로 접속하므로 업로드가 SSH_FX_PERMISSION_DENIED(Permission denied)로 실패합니다. 업로드를 위해 root로 로그인할 수도 없습니다. root 로그인은 05단계에서 비활성화했습니다. 두 가지 방법 중 하나를 선택하세요.

방법 A — 본인 계정에만 ACL 부여(권장). 쓰기 권한은 본인만 갖고, 웹 서버는 여전히 패널 코드를 덮어쓸 수 없습니다:

sudo apt install -y acl # 패널 디렉터리 전체에 대한 본인 계정의 쓰기 권한: sudo setfacl -R -m u:deploy:rwX /var/www/monitor # 같은 규칙을 기본값으로 — 이후에 생성되는 파일과 폴더에 적용: sudo setfacl -R -d -m u:deploy:rwX /var/www/monitor

방법 B — www-data 그룹을 통해. 더 간단하지만 패널 파일에 대한 쓰기 권한을 웹 서버도 갖게 됩니다. PHP에 취약점이 생기면 코드가 교체될 수 있습니다. 명령 순서가 중요합니다 — config.php와 작업 폴더는 마지막에 잠급니다:

sudo usermod -aG www-data deploy # 그룹 쓰기 권한 + setgid(2 비트): SFTP로 올린 파일이 www-data 그룹에 # 남습니다 — 그렇지 않으면 패널이 파일을 덮어쓸 수 없습니다. sudo find /var/www/monitor -type d -exec chmod 2775 {} \; sudo find /var/www/monitor -type f -exec chmod 664 {} \; sudo chmod 640 /var/www/monitor/config.php sudo chmod 2750 /var/www/monitor/data /var/www/monitor/tmp /var/www/monitor/logs
방법 B 이후에는 FileZilla에서 다시 연결하세요(서버 → 연결 끊기, 그다음 다시 로그인). 새 그룹은 새로 로그인할 때만 적용되며, 그전까지는 여전히 권한이 없습니다. 확인: id deploy — 그룹 목록에 www-data가 나타나야 합니다. ls -ld /var/www/monitor — 권한 drwxrwsr-x이며, x 대신 s는 setgid가 설정되었다는 뜻입니다.

11. 데이터베이스

데이터베이스와 사용자를 생성한 뒤 스키마를 가져오세요. 블록은 전체를 터미널에 붙여 넣습니다. monitor_dbmonitor_user는 예시 이름이며, 원하는 이름을 지정해도 됩니다. 데이터베이스 이름, 사용자, 비밀번호는 기억해 두세요. 다음 단계에서 config.php에 입력합니다:

# 1. 데이터베이스. 비밀번호는 DBPASS에 한 번만 지정하면 모든 줄에 대입됩니다. # 블록은 터미널에 전체를 붙여 넣습니다. sudo mysql은 unix 소켓으로 root 접속 # (root 비밀번호 불필요). 대화형 `sudo mysql -u root -p`를 복사·붙여넣기로 # 사용하지 마세요 — 붙여 넣을 때 SQL 줄이 비밀번호 입력으로 들어가 사라집니다. DBPASS='CHOOSE_A_PASSWORD' # ← 이 줄만 변경하세요 sudo mysql <<SQL CREATE DATABASE IF NOT EXISTS monitor_db CHARACTER SET utf8mb4; CREATE USER IF NOT EXISTS 'monitor_user'@'localhost' IDENTIFIED BY '$DBPASS'; GRANT ALL ON monitor_db.* TO 'monitor_user'@'localhost'; FLUSH PRIVILEGES; SQL # 확인 (monitor_db가 표시되어야 함): mysql -u monitor_user -p"$DBPASS" -e "SHOW DATABASES;" # 이 비밀번호를 config.php → DB_PASS에 입력하세요.
스키마를 가져올 필요는 없습니다 — DB가 비어 있으면 브라우저로 처음 접속할 때 대시보드가 (database/db.sql에서) 테이블과 admin 계정을 자동으로 생성합니다. 자동 초기화가 작동하지 않은 경우에만 스키마를 수동으로 가져오면 됩니다.
브라우저 설치 도구 public/start_db.php를 사용했다면 설치 직후 삭제하세요: 이 파일은 인증 없이 데이터베이스를 다시 생성할 수 있게 합니다. 파일이 대시보드 루트나 public/에 남아 있는 동안 대시보드는 빨간색 경고를 표시합니다.

12. config.php 설정

패널 루트에 있는 config.php(/var/www/monitor/config.php)는 직접 수정해야 하는 유일한 파일입니다. 패널의 모든 설정은 이 파일에 define() 상수로 지정됩니다. 편집기로 여세요:

sudo nano /var/www/monitor/config.php

강조 표시된 부분에 본인 값을 넣고, 나머지는 그대로 두세요:

// --- 데이터베이스 (11단계 참고) --- define('DB_HOST', 'localhost'); // 그대로 유지 define('DB_NAME', 'db_name'); // 11단계에서 만든 값 define('DB_USER', 'user'); // 11단계에서 만든 값 define('DB_PASS', 'db_password'); // 11단계에서 지정한 값 define('DB_CHARSET', 'utf8mb4'); // 그대로 유지 // --- 애플리케이션 --- define('APP_URL', 'https://monitor.example.com'); // 패널 주소, 끝에 슬래시 없이 define('TIMEZONE', 'Asia/Seoul'); // 사용자 시간대 // --- 세션 시간 --- define('SESSION_LIFETIME', 28800); // 재로그인까지 유휴 시간, 초 (28800 = 8시간)

변경할 항목:

  • DB_NAME, DB_USER, DB_PASS — 11단계에서 DB를 만들 때 지정한 데이터베이스 이름, 사용자, 비밀번호와 정확히 동일하게(예시를 그대로 뒀다면 monitor_db / monitor_user). DB_HOSTDB_CHARSET는 건드리지 마세요.
  • APP_URLhttps://가 포함된 패널의 전체 주소로, 끝에 슬래시 없이, www도 없이. 라이선스를 활성화할 도메인(16단계)과 일치해야 하며, 그렇지 않으면 키가 거부됩니다.
  • TIMEZONE — 사용자 시간대(목록은 timedatectl list-timezones). 패널이 날짜를 표시하는 방식에만 영향을 주며, cron 작업 실행 시각에는 영향을 주지 않습니다(그쪽은 시스템 시간대를 따릅니다).
  • SESSION_LIFETIME — 몇 초 동안 활동이 없으면 패널이 재로그인을 요청할지(기본값 8시간). 예: 3600 = 1시간, 86400 = 하루.
  • 오류 로깅 블록(display_errors, log_errors, error_log)은 기본값 그대로 두세요.

파일을 저장하고(Ctrl+O, Enter, 이어서 Ctrl+X) PHP-FPM을 재시작하세요. 그렇지 않으면 OPcache 때문에 변경 사항이 적용되지 않습니다:

sudo systemctl restart php*-fpm
config.php는 비밀 파일입니다(DB 비밀번호가 들어 있음). 이 파일은 웹 루트이기도 한 패널 루트에 있지만 보호되어 있습니다: 권한 640(10단계에서 설정) 및 루트 .htaccess의 명시적 차단. 공개 저장소에 올리지 말고, 실제 비밀번호가 담긴 채로 지원팀에 전달하지 마세요.
모든 매개변수에 대한 자세한 설명은 FAQ 참고: "config.php 파일 — 패널의 모든 설정".

13. 웹 서버용 sudo 설정

PHP는 시스템 명령 권한이 없는 웹 서버 사용자 권한으로 실행됩니다. 권한은 좁게 부여합니다. 특정 유틸리티에 대한 제한적 sudo그룹을 통한 로그 읽기(sudo 없이)입니다. 웹 계층이 뚫려도 root 권한은 넘어가지 않습니다.

예제의 www-data는 표준 Apache 사용자입니다. 다른 사용자를 쓴다면(일부 패널은 PHP를 별도 사용자로 실행) 전부 교체하세요. 확인: ps -o user= -C php-fpm | sort -u.

1. sudo visudo -f /etc/sudoers.d/monitor/etc/sudoers.d/monitor를 만들고 다음을 붙여 넣으세요(사용하지 않는 모듈 줄은 삭제):

# UFW — 상태 및 규칙(“방화벽” 페이지) www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw status, /usr/sbin/ufw status verbose, /usr/sbin/ufw status numbered www-data ALL=(ALL) NOPASSWD: /usr/sbin/ufw allow [0-9]*, /usr/sbin/ufw deny [0-9]*, /usr/sbin/ufw --force delete [0-9]* # Fail2ban — 상태, 밴 및 언밴(banned는 모든 jail의 밴을 한 명령으로 반환; # ban/unban은 패널 버튼에 필요) www-data ALL=(ALL) NOPASSWD: /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status *, /usr/bin/fail2ban-client banned, /usr/bin/fail2ban-client set * banip *, /usr/bin/fail2ban-client set * unbanip * # 보안 업데이트(“업데이트” 카드). 읽기 전용이지만 반드시 root 권한이 필요: # apt 캐시(~70 MB)는 root만 접근 가능, 비-root는 호출마다 다시 빌드 # (CPU 4.2초 대 0.01초). wildcard 없음 — 딱 이 명령 하나뿐, 아무것도 설치하지 않음. www-data ALL=(ALL) NOPASSWD: /usr/bin/apt list --upgradable # IPset(공격 지도, 대시보드) www-data ALL=(ALL) NOPASSWD: /usr/sbin/ipset list -t ipsum # CrowdSec www-data ALL=(ALL) NOPASSWD: /usr/bin/cscli decisions list *, /usr/bin/cscli alerts list *, /usr/bin/cscli bouncers list *, /usr/bin/cscli scenarios list * # Auditd — 이벤트 검색 + 로그 마지막 줄 읽기(정확한 경로) www-data ALL=(ALL) NOPASSWD: /usr/sbin/ausearch -m * www-data ALL=(ALL) NOPASSWD: /usr/bin/tail -n 300 /var/log/audit/audit.log # Monit / ModSecurity / AppArmor / PSAD www-data ALL=(ALL) NOPASSWD: /usr/bin/monit status www-data ALL=(ALL) NOPASSWD: /usr/sbin/apache2ctl -M www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-modsec www-data ALL=(ALL) NOPASSWD: /usr/sbin/aa-status www-data ALL=(ALL) NOPASSWD: /usr/sbin/psad --Status # 열린 포트(커널/SSH/Falco 로그는 sudo 없이 systemd-journal 그룹으로 읽음, # 2번 참조; journalctl에 sudo를 주는 것은 불필요하고 안전하지 않음) www-data ALL=(ALL) NOPASSWD: /usr/bin/ss -tuln, /usr/sbin/ss -tuln, /bin/ss -tuln # PostgreSQL(사용하는 경우만) — 고정된 읽기 전용 스크립트, # “PostgreSQL이 표시되지 않음” FAQ대로 생성; 없으면 이 줄을 삭제 www-data ALL=(ALL) NOPASSWD: /usr/local/bin/monitor-pgstat
sudo chmod 440 /etc/sudoers.d/monitor sudo visudo -c # "parsed OK"가 나와야 함

2. 로그 및 systemd 저널 접근. 모듈은 /var/log/fail2ban.log, auth.log, ufw.log, apache2/*, aide를 직접 읽습니다(Debian/Ubuntu에서 이 로그들은 adm 그룹에 속함). 커널, SSH, Falco 이벤트는 systemd-journal 그룹을 통해 journalctl 명령으로 sudo 없이 가져옵니다. 웹 사용자를 그룹 모두에 추가하고 PHP-FPM을 재시작하세요:

sudo usermod -aG adm,systemd-journal www-data sudo systemctl restart php*-fpm # 필수, 그렇지 않으면 그룹이 적용되지 않음

3. ClamAV나 Suricata가 로그를 adm 그룹이 아닌 곳에 기록하면(root:root인 경우도 있음) ACL로 접근 권한을 부여하세요:

sudo apt install acl sudo setfacl -R -m u:www-data:rX /var/log/clamav /var/log/suricata 2>/dev/null sudo setfacl -d -m u:www-data:rX /var/log/clamav /var/log/suricata 2>/dev/null

4. ModSecurity 래퍼. WAF 감사 로그(/var/log/apache2/modsec_audit.log)는 권한 640의 root 소유라 웹 사용자가 직접 읽을 수 없습니다. ModSecurity 페이지는 엔진 모드, 이벤트, 활성 규칙 목록을 고정된 읽기 전용 스크립트로 가져오며, 이 스크립트는 위 sudoers 줄에서 허용됩니다:

sudo tee /usr/local/bin/monitor-modsec >/dev/null <<'EOF' #!/bin/sh echo "ENGINE=$(grep -hE '^SecRuleEngine[[:space:]]+' /etc/modsecurity/*.conf 2>/dev/null | tail -1 | awk '{print $2}')" echo "---LOG---" tail -n 3000 /var/log/apache2/modsec_audit.log 2>/dev/null echo "---RULES---" for f in /etc/modsecurity/crs/rules/*.conf /usr/share/modsecurity-crs/rules/*.conf /etc/modsecurity/custom-rules.conf; do [ -f "$f" ] && { echo "===FILE:$(basename "$f")==="; cat "$f"; } done EOF sudo chown root:root /usr/local/bin/monitor-modsec sudo chmod 755 /usr/local/bin/monitor-modsec
/etc/modsecurity/modsecurity.conf 파일이 없으면 WAF 자체가 동작하지 않습니다. 패키지는 modsecurity.conf-recommended만 설치하고 규칙 엔진은 꺼진 상태로 남습니다. 활성화 방법은 FAQ → “ModSecurity 설치”를 참조하세요.
모든 sudoers 줄의 사용자는 FPM 풀 사용자와 일치해야 합니다. 일반 Apache/Debian에서는 www-data이고, HestiaCP에서는 사이트 풀이 사이트 소유자(예: admin) 권한으로 실행되니 grep -E '^user' /etc/php/*/fpm/pool.d/monitor.example.com.conf로 확인하세요.

5. Apache 앞에 Nginx가 있는 경우(HestiaCP, ISPmanager 등 여러 패널 — Nginx가 PHP를 Apache로 프록시하고 정적 파일은 직접 제공). 서비스 디렉터리는 .htaccess 파일로 막혀 있지만 Nginx는 이를 읽지 않습니다. 정적 파일(.json, .txt, .log, .dat)은 Apache를 우회해 직접 제공합니다. 패널 캐시와 데이터가 외부로 유출될 수 있습니다. 예를 들어 WAF 이벤트와 공격자 IP가 담긴 tmp/modsec_cache.json이 그렇습니다. Nginx 사이트 설정에 차단 규칙을 추가하세요:

location ^~ /data/ { deny all; } location ^~ /tmp/ { deny all; } location ^~ /logs/ { deny all; } location ^~ /includes/ { deny all; } location ^~ /cron/ { deny all; } location ^~ /database/ { deny all; } location = /config.php { deny all; }
^~ 접두사는 필수입니다. location / 내부의 정적 파일 정규식 규칙보다 먼저 선택되며, 없으면 차단이 동작하지 않습니다.
HestiaCP에서는 이를 별도 파일 /home/<user>/conf/web/<domain>/nginx.ssl.conf_deny(그리고 HTTP용 nginx.conf_deny)로 두세요. 사이트 설정이 nginx.ssl.conf_*를 포함하며 재빌드 시에도 이런 파일은 덮어쓰지 않습니다. 적용: sudo nginx -t && sudo systemctl reload nginx.
확인: curl -s -o /dev/null -w '%{http_code}\n' https://monitor.example.com/tmp/modsec_cache.json403이 나와야 합니다. Apache가 Nginx 없이 동작한다면(80/443을 직접 수신) 아무것도 추가할 필요 없이 .htaccess로 충분합니다.
바이너리 경로는 which로 확인하세요(예: which ufw cscli ausearch ss). sudoers는 반드시 visudo로만 편집하세요. 모든 MySQL 데이터베이스 목록은 별도 GRANT로 활성화됩니다(FAQ → “데이터베이스가 하나만 보임”).

14. IP 기반 접근 제한

모니터 접근을 IP 주소로 제한하세요. URL이 노출되더라도 로그인 페이지가 열리지 않습니다. 웹 서버 수준(아래 nginx 예시)이나 패널 자체(“설정” → “IP 기반 접근 제한”)에서 설정할 수 있습니다. Apache를 사용한다면 패널에서 제한하세요.

10단계에 따라 nginx 사이트를 이미 설정했다면 두 번째를 추가하지 말고 location / 기존 블록에 allow/deny 줄을 추가하세요. 하나의 server { } 안에 동일한 location /가 둘이면 설정 오류이며 nginx가 재시작되지 않습니다.
# nginx 설정에서 (server { } 안에): # Let's Encrypt ACME 경로는 IP 제한을 우회해 열어 둡니다 — # SSL 발급 및 자동 갱신(15단계)이 IP 필터에 영향받지 않도록. location ^~ /.well-known/acme-challenge/ { allow all; } location / { allow 203.0.113.10; # ← 본인 IP 입력 allow 10.0.0.0/8; # 로컬 네트워크 (필요 시) deny all; try_files $uri $uri/ /index.php?$query_string; } # nginx 재시작: sudo nginx -t && sudo systemctl reload nginx

15. SSL(HTTPS) 발급

대시보드는 HTTPS로만 동작합니다. 로그인 세션은 보안 쿠키를 사용하며 WebAuthn(2FA)은 HTTPS에서만 작동합니다. http://로는 로그인할 수 없습니다.

인증서는 무료입니다(Let's Encrypt). 도메인 DNS가 이미 서버를 가리키고 있어야 합니다. 명령은 웹 서버에 따라 다릅니다:

# Apache: sudo certbot --apache -d monitor.example.com # nginx — nginx를 사용하는 경우에만. Apache에서는 실행하지 마세요: # apt가 nginx를 끌어와 80번 포트를 점유하여 Apache와 충돌합니다. # sudo apt install python3-certbot-nginx # sudo certbot --nginx -d monitor.example.com # certbot이 알아서 HTTPS를 설정에 기록하고 자동 갱신을 구성합니다
certbot이 묻는 것: e-mail → 약관 동의(Y) → EFF에 e-mail 전달(선택 사항). 이후 인증서를 발급하고 <VirtualHost *:443>을 기록하며 http→https 리디렉션과 자동 갱신을 구성합니다.
certbot 실행 전에 DNS가 서버를 가리켜야 합니다(80번 포트로 소유권 확인). 확인: dig +short monitor.example.com → 서버 IP. 80/443 포트 개방: sudo ufw allow 80,443/tcp.

발급 후: https://monitor.example.com가 자물쇠와 함께 열리고, http://https://로 리디렉션됩니다(config.phpAPP_URL은 12단계에서 이미 설정됨).

16. 로그인 및 초기 설정

https://monitor.example.com을 열고 admin / useradmin으로 로그인한 뒤 체크리스트를 진행하세요:

  1. admin 비밀번호 변경 — 메뉴의 “사용자” 섹션.
  2. WebAuthn(2FA) 활성화 — “WebAuthn 키” → 키/passkey 등록(HTTPS 필요). 두 개를 함께 등록하세요. 유일한 키를 분실하면 해당 키로 로그인할 수 없습니다. 자세히 보기.
  3. IP 접근 제한 — “설정” → “IP 접근 제한”(활성화 전에 본인 IP를 입력하세요, 그렇지 않으면 접근이 차단됩니다).
  4. 라이선스 입력 — 개인 계정의 ARCIVEO-… 코드를 본인 도메인에 활성화하고 키를 “설정” → “라이선스”에 입력하세요. 자세히 보기.
  5. 알림 설정 — “설정”에서 Telegram 및/또는 Email. 자세히 보기.
  6. 설치 프로그램 삭제 public/start_db.php가 남아 있으면 삭제하세요(11단계).

17. 보안 도구 (선택 사항)

대시보드는 이미 작동 중입니다. 도구는 필요에 따라 설치하면 됩니다 — 필요한 것만 설치하면 대시보드가 곧바로 상태를 표시합니다. 각 도구의 설치 명령은 안내서에 있습니다(도구별 개별 섹션):

18. Cron 및 유지 관리

한 번만 설정하면 되며, 이 또한 선택 사항이지만 권장합니다. 자세한 명령어는 설명서를 참고하세요:

  1. Cron 작업 (보고서, 목록 업데이트, 점검);
  2. 백업;
  3. 패널 업데이트 및 이전;
  4. 접근 복구 — 보안 키/비밀번호 분실 시.
무언가 작동하지 않거나 "데이터 없음"이 표시되나요? 설명서의 "진단" 그룹을 확인하세요.
Arcivéo - Security Monitor © 2026