Rocky Linux 초기 서버 세팅 체크리스트: 보안·안정성·자동화까지 한 번에 끝내는 실전 가이드

Rocky Linux 9/10 초기 서버 세팅 7단계 체크리스트. 업데이트·sudo 사용자·SSH 키 인증·firewalld·SELinux·dnf-automatic·시간 동기화까지 실무 검증 순서로 정리했습니다.
요약 스니펫
Rocky Linux 초기 서버 세팅은 ① 전체 패키지 업데이트 → ② sudo 일반 사용자 생성 → ③ SSH 키 등록 및 루트·비밀번호 로그인 차단 → ④ firewalld로 필요한 포트만 개방 → ⑤ SELinux는 Enforcing 유지 → ⑥ dnf-automatic으로 보안 패치 자동화 → ⑦ chronyd 시간 동기화, 이 7단계 순서로 진행하는 것이 핵심입니다. 평균 30~40분이 소요되며, 이후 운영 중 사고율을 크게 낮춥니다.

새 VPS에 Rocky Linux 9를 설치하고 처음 루트로 접속한 순간, 무엇부터 건드려야 할지 막막했던 경험이 한 번쯤은 있으실 겁니다. 저도 초기에는 그냥 웹 서버부터 띄우고 나중에 보안을 손보자고 미뤘다가, 한 주 만에 /var/log/secure에 수만 건의 SSH 브루트포스 기록이 쌓여 있는 걸 보고 식겁한 적이 있습니다. 그 경험 이후로는 서버를 받자마자 동일한 체크리스트를 따라 30분간 "초기 세팅"을 끝낸 뒤에야 다른 작업을 시작합니다.

이 글은 Rocky Linux 9(및 10 적용 가능) 기준으로, 실제 운영 서버에서 검증된 초기 세팅 순서를 정리한 것입니다. CentOS 계열을 써온 분이라면 거의 동일하게 적용되며, 각 단계가 "왜 필요한지"와 "하지 말아야 할 것"까지 함께 짚겠습니다.

Rocky Linux 초기 서버 세팅을 위해 터미널에서 작업 중인 관리자의 모습
초기 세팅의 첫 관문, 터미널 접속

왜 초기 세팅 체크리스트가 필요한가

Rocky Linux는 기본값이 비교적 안전한 편이지만, 그래도 "기본값 그대로"는 운영 환경에 부적합합니다. 특히 클라우드 VPS는 공인 IP를 부여받는 순간부터 자동화된 스캐너에 노출됩니다. Shodan이나 Censys 같은 엔진이 IPv4 전체를 수 시간 안에 훑고 지나가고, 생성 직후 평균 5~10분 이내에 SSH 22번 포트로 첫 로그인 시도가 들어옵니다. 체크리스트는 이 공격 표면을 최소화하기 위한 최소 방어선입니다.

또한 체크리스트는 "재현 가능성"을 보장합니다. 서버를 10대 운영하든 100대 운영하든 동일한 순서로 세팅해 두면, 장애 대응 시 "이 서버만 왜 다르지?" 하는 변수를 줄일 수 있습니다. 가능하다면 이 체크리스트를 Ansible 플레이북이나 cloud-init 스크립트로 코드화해 두는 것이 이상적입니다.

첫 로그인과 시스템 업데이트

서버를 받으면 가장 먼저 전체 패키지를 업데이트합니다. 많은 가이드가 "로그인 → 사용자 생성"부터 시작하지만, 저는 업데이트를 가장 먼저 하는 편을 권장합니다. 이유는 단순합니다. 이미지 스냅샷이 만들어진 시점과 현재 시점 사이에 공개된 CVE가 있을 수 있고, 그 취약점이 바로 지금 스캔당하고 있을 가능성이 있기 때문입니다.

# 전체 패키지 업데이트 및 재부팅
dnf -y update
dnf -y install epel-release
dnf -y install vim wget curl git tar bash-completion

# 커널이 업데이트되었다면 재부팅
needs-restarting -r || reboot

