infra
Platform

모듈 맵

[Infra Ops] 리눅스 서버 초기 구축 세팅 및 보안 하드닝 체크리스트

0 / 52 완료

펼치기
0 / 52 완료0%

Infra-ops · 02 / 52

[Infra Ops] 리눅스 서버 초기 구축 세팅 및 보안 하드닝 체크리스트

새 Linux 서버를 받았을 때 처음 해야 하는 hostname, timezone, 서비스 계정, SSH 보안, 방화벽 초기 설정을 수행합니다

🚨INCIDENT ALERT
HIGH

새 서버가 IDC에서 납품됐습니다. OS만 깔린 상태로 IP 정보와 root 비밀번호 한 장만 들고 왔습니다. "3일 후 스테이징에 올려야 해요." 처음 접속부터 서비스 계정 생성, 방화벽 초기 설정, SSH 보안 설정까지 — 서버 운영의 모든 것은 이 초기 작업에서 시작됩니다.

여기서 설정이 잘못되면 나중에 찾기도 어렵고 고치기도 어렵습니다.

이번 챕터에서 배울 것
  • 1hostname, timezone, locale을 서비스 운영 표준에 맞게 설정할 수 있다
  • 2Java, wget, curl, unzip 등 필수 패키지를 설치하고 버전을 확인할 수 있다
  • 3서비스 전용 계정을 원칙에 따라 생성하고 /sbin/nologin을 설정할 수 있다
  • 4firewalld 및 SELinux 초기 설정을 수행할 수 있다
  • 5SSH PasswordAuthentication 비활성화 및 포트 변경으로 보안 강화를 할 수 있다
실습 환경 준비
현재 서버 기본 정보 확인
hostnamectl && timedatectl && locale
패키지 관리자 확인 (RHEL/Ubuntu)
which dnf yum apt 2>/dev/null
방화벽 서비스 상태 확인
systemctl status firewalld ufw 2>/dev/null | head -5
SELinux 상태 확인 (RHEL 계열)
getenforce 2>/dev/null || echo 'SELinux not installed'

Hostname / Timezone / Locale 설정

💡개념

Hostname 설정

서버 이름은 단순한 식별자가 아닙니다. 로그, 모니터링 대시보드, 장애 알림 메시지 모두에 호스트명이 출력되기 때문에, 이름이 불명확하면 "어느 서버에서 난 에러인지"를 파악하는 데만 시간이 낭비됩니다. 처음부터 역할과 환경이 드러나는 이름을 붙이는 것이 운영 효율을 높이는 첫 번째 설정입니다.

서버 초기 구축 — 설정 체크리스트와 SSH 보안 강화

호스트명은 단순한 이름이 아닙니다. 로그에 출력되고, 모니터링 대시보드에 표시되며, 장애 상황에서 "어느 서버에서 난 에러인지"를 식별하는 핵심 식별자입니다.

명명 규칙 예시: {역할}-{환경}-{번호}

  • web-prd-01, was-prd-01, db-prd-01
  • web-stg-01, was-dev-01
로컬 터미널
# 호스트명 확인
hostname
hostnamectl

# 호스트명 변경 (재부팅 불필요, 즉시 적용)
sudo hostnamectl set-hostname web-prd-01

# /etc/hosts에 자신의 호스트명 등록 (내부 DNS 없는 환경)
# 127.0.0.1 localhost
# 10.0.1.10 web-prd-01    ← 실제 IP로 등록
sudo vi /etc/hosts

hostnamectl set-hostname/etc/hostname 파일을 수정하고 systemd-hostnamed에 즉시 반영합니다. 과거의 hostname 명령어는 재부팅 후 초기화되므로 사용하지 마세요.

신규 서버 초기 설정 체크리스트

💡개념

Timezone 및 Locale 설정

