VPS 첫 세팅

새로 받은 리눅스 서버에서 계정과 SSH 키, 방화벽, 자동 보안 업데이트, 시간대, 스왑, 리버스 프록시와 TLS, 로그 로테이션, 기본 모니터링까지 순서대로 잡는 체크리스트입니다.

작성

새로 만든 VPS에서 가장 먼저 할 일은 접속 경로를 안전하게 만드는 것입니다. 일반 계정을 만들고, SSH 키 인증으로 바꾸고, 비밀번호 로그인을 끄고, 방화벽을 켜는 네 가지가 첫 30분에 끝나야 할 작업입니다. 그다음에 업데이트, 시간대, 스왑, 리버스 프록시와 TLS, 로그와 모니터링을 차례로 잡습니다.

아래 명령은 Ubuntu와 Debian 계열 기준입니다. 다른 배포판이면 패키지 이름과 방화벽 도구만 바꾸면 됩니다. 레토에서 가상 서버를 쓴다면 클라우드 인스턴스 상품입니다. 현재 제공 중인 두 플랜은 EPYC 7352 프로세서 기반이고, 플랜별 사양은 상품 페이지에 정리되어 있습니다. 콘솔에서는 VNC 접속과 스냅샷, 이미지 복제를 쓸 수 있으니 아래 작업을 시작하기 전에 위치를 한 번 확인해 두세요. 서버를 직접 관리하지 않고 제어판으로 운영하고 싶다면 Plesk 기반인 웹호스팅 첫 세팅을 보세요.

계정과 SSH

  1. 일반 계정을 만들고 sudo 권한을 줍니다

    adduser deploy
    usermod -aG sudo deploy
    
  2. 로컬에서 키를 만들고 서버에 올립니다

    키는 서버가 아니라 내 컴퓨터에서 만듭니다. 개인키는 서버에 올리지 않습니다.

    ssh-keygen -t ed25519 -C "deploy@example.com"
    ssh-copy-id deploy@203.0.113.10
    
  3. 키로 접속되는지 먼저 확인합니다

    기존 창을 닫지 말고 새 터미널에서 ssh deploy@203.0.113.10 이 비밀번호 없이 붙는지 확인합니다. 여기서 실패하면 다음 단계로 넘어가지 않습니다.

  4. 비밀번호 로그인과 root 로그인을 끕니다

    /etc/ssh/sshd_config 또는 /etc/ssh/sshd_config.d/ 아래 파일에 다음을 넣습니다.

    PermitRootLogin no
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    PubkeyAuthentication yes
    

    문법을 검사한 뒤 다시 읽힙니다. 재시작이 아니라 reload를 쓰면 현재 세션이 끊기지 않습니다.

    sudo sshd -t && sudo systemctl reload ssh
    
  5. 접속 실패를 반복하는 IP를 차단합니다

    sudo apt install -y fail2ban
    sudo systemctl enable --now fail2ban
    

    SSH 포트를 22에서 옮기는 것은 보안 효과보다 자동 스캔 로그를 줄이는 효과가 큽니다. 옮긴다면 방화벽 규칙을 먼저 열고 바꾸세요.

방화벽과 업데이트

기본 정책은 들어오는 것은 모두 막고, 필요한 포트만 여는 것입니다.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

데이터베이스나 캐시 서버 포트는 절대 전체 공개하지 않습니다. 같은 서버 안이면 localhost 로만 듣게 하고, 다른 서버에서 붙어야 하면 특정 IP만 허용합니다.

sudo ufw allow from 203.0.113.20 to any port 5432 proto tcp

업데이트는 처음 한 번 전체를 올린 뒤 보안 업데이트를 자동으로 받게 둡니다.

sudo apt update && sudo apt full-upgrade -y
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

커널 업데이트는 재부팅이 있어야 적용됩니다. 자동 재부팅 시간을 정하거나, 정기 점검 시간에 직접 재부팅하는 규칙을 정해 두세요.

시간대, 시각 동기화, 스왑

로그 시각이 어긋나면 장애 분석이 어려워집니다. 서버 시간대와 NTP 동기화는 첫날에 맞춰 둡니다.

sudo timedatectl set-timezone Asia/Seoul
timedatectl status

System clock synchronized: yes 와 NTP service: active 가 보이면 됩니다. 컨테이너와 로그 수집기를 함께 쓴다면 서버 시간대는 UTC로 두고 표시 단계에서만 변환하는 방식도 흔합니다. 어느 쪽이든 팀 안에서 하나로 통일하세요.

메모리가 작은 서버라면 스왑을 만들어 둡니다.

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

디스크 쓰기를 줄이려면 vm.swappiness 를 10 정도로 낮춰 /etc/sysctl.d/ 에 넣어 둡니다.

리버스 프록시와 TLS

애플리케이션을 80, 443 포트에 직접 붙이지 말고 앞단에 웹서버를 둡니다. 인증서 처리, 정적 파일 서빙, 요청 로그, 무중단 재배포가 모두 쉬워집니다.