needs-restarting -r 명령은 dnf-utils 패키지에 포함되어 있으며, 커널이나 주요 라이브러리가 업데이트돼 재부팅이 필요한지 알려줍니다. "0 (재부팅 불필요)" 또는 "1 (재부팅 필요)"로 결과를 반환하므로 스크립트에서도 활용하기 좋습니다.

sudo 권한을 가진 일반 사용자 생성

루트 계정으로 직접 서비스를 운영하는 것은 사고 시 복구가 사실상 불가능한 수준의 피해를 부릅니다. Rocky Linux에서는 wheel 그룹에 속한 사용자가 sudo를 쓸 수 있도록 기본 설정돼 있으므로, 여기에 추가해주기만 하면 됩니다.

# 사용자 생성 후 wheel 그룹에 추가
adduser deploy
passwd deploy
usermod -aG wheel deploy

# 확인
id deploy
# uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),10(wheel)

추가 후에는 반드시 새 터미널 창에서 해당 사용자로 로그인 가능한지 먼저 확인한 뒤 다음 단계(루트 로그인 차단)로 넘어가야 합니다. 순서를 어기면 자기 자신을 서버에서 내쫓는 상황이 벌어질 수 있습니다. 저도 딱 한 번, 검증 없이 루트 SSH를 먼저 잠갔다가 VPS 업체 콘솔로 겨우 복구한 적이 있었는데, 그 30분이 굉장히 길게 느껴졌습니다.

항목 권장 값 이유
계정 이름admin, deploy 등 용도별예측 불가능한 이름으로 스캐너 표적 감소
비밀번호16자 이상, 영숫자+기호sudo 승격 시 재확인용
그룹wheelRocky Linux 기본 sudo 그룹
홈 디렉터리 권한700다른 사용자 접근 차단

Rocky Linux SSH 키 인증을 위해 준비된 보안 키와 노트북
SSH 키 인증은 비밀번호보다 안전합니다

SSH 키 인증과 루트 로그인 차단

SSH는 기본적으로 암호화된 프로토콜이지만, 비밀번호 인증을 허용하면 브루트포스에 취약합니다. 공개키 인증으로 전환하는 것이 가장 확실한 방어책입니다. 로컬에서 키를 만들어 서버로 복사하는 순서는 다음과 같습니다.

# 로컬(개인 PC)에서 키 생성 (ed25519 권장)
ssh-keygen -t ed25519 -C "deploy@myserver"

# 서버로 공개키 복사
ssh-copy-id deploy@서버IP

# 서버에서 sshd_config 편집
sudo vi /etc/ssh/sshd_config.d/99-hardening.conf

Rocky Linux 9부터는 /etc/ssh/sshd_config.d/ 디렉터리의 드롭인(drop-in) 파일을 읽도록 돼 있으므로, 원본 sshd_config를 직접 수정하기보다 별도의 하드닝 파일을 만드는 것이 업그레이드 시 안전합니다.

# /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
MaxAuthTries 3
LoginGraceTime 30
AllowUsers deploy
# Port 22022   # 필요 시 포트 변경 (방화벽·SELinux 동시 허용 필요)
# 설정 검증 후 재시작
sudo sshd -t && sudo systemctl restart sshd
⚠️ 주의
sshd -t로 문법 검증을 통과한 뒤에도 현재 세션을 끊지 말고 새 터미널로 접속 테스트를 해야 합니다. 새 세션에서 로그인이 성공해야 비로소 설정이 올바른 것입니다. 포트를 변경했다면 firewalld와 SELinux(semanage port -a -t ssh_port_t -p tcp 22022)도 함께 업데이트해야 합니다.

SSH 포트를 22에서 다른 번호로 바꾸는 것에 대해서는 의견이 갈립니다. "보안은 모호함에 의존하면 안 된다"는 반론이 일리 있지만, 실무에서는 22번 포트의 스캔 트래픽만 제거해도 journalctl -u sshd 로그의 노이즈가 90% 이상 줄어들어 실제 침입 시도를 발견하기가 훨씬 쉬워집니다. 기능적 보안보다는 운영 편의 측면의 이득으로 생각하면 됩니다.

firewalld 방화벽 구성

Rocky Linux의 기본 방화벽은 firewalld입니다. iptables 직접 조작에 비해 "zone" 개념과 서비스 기반 규칙이 있어 유지보수가 쉽습니다. 웹 서버를 예로 들면 다음과 같이 구성합니다.