새벽 2시에 장애가 났는데 서버 로그에 찍힌 시간이 오후 5시라면, 장애 발생 시점을 추적하는 데만 30분을 낭비합니다. 서버 timezone이 UTC이면 한국 시간과 9시간이 차이나 로그를 볼 때마다 계산이 필요하고, 분석 실수도 잦아집니다. 여러 서버의 timezone이 제각각이면 로그를 합쳐서 분석할 때 시간 순서가 뒤섞입니다.

Timezone 설정 (가장 중요):

로컬 터미널
# 현재 timezone 확인
timedatectl

# Asia/Seoul로 설정
sudo timedatectl set-timezone Asia/Seoul

# 설정 확인
timedatectl status
# Local time: Thu 2025-01-15 14:30:00 KST
# Time zone: Asia/Seoul (KST, +0900)

Locale 설정 (한국어 인코딩 문제 방지):

로컬 터미널
# 현재 locale 확인
locale

# UTF-8 locale 생성 및 설정 (Ubuntu/Debian)
sudo locale-gen ko_KR.UTF-8
sudo update-locale LANG=ko_KR.UTF-8 LC_ALL=ko_KR.UTF-8

# RHEL/CentOS 계열
sudo localectl set-locale LANG=ko_KR.UTF-8

# 적용 확인 (재로그인 후)
locale

NTP 시간 동기화 확인:

로컬 터미널
# systemd-timesyncd 상태 확인 (Ubuntu)
timedatectl show-timesync --all | head -5

# chronyc로 NTP 동기화 확인 (RHEL/CentOS)
chronyc tracking | grep -E 'Source|Offset'

서버 시간이 맞지 않으면 SSL 인증서 검증 실패, JWT 토큰 만료 오류, 로그 분석 오차 등 예상치 못한 문제가 다양하게 발생합니다.

Hostname / Timezone 초기 설정 실습
🔍실행 후 확인할 것
  • hostnamectl 출력에서 'Static hostname'이 FQDN 형식(web-server-01.example.com)이면 올바른 형태
  • timedatectl에서 'Time zone: Asia/Seoul'이 보이면 KST 적용 완료
  • NTPSynchronized=yes이면 시간 동기화 정상 — no이면 chrony/ntpd 서비스 확인 필요
  • date 명령어 결과 시간이 실제 시간과 맞는지 확인

필수 패키지 설치

💡개념

Java 및 기본 유틸리티 설치

서버에 Java가 설치돼 있지 않아 Tomcat이 기동조차 안 됐는데, 신규 서버 초기화 체크리스트에 Java 설치 항목이 빠져있었습니다. 서버마다 Java 버전이 다르면 개발계에서 테스트한 애플리케이션이 운영계에서 예상치 못한 방식으로 동작합니다. JDK 8과 JDK 17은 API 호환성 차이가 있어, 버전 혼용은 배포 후 기동 실패로 직결됩니다. 초기화 시점에 버전을 고정하고 문서화해야 나중에 서버가 늘어도 일관된 환경이 유지됩니다.

WAS(Tomcat 등) 운영에는 Java가 필수입니다. 버전 관리를 명확히 해야 이후 Java 버전 충돌 문제를 방지할 수 있습니다.

로컬 터미널
# --- Ubuntu/Debian 계열 ---

# 패키지 목록 업데이트 (먼저 실행)
sudo apt-get update

# Java 17 LTS 설치 (OpenJDK)
sudo apt-get install -y openjdk-17-jdk

# 기본 유틸리티 설치
sudo apt-get install -y wget curl unzip vim net-tools

# --- RHEL/CentOS Stream / Rocky Linux 계열 ---

# Java 17 설치
sudo dnf install -y java-17-openjdk java-17-openjdk-devel

# 기본 유틸리티 설치
sudo dnf install -y wget curl unzip vim net-tools

# --- 공통: 설치 확인 ---
java -version
# openjdk version "17.0.x" 2024-xx-xx
# OpenJDK Runtime Environment ...

which wget curl unzip

