infra
Platform

모듈 맵

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

0 / 52 완료

펼치기
0 / 52 완료0%

인프라 운영 & SRE · 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 명령어는 재부팅 후 초기화되므로 사용하지 마세요.

신규 서버 초기 설정 체크리스트 — 호스트명 설정(hostnamectl, 재부팅 후에도 유지)·시간 동기화(chrony)·패키지 업데이트·관리 계정 생성·SSH 보안(키 인증·root 차단·포트 변경)·방화벽·모니터링 에이전트 설치를 순서대로. 초기에 빠뜨리면 나중에 운영 중 적용이 번거로움확대

💡개념

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 초기 설정 실습
1

1. 현재 서버 기본 정보 확인

hostnamectl && echo '---' && timedatectl | head -6
2

2. Timezone 확인 및 변경 테스트

timedatectl list-timezones | grep Seoul && timedatectl | grep 'Time zone'
3

3. 시간 동기화 상태 확인

timedatectl show --property=NTPSynchronized,NTP && date
🔍실행 후 확인할 것
  • hostnamectl 출력에서 먼저 Static hostname 값을 보고, 그 다음 timedatectl로 시간대 확인 — 두 항목을 순서대로 체크해야 초기화 완료
  • NTPSynchronized 기준: yes이면 정상, no이면 systemctl status chronyd 또는 ntpd로 동기화 서비스 상태 확인 — 5분 이상 지나도 no이면 chrony 재시작 필요
  • hostname이 변경됐는데 timedatectl 시각이 UTC 기준이면 → 두 설정이 모두 적용됐더라도 timezone 미설정 상태를 의미하므로 timedatectl set-timezone Asia/Seoul 재실행

필수 패키지 설치

💡개념

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 작업은 모든 책임이 불분명해짐
서비스 계정 생성 실습
1

1. 서비스 계정 생성

sudo useradd -r -m -d /opt/appuser -s /sbin/nologin appuser 2>/dev/null || echo '계정 이미 존재'; id appuser
2

2. 계정 속성 확인

getent passwd appuser && sudo ls -la /opt/appuser/
3

3. 로그인 차단 확인

su - appuser 2>&1 | head -3 || echo '로그인 차단 확인 완료'
🔍실행 후 확인할 것
  • id appuser 출력에서 먼저 uid 숫자를 보고, 그 다음 getent passwd 마지막 필드로 shell 확인 — uid 1000 미만이면 시스템 계정(-r 옵션 효과), shell이 /sbin/nologin이면 대화형 로그인 차단
  • uid 기준: 1000 미만=시스템 계정(정상), 1000 이상=일반 사용자(-r 플래그 누락) — 서비스 계정은 반드시 1000 미만이어야 보안 정책 통과
  • uid가 1000 미만인데 shell이 /bin/bash이면 → 대화형 로그인 차단이 안 된 상태 — usermod -s /sbin/nologin 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 3가지 모드 비교와 올바른 대응 순서 — Enforcing(운영 기본)은 정책 위반을 차단하고 audit 로그도 남겨 방어막 ON, Permissive(임시 진단)는 위반을 허용하되 로그는 남겨 관찰만, Disabled(지양)는 차단도 기록도 없어 방어막 OFF 무방비. Nginx 접속이 안 될 때 올바른 순서는 getenforce로 모드 확인 → setenforce 0으로 Permissive 임시 전환 → ausearch·audit2allow로 차단 원인 확인 → semanage port로 필요한 정책만 추가 → setenforce 1로 Enforcing 복원이며, 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
방화벽 상태 확인 실습
1

1. 방화벽 서비스 상태 확인

systemctl is-active firewalld 2>/dev/null && firewall-cmd --state 2>/dev/null || (systemctl is-active ufw 2>/dev/null && sudo ufw status 2>/dev/null) || echo '방화벽 비활성 또는 다른 방식 사용'
2

2. 허용된 포트 목록 확인