sudo apt install -y nginx
sudo apt install -y certbot python3-certbot-nginx

DNS에서 도메인의 A 레코드가 이 서버 IP를 가리키고 있어야 인증서 발급이 됩니다. 레코드 설정은 DNS 레코드 종류와 입력 방법을 참고하세요. 전환 예정이라면 TTL을 미리 낮춰 두면 편합니다.

sudo certbot --nginx -d example.com -d www.example.com
sudo systemctl list-timers | grep certbot

프록시 블록은 다음과 같은 형태입니다. 애플리케이션은 로컬 포트에서만 듣게 합니다.

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

갱신 타이머가 실제로 도는지 한 번은 확인하고, 인증서 만료 알림을 캘린더에 걸어 두세요. 인증서 종류와 선택 기준은 SSL 인증서에 정리되어 있습니다. 이 서버에서 메일을 보낼 계획이라면 발송 도메인 인증과 도달률에 필요한 설정을 먼저 확인하세요. 항목은 메일 도달률 높이기에 정리되어 있습니다.

로그와 모니터링

디스크가 로그로 가득 차서 서비스가 멈추는 사고는 흔합니다. 애플리케이션 로그에는 반드시 로테이션을 겁니다. /etc/logrotate.d/myapp 예시입니다.

/var/log/myapp/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 deploy adm
    sharedscripts
}

systemd 저널도 무한정 쌓이지 않게 상한을 둡니다.

sudo journalctl --disk-usage
sudo journalctl --vacuum-size=500M

모니터링은 처음부터 크게 만들 필요가 없습니다. 아래 네 가지만 있어도 대부분의 장애를 미리 잡습니다.

  • 외부에서 보는 상태 점검 (도메인 기준 HTTP 응답과 인증서 만료일)
  • 디스크 사용률 임계치 알림 (80%에서 경고)
  • 메모리와 CPU 추세, 프로세스 재시작 횟수
  • 알림을 받을 사람과 채널을 정해 두기 (알림이 아무에게도 안 가면 없는 것과 같습니다)

수집 도구는 node_exporter와 Prometheus 조합이 흔하고, 소규모라면 외부 상태 점검 서비스 하나로도 충분합니다. 중요한 것은 도구가 아니라 알림이 사람에게 도달하는지입니다.

인수인계 전 점검

  • 새 터미널에서 키로 접속되고, 비밀번호 로그인은 거부되는가
  • ufw status에 열려 있어야 할 포트만 보이는가
  • 재부팅 후 서비스가 자동으로 올라오는가 (systemctl enable 확인)
  • 백업 대상과 주기가 정해져 있고, 복원을 한 번 해 봤는가
  • 접속 키를 가진 사람 목록과 퇴사 시 회수 절차가 있는가
  • 서버 정보(IP, 용도, 담당자, 결제 주체)가 사내 문서에 기록되어 있는가

마지막 두 항목은 사람이 바뀔 때 서버가 방치되는 것을 막는 장치입니다. 도메인과 함께 관리 대장을 만드는 방법은 법인 도메인 관리 체크리스트에 정리되어 있습니다.

자주 묻는 질문

권장하지 않습니다. root는 실수 한 번으로 시스템 전체를 지울 수 있고, 누가 무엇을 했는지 로그로 구분되지 않습니다. 일반 계정을 만들어 sudo로 필요한 순간에만 권한을 올리는 편이 안전합니다.

그래서 키를 끄기 전에 새 세션으로 접속이 되는지 반드시 확인합니다. 기존 SSH 세션을 열어 둔 채로 새 터미널에서 접속을 검증하면 설정이 잘못돼도 되돌릴 수 있습니다. 레토 클라우드 인스턴스는 콘솔에서 VNC로 접속할 수 있으므로, SSH가 아예 막혀도 화면에 직접 붙어 설정을 되돌릴 수 있습니다.

메모리가 작은 서버라면 메모리와 같은 크기에서 두 배 사이가 무난합니다. 스왑은 성능을 위한 것이 아니라 순간적인 메모리 부족으로 프로세스가 강제 종료되는 것을 막기 위한 안전장치입니다. SSD 수명이 걱정되면 swappiness 값을 낮춰 두면 됩니다.

서로 다른 일을 합니다. 방화벽은 열어 둘 포트를 정하고, fail2ban은 열어 둔 포트에 반복 실패하는 IP를 일정 시간 차단합니다. SSH를 키 인증만 허용해도 로그가 시도 기록으로 가득 차는 것을 줄이는 효과가 있습니다.

레토 웹호스팅은 Plesk 기반이므로 제어판에서 도메인, 파일, 데이터베이스, 메일 계정, 인증서를 다룹니다. 루트 권한으로 패키지를 올리거나 프로세스와 포트를 직접 관리할 필요가 없다면 그쪽이 손이 덜 갑니다. 반대로 임의의 소프트웨어를 설치하고 방화벽 규칙을 직접 정해야 한다면 이 문서의 가상 서버 구성이 맞습니다.

관련 가이드

용어