Java 버전 여러 개가 설치된 경우 기본값 지정:

로컬 터미널
# Ubuntu
sudo update-alternatives --config java
# 목록에서 사용할 버전 번호 입력

# RHEL/CentOS
sudo alternatives --config java

JAVA_HOME 환경변수 설정 (Tomcat 등에서 필요):

로컬 터미널
# 설치 경로 확인
dirname $(dirname $(readlink -f $(which java)))
# 예: /usr/lib/jvm/java-17-openjdk-amd64

# /etc/profile.d/java.sh 로 영구 설정
sudo tee /etc/profile.d/java.sh << 'EOF'
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
EOF

source /etc/profile.d/java.sh
echo $JAVA_HOME

서비스 계정 생성

💡개념

서비스 전용 계정 생성 원칙

Tomcat, Nginx 등의 미들웨어를 root로 실행하는 것은 심각한 보안 위험입니다. 프로세스가 탈취되면 서버 전체가 장악됩니다.

원칙: 각 서비스는 전용 계정으로 실행하고, 해당 계정은 대화형 쉘 로그인을 차단합니다.

로컬 터미널
# Tomcat 전용 계정 생성
# -r: 시스템 계정 (UID < 1000)
# -s /sbin/nologin: 대화형 쉘 차단
# -d /opt/tomcat: 홈 디렉터리 지정
# -m: 홈 디렉터리 생성
sudo useradd -r -s /sbin/nologin -d /opt/tomcat -m tomcat

# 계정 확인
id tomcat
# uid=999(tomcat) gid=999(tomcat) groups=999(tomcat)

grep tomcat /etc/passwd
# tomcat:x:999:999::/opt/tomcat:/sbin/nologin

# SSH 로그인 차단 확인 (이 계정으로 su 시도)
sudo su -s /bin/bash tomcat -c "whoami"
# tomcat (쉘은 열리지만 su - tomcat 직접 접속은 차단됨)

계정별 디렉터리 소유권 설정:

로컬 터미널
# 서비스 디렉터리를 해당 계정이 소유하도록 설정
sudo mkdir -p /opt/tomcat/webapps /opt/tomcat/logs /opt/tomcat/conf
sudo chown -R tomcat:tomcat /opt/tomcat
sudo chmod 750 /opt/tomcat

# 확인
ls -la /opt/ | grep tomcat
# drwxr-x--- 5 tomcat tomcat 4096 Jan 15 14:30 tomcat

root로 직접 작업하지 않는 이유:

  • 실수로 시스템 파일 삭제 시 복구 불가
  • 작업 이력 추적 불가 (who did what 불명확)
  • 보안 감사(audit) 시 root 작업은 모든 책임이 불분명해짐
서비스 계정 생성 실습
🔍실행 후 확인할 것
  • id appuser 결과에서 uid가 1000 미만(시스템 계정 범위)이면 -r 옵션 효과
  • getent passwd appuser에서 마지막 필드가 /sbin/nologin 또는 /usr/sbin/nologin이면 정상
  • su - appuser 시도 시 'This account is currently not available' 메시지가 나와야 함
  • 홈 디렉터리 소유자가 appuser:appuser이면 파일 접근 권한 설정 완료

방화벽 초기 설정

💡개념

firewalld 기본 설정 (RHEL/CentOS 계열)

OS 설치 직후 방화벽 설정 없이 서버를 사용하다가 보안 스캐너에 불필요한 포트가 노출됐다는 경고를 받은 경우가 있습니다. 초기 서버에는 기본적으로 열려있는 포트가 있고, 서비스 포트가 아닌 것들은 외부에 노출되면 안 됩니다. 필요한 포트만 열고 나머지는 닫는 것이 서버 초기화의 기본입니다.

서버 터미널
# firewalld 설치 및 시작
sudo systemctl enable --now firewalld
sudo systemctl status firewalld

# 현재 zone 및 허용 서비스 확인
sudo firewall-cmd --get-default-zone
# public