sudo firewall-cmd --list-all 2>/dev/null || sudo ufw status numbered 2>/dev/null || sudo iptables -L INPUT -n --line-numbers 2>/dev/null | head -20
🔍실행 후 확인할 것
  • firewall-cmd --list-all 출력에서 먼저 services 항목을 보고, 그 다음 ports 항목 확인 — ssh가 services에 없으면 현재 접속이 유일한 세션이라도 즉시 추가 필요
  • services 기준: ssh 포함=현재 접속 유지 가능, 누락=방화벽 재시작 시 SSH 단절 위험 — 방화벽 설정 전 반드시 ssh 허용 여부를 먼저 확인
  • running 상태인데 80/443 포트가 services/ports에 없으면 → Nginx/Apache가 기동돼도 외부 요청이 차단되는 구조이므로 포트 추가 후 --runtime-to-permanent로 영구 적용

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 설정 전에 반드시 키 기반 로그인이 성공하는지 확인하세요. 확인 전에 재시작하면 서버에서 잠길 수 있습니다.

서버 초기 설정 체크리스트 실습
1

1. Hostname 설정

sudo hostnamectl set-hostname was-dev-01 && hostname
2

2. Timezone 설정

sudo timedatectl set-timezone Asia/Seoul && timedatectl | grep 'Local time'
3

3. 서비스 계정 생성

sudo useradd -r -s /sbin/nologin -d /opt/appuser -m appuser && id appuser
4

4. sshd_config 검증

sudo sshd -t && echo 'SSH config OK'
5

5. 방화벽 상태 확인

sudo firewall-cmd --list-all 2>/dev/null || sudo ufw status 2>/dev/null || iptables -L INPUT -n --line-numbers | head -20
🔍실행 후 확인할 것
  • hostname → timedatectl → id appuser → sshd -t → firewall-cmd --list-all 순서로 확인 — 앞 단계 실패 시 이후 단계는 의미 없으므로 순서대로 체크
  • sshd -t 기준: 아무 출력 없이 exit code 0=설정 문법 정상, 에러 메시지 출력=반드시 수정 후 reload — 문법 오류 상태에서 reload 시 sshd 재시작 실패로 SSH 접속 불가
  • KST 설정됐는데 방화벽 서비스 목록에 ssh가 없으면 → 개별 설정은 성공했어도 재부팅 후 SSH 접속 불가 상태이므로 firewall-cmd --permanent --add-service=ssh 즉시 실행

심화 — '재부팅 후에도' 유효한 하드닝

💡개념

심화: 런타임 설정과 영구 설정, 그리고 부팅 순서

