RHEL 실전 #1 웹 서버 운영: nginx, systemd, SELinux 정책

5 분 소요

RHEL 실무 트랙의 기초,중급,고급에서 systemd, SELinux, firewalld, 스토리지를 하나씩 익혔다면, 이제 익힌 도구들을 하나의 서비스를 올리는 한 사이클로 묶을 차례입니다. RHEL 실전 트랙은 개별 기능을 나열하는 대신, 실제 운영에서 마주치는 시나리오를 처음부터 끝까지 따라가는 트랙입니다. 그 첫 글로 가장 흔한 작업인 웹 서버 운영을 다루겠습니다.

RHEL에서 nginx를 올리는 일은 패키지 하나를 설치하는 것으로 끝나지 않습니다. 서비스를 systemd로 등록하고, SELinux가 막는 부분을 풀고, firewalld로 포트를 여는 세 박자가 맞아야 비로소 외부에서 페이지가 열립니다. 이 세 박자가 어긋났을 때 어디서 막히는지를 함께 짚겠습니다.

패키지 설치와 서비스 등록 #

RHEL의 기본 저장소에는 nginx가 들어 있습니다. dnf로 설치한 뒤 systemd로 등록합니다.

# 설치
sudo dnf install -y nginx

# 부팅 시 자동 시작 + 즉시 시작 (한 번에)
sudo systemctl enable --now nginx

# 상태 확인
systemctl status nginx

enable --now는 enable(부팅 자동 시작)과 start(즉시 시작)를 한 번에 처리합니다. RHEL 실무에서 서비스를 올릴 때 가장 자주 쓰는 형태입니다. 설치 직후에는 로컬에서 먼저 응답을 확인하겠습니다.

curl -I http://localhost

여기까지는 SELinux나 firewalld가 개입하지 않아 대체로 한 번에 됩니다. 문제는 외부에서 접속할 때, 그리고 기본값을 벗어날 때 시작됩니다.

firewalld로 포트 열기 #

기본 상태의 RHEL은 firewalld가 활성화되어 있어, http(80),https(443)가 막혀 있습니다. 서비스 단위로 영구 개방합니다.

# http,https 서비스 영구 허용
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent

# 반영
sudo firewall-cmd --reload

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

--permanent를 빠뜨리면 재부팅 후 규칙이 사라집니다. --permanent로 영구 규칙을 만든 뒤 --reload로 런타임에 반영하는 두 단계가 RHEL 방화벽 작업의 기본 흐름입니다.

SELinux가 막는 지점 #

RHEL의 SELinux는 기본이 enforcing입니다. nginx가 표준 위치(/usr/share/nginx/html)에서 표준 포트(80,443)로 동작하는 한 SELinux는 조용합니다. 그러나 문서 루트를 옮기거나 비표준 포트를 쓰면 즉시 막힙니다. 이 두 가지가 실무에서 가장 자주 겪는 SELinux 사고입니다.

비표준 포트를 열 때 #

nginx를 8080 포트로 돌리도록 설정을 바꾸면, 설정 자체는 맞아도 서비스가 뜨지 않습니다. SELinux가 8080을 웹 서버 포트로 인정하지 않기 때문입니다.

# 현재 http_port_t에 등록된 포트 확인
sudo semanage port -l | grep http_port_t

# 8080을 웹 포트로 영구 등록
sudo semanage port -a -t http_port_t -p tcp 8080

semanage가 없다면 policycoreutils-python-utils 패키지를 설치합니다. 포트를 등록한 뒤 nginx를 재시작하면 정상적으로 뜹니다.

문서 루트를 옮길 때 #

콘텐츠를 /srv/www 같은 비표준 경로로 옮기면, 그 디렉터리의 SELinux 컨텍스트가 웹 콘텐츠 타입이 아니라 nginx가 읽지 못합니다. 컨텍스트를 영구 부여하고 적용합니다.

# /srv/www 이하를 웹 콘텐츠 타입으로 영구 등록
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"

# 디스크의 실제 레이블에 적용
sudo restorecon -Rv /srv/www

semanage fcontext로 정책에 규칙을 추가하고 restorecon으로 실제 파일에 적용하는 두 단계가 핵심입니다. chcon으로도 컨텍스트를 바꿀 수 있지만 chcon은 임시라 재레이블이나 재부팅 시 되돌아가므로, 영구 작업에는 semanage fcontext + restorecon을 씁니다.

boolean으로 동작 허용 #

nginx가 다른 서버로 요청을 전달(reverse proxy)하거나 NFS,CIFS 위의 콘텐츠를 읽어야 할 때는 SELinux boolean을 켜야 합니다.

# 네트워크 연결 허용 (reverse proxy 등)
sudo setsebool -P httpd_can_network_connect on

-P를 붙여야 재부팅 후에도 유지됩니다. 어떤 boolean이 필요한지는 getsebool -a | grep httpd로 후보를 추리고, 막혔을 때 audit 로그(/var/log/audit/audit.log)에서 ausearchsealert로 원인을 찾습니다.

막혔을 때 진단 순서 #

웹 서버가 안 열릴 때는 다음 순서로 좁혀 가면 대부분 원인이 드러납니다.

  1. 서비스가 떠 있는가. systemctl status nginx, 실패 시 journalctl -u nginx
  2. 로컬에서 열리는가. curl -I http://localhost로 nginx 자체 문제와 외부 접근 문제를 분리
  3. 방화벽이 열렸는가. firewall-cmd --list-all에 http,https가 있는가
  4. SELinux가 막는가. sudo ausearch -m AVC -ts recent 또는 journalctl에 denied가 있는가, 임시로 setenforce 0 후 되면 SELinux가 원인

특히 4번에서 setenforce 0으로 잠깐 permissive로 바꿔 보면 SELinux가 원인인지 1초 만에 갈립니다. 단, 확인용으로만 쓰고 원인을 찾은 뒤에는 반드시 setenforce 1로 되돌리고 정책으로 푸는 것이 옳은 운영입니다.

정리 #

이번 글에서 잡은 것:

  • 웹 서버 운영은 세 박자. systemd 서비스 등록(enable --now), firewalld 포트 개방(--permanent + --reload), SELinux 정책
  • SELinux가 막는 두 지점. 비표준 포트(semanage port -a), 비표준 문서 루트(semanage fcontext + restorecon)
  • boolean. reverse proxy,원격 콘텐츠는 setsebool -P httpd_can_network_connect on
  • 진단 순서. 서비스 → 로컬 curl → 방화벽 → SELinux. setenforce 0은 확인용으로만

다음: DB 운영 #

웹 계층을 올렸으니 그 뒤를 받치는 데이터 계층으로 갑니다.

#2 DB 운영: PostgreSQL on RHEL에서는 RHEL의 AppStream module로 PostgreSQL을 설치하고 초기화하는 법, 데이터 디렉터리와 SELinux 컨텍스트, 원격 접속을 위한 설정과 firewalld, 그리고 백업과 서비스 운영까지 한 사이클로 정리하겠습니다.

X