sudo firewall-cmd --list-all
# public (active)
#   services: cockpit dhcpv6-client ssh

# HTTP, HTTPS 포트 영구 허용
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# 특정 포트 허용 (Tomcat AJP 또는 커스텀 포트)
sudo firewall-cmd --permanent --add-port=8080/tcp

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

# 확인
sudo firewall-cmd --list-all
# services: cockpit dhcpv6-client http https ssh
# ports: 8080/tcp

# 특정 IP 대역만 허용 (DB 서버 접근 제한)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.1.0/24" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --reload
💡개념

SELinux 초기 설정 (RHEL/CentOS 계열)

Nginx를 설치하고 나서 80 포트가 열려있는데 접속이 안 됩니다. 원인이 SELinux였는데, disabled로 꺼버리면 이후에 다른 보안 취약점이 생겼을 때 SELinux가 막아줄 방어막이 사라집니다. "어렵다"는 이유로 disabled로 꺼두는 경우가 많지만, 이는 서버 보안을 크게 약화시킵니다.

로컬 터미널
# 현재 SELinux 상태 확인
getenforce
# Enforcing / Permissive / Disabled

sestatus | head -5

# 신규 서비스 설치 후 임시로 Permissive로 전환 (로그 수집 목적)
sudo setenforce 0   # 임시 (재부팅 후 복원)
getenforce
# Permissive

# 서비스 정상 동작 확인 후 다시 Enforcing으로
sudo setenforce 1

# 영구 변경 (재부팅 후에도 적용) — /etc/selinux/config 수정
sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
grep SELINUX /etc/selinux/config

# Nginx가 특정 포트를 사용할 수 있게 SELinux 정책 추가
sudo semanage port -a -t http_port_t -p tcp 8081
sudo semanage port -l | grep http_port_t

audit 로그에서 SELinux 차단 원인 확인:

로컬 터미널
# SELinux가 막은 액션 확인
sudo ausearch -m avc -ts recent | tail -20

# audit2allow로 필요한 정책 확인
sudo ausearch -m avc -ts recent | audit2allow -M myapp
방화벽 상태 확인 실습
🔍실행 후 확인할 것
  • firewall-cmd --state 결과가 'running'이면 방화벽 활성 상태
  • services 항목에 'ssh'가 포함돼 있어야 현재 SSH 접속이 유지되는 이유가 됨
  • 방화벽 규칙에 서비스 포트(80, 443, 8080 등)가 없으면 외부에서 접근 불가

SSH 보안 설정

💡개념

SSH 보안 강화

신규 서버를 IDC에서 받자마자 보안 팀에서 "22번 포트에 무차별 대입 시도 로그가 쌓이고 있습니다"라는 알림이 왔습니다.

SSH 보안 설정 — sshd_config 핵심 항목 OS만 설치된 서버는 기본 SSH 설정 그대로라 root 로그인도 되고 패스워드 인증도 열려있습니다. 서버를 인터넷에 연결하는 순간부터 공격은 시작됩니다. 기본 SSH 설정은 보안상 취약점이 많습니다. 서버 초기 구축 시 반드시 아래 항목을 점검합니다.

로컬 터미널
# sshd_config 수정 전 반드시 백업
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)

# sshd_config 수정
sudo vi /etc/ssh/sshd_config

설정해야 하는 주요 항목:

로컬 터미널
# 1. 기본 포트 변경 (22 → 다른 포트, 스캔 봇 차단 효과)
Port 2222

# 2. root 직접 로그인 차단
PermitRootLogin no

# 3. 비밀번호 인증 비활성화 (키 기반 인증만 허용)
PasswordAuthentication no
ChallengeResponseAuthentication no

# 4. 빈 비밀번호 허용 안 함
PermitEmptyPasswords no

# 5. 접속 허용 사용자 제한 (필요한 계정만)
AllowUsers deploy ops-admin