# firewalld 상태 확인 및 활성화
sudo systemctl enable --now firewalld
sudo firewall-cmd --state

# 현재 활성 zone 확인
sudo firewall-cmd --get-active-zones

# HTTP/HTTPS 허용, SSH는 기본 포함됨
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# 변경 적용
sudo firewall-cmd --reload

# 규칙 확인
sudo firewall-cmd --list-all

--permanent 플래그를 빠뜨리면 재부팅 시 규칙이 사라집니다. 반대로 영구 저장 없이 일회성 테스트만 하고 싶다면 --permanent를 빼고 --reload도 생략하면 됩니다. 특정 IP만 SSH를 허용하고 싶다면 rich rule을 씁니다.

# 회사 IP(예: 203.0.113.5)에서만 SSH 허용, 나머지는 차단
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4" source address="203.0.113.5/32"
  service name="ssh" accept'
sudo firewall-cmd --reload

Rocky Linux 방화벽과 SELinux 다층 보안을 상징하는 네트워크 보안 이미지
firewalld와 SELinux는 서로 다른 계층을 보호합니다

SELinux 유지와 잘못된 비활성화 관행

많은 초보 가이드가 "SELinux는 귀찮으니 꺼버리세요"라고 안내하는데, 이건 Rocky Linux를 쓸 이유의 절반을 버리는 선택입니다. SELinux는 방화벽이 막지 못하는 "프로세스 간 권한 경계"를 지켜주는 계층으로, 예를 들어 웹서버가 해킹당해도 /etc/shadow를 읽지 못하도록 타입 강제(Type Enforcement)로 막아줍니다.

# 현재 모드 확인
getenforce
# 기대값: Enforcing

# 영구 설정 확인 (SELINUX=enforcing 유지)
cat /etc/selinux/config | grep ^SELINUX=

# 문제 발생 시 "끄기" 대신 "로그 분석"이 먼저
sudo dnf install -y setroubleshoot-server
sudo ausearch -m AVC -ts recent
sudo sealert -a /var/log/audit/audit.log

오해 하나 짚고 넘어가면, SELinux가 "애플리케이션을 동작하지 못하게 막는다"는 인식은 대부분 설정 오류에서 비롯됩니다. 비표준 경로에 웹 루트를 만들면 httpd_sys_content_t 컨텍스트가 없어서 접근이 거부될 뿐, semanage fcontextrestorecon으로 컨텍스트만 맞춰주면 정상 동작합니다. 끄는 대신 배우는 쪽이 장기적으로 훨씬 이득입니다.

💡 팁 — 비표준 경로 웹 루트 허용 예시
sudo semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?"
sudo restorecon -Rv /data/www
이렇게 두 줄이면 SELinux를 유지한 채 /data/www를 웹 루트로 쓸 수 있습니다.

dnf-automatic으로 보안 패치 자동화

서버를 만들어두고 몇 달 뒤 로그인해 보면, 그사이 공개된 CVE가 누적된 채로 방치돼 있는 경우가 흔합니다. Rocky Linux 공식 문서도 dnf-automatic 활성화를 권장합니다. 전체 자동 업데이트는 재시작이 필요한 패키지가 설치될 때 부작용이 있을 수 있으므로, 보안 패치만 자동 적용하고 나머지는 알림만 받는 구성이 균형점입니다.

sudo dnf install -y dnf-automatic

# 설정 파일 편집
sudo vi /etc/dnf/automatic.conf
# /etc/dnf/automatic.conf 주요 항목
[commands]
upgrade_type = security       # 보안 패치만
apply_updates = yes           # 자동 적용

[emitters]
emit_via = email,stdio

[email]
email_from = root@example.com
email_to = admin@example.com
email_host = localhost
# 타이머 활성화
sudo systemctl enable --now dnf-automatic.timer
systemctl list-timers | grep dnf-automatic