초기 세팅에서 가장 조용히 새는 곳은 "지금은 됐는데 재부팅하면 사라지는" 설정입니다. 하드닝은 한 번 적용이 아니라 서버가 다시 켜져도 같은 상태여야 완성입니다. 여기서 두 가지 내부 개념을 짚습니다.

  • 런타임 vs 영구: setenforce 0, 옵션 없는 firewall-cmd, sysctl -w, 예전 hostname 명령은 모두 메모리에만 반영되는 런타임 변경이라 재부팅으로 사라집니다. 영구 반영은 각각 /etc/selinux/config, firewall-cmd --permanent(+--reload), /etc/sysctl.d/*.conf, hostnamectl이 담당합니다. 실무에서 자주 쓰는 안전 패턴은 런타임으로 먼저 시험해 서비스가 멀쩡한지 본 뒤, 확정되면 영구 설정에 반영하는 것입니다.
  • 부팅 순서(systemd 유닛 의존성): 서비스는 systemd가 정한 순서로 뜹니다. 유닛의 After=/Wants=가 잘못 걸리면, 예컨대 네트워크 인터페이스가 IP를 받기 전에 서비스가 먼저 떠서 특정 IP 바인딩에 실패합니다. network.target은 '네트워크 스택 구성 중'까지만 보장하고, 실제로 IP가 붙어 통신 가능한 시점network-online.target이 보장합니다 — 특정 주소에 바인딩하는 서비스는 이걸 기다려야 합니다.

그래서 초기 세팅의 마지막 검증은 언제나 "한 번 재부팅해 보고 모든 서비스가 스스로 올라오는지" 확인하는 것입니다. systemctl is-enabled로 자동 시작 등록을, 재부팅 후 systemctl --failed로 실패 유닛을 봅니다.

상황: 유닛 파일을 만들어 enable까지 했는데, 서버를 재부팅하면 이 서비스만 failed 상태입니다. 로그인해서 손으로 systemctl start를 하면 즉시 정상 기동됩니다. '수동은 되고 자동은 안 되는' 전형적인 패턴입니다.

원인: 서비스가 설정에서 특정 내부 IP(예: 10.0.1.10:8080)에 바인딩하도록 돼 있는데, 부팅 과정에서 이 유닛이 네트워크 인터페이스가 IP를 받기 전에 먼저 시작됐습니다. 아직 존재하지 않는 주소에 bind하려니 'Cannot assign requested address'가 납니다. 수동 시작은 이미 IP가 붙은 뒤라 문제가 없던 것입니다.

진단: journalctl -b -u <서비스>에서 실패 시각과, journalctl -b -u NetworkManager(또는 systemd-networkd)의 IP 획득 시각을 비교합니다 — 서비스 실패가 IP 획득보다 앞서면 확정입니다. systemctl cat <서비스>로 유닛의 After=/Wants= 줄을 확인해 network-online.target 의존이 빠졌는지 봅니다.

해결: 유닛 [Unit] 섹션에 Wants=network-online.targetAfter=network-online.target를 추가하고 daemon-reload 후 재부팅해 검증합니다(둘 다 있어야 하며, network-online.target이 실제 활성화되려면 NetworkManager-wait-online 같은 대기 서비스가 enable돼 있어야 합니다). sleep으로 무작정 기다리게 하는 것은 부팅만 느려지는 임시방편일 뿐 근본 해결이 아닙니다.

💼
실무 맥락
현업 패턴

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

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

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

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

명령어·단축키 빠른 참조

새 서버 초기 세팅·보안 하드닝에서 다룬 명령을 영역별로 모았습니다.

명령어/단축키용도자주 쓰는 예
hostnamectl set-hostname호스트명 영구 설정(재부팅 유지)hostnamectl set-hostname web-prd-01
timedatectl set-timezone타임존 설정(로그 시각 통일)timedatectl set-timezone Asia/Seoul
localectl set-locale로케일 설정(한글 인코딩)localectl set-locale LANG=ko_KR.UTF-8
chronyc trackingNTP 시간 동기화 확인chronyc tracking | grep -E 'Source|Offset'
dnf / apt-get install필수 패키지 설치dnf install -y java-17-openjdk, apt-get install -y wget curl unzip
useradd -r -s /sbin/nologin로그인 불가 서비스 계정 생성useradd -r -s /sbin/nologin -d /opt/tomcat -m tomcat
id / getent passwd계정 UID·셸 확인id tomcat, getent passwd tomcat
firewall-cmd --permanent방화벽 포트·서비스 영구 허용firewall-cmd --permanent --add-service=http && firewall-cmd --reload
firewall-cmd --list-all허용 서비스·포트 확인firewall-cmd --list-all(ssh 포함 여부 먼저)
getenforce / setenforceSELinux 모드 확인·임시 전환setenforce 0(Permissive 진단) → setenforce 1
semanage portSELinux 포트 정책 추가semanage port -a -t http_port_t -p tcp 8081
sshd -tsshd_config 문법 검증(재시작 전 필수)sshd -t && systemctl restart sshd
ssh-keygen / ssh-copy-id키 생성·서버 등록ssh-keygen -t ed25519 -C ops@co, ssh-copy-id -p 2222 deploy@IP
systemctl --failed재부팅 후 실패 유닛 확인systemctl --failed, systemctl is-enabled <svc>

관련 모듈로 더 깊이:

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

지식 확인

퀴즈 — 8문제

Q1

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

Q2

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

Q3

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

Q4

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

Q5

내부 DNS가 없는 환경에서 서버 호스트명을 바꾼 뒤 /etc/hosts에도 자신의 호스트명을 등록하는 이유는?

Q6

서버 locale을 적절히 설정하지 않으면 생길 수 있는 문제는?

Q7

[심화] 초기 하드닝 중 setenforce 0와 firewall-cmd --add-service=http(--permanent 없이)를 실행했다. 서버를 재부팅하면 어떻게 되는가?

Q8

[심화] 새로 등록한 서비스가 부팅 시 'Cannot assign requested address'로 실패하는데, 부팅이 끝난 뒤 수동으로 systemctl start 하면 정상 기동된다. 유닛 파일에 필요한 것은?

0 / 8 답변

🧪 실습으로 확인하기

Nginx 설치 및 기동

초급

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

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

이것도 배워보세요