# 6. 로그인 시도 타임아웃
LoginGraceTime 30

# 7. MaxAuthTries 줄이기
MaxAuthTries 3
로컬 터미널
# 설정 문법 검증 (적용 전 반드시 실행!)
sudo sshd -t
# 오류 없으면 아무 출력 없음

# SSH 서비스 재시작
sudo systemctl restart sshd

# 재시작 후 상태 확인
sudo systemctl status sshd

공개키 등록 (키 기반 인증 설정):

로컬 터미널
# 관리자 PC에서 키 생성 (관리자 PC에서 실행)
ssh-keygen -t ed25519 -C "ops-admin@company.com"

# 공개키를 서버에 등록
ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 2222 deploy@서버IP

# 또는 수동으로
mkdir -p ~/.ssh && chmod 700 ~/.ssh
cat >> ~/.ssh/authorized_keys << 'EOF'
ssh-ed25519 AAAA... 관리자공개키내용
EOF
chmod 600 ~/.ssh/authorized_keys

주의: PasswordAuthentication no 설정 전에 반드시 키 기반 로그인이 성공하는지 확인하세요. 확인 전에 재시작하면 서버에서 잠길 수 있습니다.

서버 초기 설정 체크리스트 실습
🔍실행 후 확인할 것
  • hostnamectl 명령 후 hostname 출력값이 설정한 이름(was-dev-01)으로 변경된다
  • timedatectl | grep 'Local time' 에서 KST(+09:00) 시간대가 표시된다
  • id appuser 결과에서 shell이 /sbin/nologin으로 표시되어 대화형 로그인이 차단됨을 확인
  • sudo sshd -t 실행 결과가 아무 출력 없이 Exit code: 0이면 SSH 설정 문법 OK
  • 방화벽 상태에서 허용된 포트와 서비스 목록이 정책대로 표시된다
💼
실무 맥락
현업 패턴

실제 업무에서 이 지식이 쓰이는 상황:

신규 서버 초기 설정은 인프라 엔지니어의 가장 기본적인 업무입니다. 이 설정이 표준화되어 있지 않으면 서버가 늘어날수록 관리 부담이 기하급수적으로 커집니다.

실무에서는 이 과정을 Ansible Playbook이나 Shell 스크립트로 자동화합니다. "신규 서버 초기화 플레이북"을 만들어두면 서버 10대를 동시에 초기화하는 데 5분도 걸리지 않습니다.

중요한 것은 표준화입니다. 서버마다 timezone이 다르고, Java 버전이 다르고, 계정 이름이 다르면 — 나중에 스크립트를 쓸 때마다 예외 처리를 넣어야 합니다.

다음 모듈에서는 이 서버에서 매일 하게 될 작업의 기초 — Linux 파일시스템 구조, 권한, systemctl 서비스 관리를 다룹니다.

지식 확인

퀴즈 — 4문제

Q1

서버에 서비스 전용 계정(service account)을 만들 때 /sbin/nologin을 지정하는 이유는?

Q2

sshd_config에서 PasswordAuthentication no 로 설정하는 이유는?

Q3

SELinux를 완전히 비활성화(disabled)하는 대신 permissive 모드를 임시로 사용하는 이유는?

Q4

서버의 timezone을 Asia/Seoul로 설정해야 하는 실무적 이유는?

0 / 4 답변

🧪 실습으로 확인하기

Nginx 설치 및 기동

초급

Linux 서버에 Nginx를 설치하고 systemd 서비스로 등록하여 80포트에서 응답하는 상태까지 만든다.

30📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

infra-ops입문 · 50
[Infra Ops] 프로세스(ps), 포트(netstat), 리소스(top) 모니터링 실무
인프라 서비스 운영 트랙 계속
linux입문 · 30
[Linux] 개발자가 왜 리눅스 서버와 커맨드라인을 반드시 배워야 하는가
Linux 트랙 시작점