참고로 Rocky Linux 포럼에는 "dnf-automatic이 보안 업데이트가 없다고 보고하지만 일반 업데이트는 123개가 쌓여 있다"는 문의가 종종 올라옵니다. 이는 정상 동작이며, upgrade_type = security로 설정했을 때 보안으로 분류된 advisory만 처리하기 때문입니다. 일반 업데이트는 별도 유지보수 창(main maintenance window)에 수동으로 돌리는 것이 안전합니다.

시간 동기화와 로그 관리

마지막으로, 자주 간과되지만 장애 분석 시 가장 먼저 문제가 되는 두 가지가 시간과 로그입니다. 서버 간 시각이 수 초만 어긋나도 분산 시스템의 인증 토큰이 만료 처리되거나, 로그 타임스탬프가 맞지 않아 사건 순서를 복원하지 못합니다.

# chrony는 Rocky Linux 기본 NTP 클라이언트
sudo systemctl enable --now chronyd
chronyc sources -v
chronyc tracking

# 타임존을 KST로
sudo timedatectl set-timezone Asia/Seoul
timedatectl

로그 관리 측면에서는 journald의 영속 저장을 권장합니다. 기본값은 메모리 저장이라 재부팅 시 과거 로그가 사라집니다.

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

# 저장 용량 확인
journalctl --disk-usage

서버 보안 패치 자동화 일정과 업데이트 알림 개념 이미지
자동 패치 스케줄링으로 유지보수 부담 감소

자주 묻는 질문

Q1. Rocky Linux 9와 10 중 어느 쪽을 깔아야 하나요?

2026년 5월 기준 Rocky Linux 10이 안정 버전으로 출시되어 있지만, 상용 소프트웨어 호환성과 장기 안정성이 검증된 건 아직 9입니다. 프로덕션 신규 구축이라면 Rocky Linux 9를, 개인 학습/테스트 환경이라면 10을 권장합니다.

Q2. SSH 포트를 꼭 22에서 바꿔야 하나요?

보안 강화 효과보다는 로그 노이즈 감소 효과가 큽니다. 필수는 아니지만, 바꿀 경우 firewalld와 SELinux(semanage port) 설정을 함께 업데이트해야 접속 가능합니다.

Q3. SELinux가 너무 복잡한데 그냥 Permissive 모드로 두면 안 되나요?

Permissive는 "차단은 하지 않지만 로그는 남기는" 모드로, 운영 시작 단계에서 문제 파악용으로는 유용합니다. 하지만 운영 환경에서는 반드시 Enforcing으로 복귀해야 합니다. Permissive로 수 개월 방치하면 사실상 비활성화와 같습니다.

Q4. fail2ban도 설치해야 하나요?

SSH 키 인증만 허용하고 비밀번호 로그인을 차단했다면 fail2ban의 효용은 크게 떨어집니다. 다만 웹 서버의 로그인 페이지나 SMTP 등 애플리케이션 계층 공격이 우려된다면 도입할 만합니다. EPEL 저장소에서 dnf install fail2ban으로 설치 가능합니다.

Q5. 이 체크리스트를 Ansible로 자동화하려면?

ansible.builtin.user, ansible.posix.authorized_key, ansible.posix.firewalld, community.general.selinux 모듈을 조합하면 위 단계 대부분을 idempotent하게 구성할 수 있습니다. DevSec Hardening Framework(devsec.hardening) 역할을 참조하면 좋은 출발점이 됩니다.

본 글은 일반적인 시스템 관리 참고용이며, 모든 환경에서 동일하게 동작함을 보장하지 않습니다. 운영 서버에 적용하기 전 반드시 테스트 환경에서 검증하시기 바랍니다. 보안 구성은 조직의 정책과 컴플라이언스 요구사항에 따라 조정이 필요할 수 있습니다.

체크리스트는 외워서 치는 주문이 아니라, 매번 "왜 이걸 하는가"를 되짚는 의식에 가깝습니다. 위 순서대로 30~40분을 투자하면, 이후 몇 달간의 운영 스트레스가 확연히 줄어듭니다. 자신만의 스타일로 다듬어가며 Ansible 플레이북으로 코드화해두면, 서버를 찍어내듯 안전하게 늘려갈 수 있습니다. 이제 남은 일은, 이 글을 닫고 실제 서버에 접속해 첫 dnf update를 돌리는 것뿐입니다.