안녕하세요. 일본서버 호스팅 전문 비전 IDC 기술팀입니다.
CentOS 7에서 Nginx 웹사이트에 접속했을 때 403 Forbidden 오류가 표시된다면, Nginx 프로세스는 요청을 받았지만 요청한 파일이나 디렉터리에 대한 접근을 허용하지 못한 상태일 가능성이 높습니다. 대표적인 원인은 웹 루트의 파일·디렉터리 권한, 기본 인덱스 파일 부재, 잘못된 root 또는 alias 설정, SELinux 컨텍스트, 그리고 Nginx의 deny 규칙입니다.
이 문서에서는 Nginx 오류 로그를 먼저 확인한 뒤 실제 문서 루트, Unix 권한, 인덱스 파일, SELinux, 접근 제어 설정을 순서대로 점검하여 403 Forbidden의 원인을 찾고 안전하게 복구하는 방법을 설명합니다.
적용 환경
| 운영체제 | CentOS Linux 7 |
|---|---|
| 웹 서버 | Nginx |
| 주요 설정 경로 | /etc/nginx/nginx.conf, /etc/nginx/conf.d/ |
| 주요 로그 | /var/log/nginx/error.log, /var/log/nginx/access.log |
가장 먼저 확인할 항목
먼저 Nginx 서비스가 실행 중이고 설정 문법에 오류가 없는지 확인합니다.
systemctl status nginx --no-pager -l
nginx -t
nginx -t 결과에서 설정 문법이 정상이라는 메시지가 확인되어야 합니다. 설정 검사 자체가 실패한다면 403 문제를 확인하기 전에 해당 문법 오류부터 수정해야 합니다.
서버 내부에서 직접 요청하여 실제 HTTP 상태 코드를 확인합니다.
curl -I http://127.0.0.1/
Nginx 오류 로그에서 원인 확인
403 오류를 재현한 직후 Nginx 오류 로그를 확인하면 원인을 가장 빠르게 좁힐 수 있습니다.
tail -n 100 /var/log/nginx/error.log
실시간으로 요청과 로그를 함께 확인하려면 다음 명령을 실행한 뒤 다른 터미널이나 브라우저에서 문제가 발생하는 URL에 접속합니다.
tail -f /var/log/nginx/error.log
로그에 directory index of ... is forbidden이 보이면 인덱스 파일 문제를, Permission denied가 보이면 Unix 권한 또는 SELinux를 우선 확인합니다. 로그 파일 경로를 별도로 변경한 환경에서는 현재 적용 중인 설정을 확인해야 합니다.
nginx -T 2>&1 | grep -nE 'error_log|access_log|server_name|root|alias|index'
문서 루트와 인덱스 파일 확인
1. 실제 적용 중인 root와 index 확인
Nginx가 어느 디렉터리에서 파일을 찾고 있는지 확인합니다. 여러 가상 호스트가 있다면 요청한 도메인의 server 블록을 정확히 찾아야 합니다.
nginx -T 2>&1 | grep -nE 'server_name|root|alias|index'
Nginx의 index 지시어 기본값은 index.html입니다. 요청 URI가 /처럼 디렉터리를 가리키는데 지정된 인덱스 파일이 없고 디렉터리 목록 표시도 허용하지 않는다면 403이 발생할 수 있습니다.
2. 인덱스 파일 존재 여부 확인
예를 들어 실제 문서 루트가 /usr/share/nginx/html이라면 다음과 같이 확인합니다.
ls -la /usr/share/nginx/html
ls -l /usr/share/nginx/html/index.html
사이트가 index.php를 사용하는 환경이라면 Nginx 설정의 index 목록에도 해당 파일이 포함되어 있어야 합니다.
index index.php index.html;
파일과 디렉터리 권한 확인
Nginx 워커 프로세스가 실행되는 계정을 먼저 확인합니다.
grep -n '^[[:space:]]*user' /etc/nginx/nginx.conf
ps -eo user,group,pid,cmd | grep '[n]ginx: worker'
일반적인 패키지 구성에서는 워커가 nginx 계정으로 실행되지만, 실제 서버 설정을 기준으로 판단해야 합니다.
문제가 되는 파일까지의 모든 상위 디렉터리 권한을 한 번에 확인하려면 namei를 사용할 수 있습니다.
namei -l /usr/share/nginx/html/index.html
웹 서버가 파일을 읽으려면 파일 자체에 읽기 권한이 필요하고, 해당 파일까지 이동하는 모든 상위 디렉터리에는 실행(x) 권한이 필요합니다. 사용자 정의 웹 루트를 사용하는 경우 특히 상위 디렉터리 권한을 놓치기 쉽습니다.
예를 들어 정적 웹 콘텐츠를 일반적으로 읽기 전용으로 제공하는 경우 파일은 644, 디렉터리는 755와 같은 형태가 흔하지만, 실제 애플리케이션의 소유권과 쓰기 요구사항을 먼저 확인해야 합니다.
SELinux 차단 여부 확인
Unix 파일 권한이 정상인데도 Permission denied가 발생한다면 SELinux 컨텍스트를 확인합니다.
getenforce
ls -Zd /usr/share/nginx/html
ls -Z /usr/share/nginx/html/index.html
기본 웹 콘텐츠 경로의 레이블이 변경되었다면 기본 SELinux 컨텍스트를 복원합니다.
restorecon -Rv /usr/share/nginx/html
웹 루트를 /srv/www/site처럼 사용자 정의 경로로 변경했다면 웹 서버가 읽을 수 있는 httpd_sys_content_t 컨텍스트를 영구적으로 지정할 수 있습니다.
semanage fcontext -a -t httpd_sys_content_t "/srv/www/site(/.*)?"
restorecon -Rv /srv/www/site
SELinux 차단 기록은 Audit 로그에서 확인합니다.
ausearch -m AVC,USER_AVC -ts recent | tail -n 50
Nginx 접근 제어 설정 확인
파일과 SELinux가 정상인데 특정 URL만 403을 반환한다면 allow, deny, 인증 관련 설정 또는 특정 location 블록을 확인합니다.
grep -RniE '^[[:space:]]*(allow|deny|auth_basic|internal)[[:space:]]' /etc/nginx
현재 전체 설정에서 어떤 server와 location이 실제 요청을 처리하는지 확인하려면 다음 명령이 유용합니다.
nginx -T 2>&1 | less
특정 위치에 deny all;이 설정되어 있다면 해당 요청은 의도적으로 차단됩니다. 보안 목적으로 작성된 규칙일 수 있으므로 삭제하기 전에 해당 위치가 외부 공개 대상인지 확인해야 합니다.
설정 적용 및 정상 작동 확인
Nginx 설정 파일을 수정했다면 반드시 문법을 먼저 검사합니다.
nginx -t
문법 검사가 성공한 경우 재시작보다 연결 중단 영향이 적은 reload 방식으로 설정을 반영할 수 있습니다.
systemctl reload nginx
systemctl status nginx --no-pager -l
다시 HTTP 상태 코드를 확인합니다.
curl -I http://127.0.0.1/
정상적으로 웹 페이지가 제공된다면 일반적으로 200, 리디렉션 설정이 있다면 301 또는 302 등의 상태가 확인될 수 있습니다. 외부 도메인이 여러 가상 호스트 중 하나를 사용하는 경우에는 실제 도메인의 Host 헤더를 지정해 확인할 수 있습니다.
curl -I -H 'Host: server.example.com' http://127.0.0.1/
증상별 원인과 해결 방법
| 증상 또는 로그 | 가능한 원인 | 확인 방법 | 해결 방향 |
|---|---|---|---|
directory index of ... is forbidden |
인덱스 파일이 없거나 index 설정과 실제 파일명이 다름 |
nginx -T, 문서 루트의 파일 목록 확인 |
올바른 인덱스 파일을 배치하고 index 지시어 수정 |
Permission denied |
파일·상위 디렉터리 권한 또는 SELinux 차단 | namei -l, ls -Z, ausearch |
최소 권한으로 접근 허용, 올바른 SELinux 컨텍스트 적용 |
| 특정 URL만 403 | location, deny, 인증 또는 내부 전용 설정 |
nginx -T와 접근 제어 지시어 검색 |
요청 URI를 처리하는 블록의 규칙을 검토하여 필요한 범위만 수정 |
| 기본 사이트는 정상인데 도메인만 403 | 다른 server 블록이 선택되거나 해당 가상 호스트의 root가 잘못됨 |
server_name, root 확인 및 Host 헤더를 지정한 curl 테스트 |
해당 도메인의 가상 호스트 설정 수정 |
원상복구 방법
Nginx 설정을 수정하기 전 백업했다면 원래 설정 파일을 복원한 뒤 문법을 검사하고 reload합니다.
nginx -t
systemctl reload nginx
이 문서에서 사용자 정의 SELinux 파일 컨텍스트 규칙을 새로 추가했다가 제거해야 한다면 동일한 정규식을 지정하여 삭제하고 기본 컨텍스트를 다시 적용합니다.
semanage fcontext -d "/srv/www/site(/.*)?"
restorecon -Rv /srv/www/site
자주 묻는 질문
403 Forbidden이면 Nginx 서비스가 중지된 상태인가요?
대부분 그렇지 않습니다. 403은 웹 서버가 요청을 처리한 뒤 접근을 거부했다는 HTTP 상태 코드입니다. 서비스 중지라면 연결 거부나 타임아웃처럼 다른 형태의 오류가 나타나는 경우가 일반적입니다.
SELinux를 비활성화하면 해결되나요?
SELinux가 원인이라면 비활성화했을 때 증상이 사라질 수 있지만, 이를 영구 해결책으로 사용하는 것은 권장하지 않습니다. Audit 로그에서 차단 원인을 확인하고 웹 콘텐츠에 적합한 파일 컨텍스트나 필요한 정책을 적용하는 방식으로 해결하는 것이 좋습니다.
파일 권한을 777로 바꾸면 빠르게 해결되지 않나요?
접근 권한 문제를 일시적으로 가릴 수는 있지만 보안 위험이 커집니다. Nginx 사용자가 읽어야 하는 파일과 통과해야 하는 디렉터리에 필요한 최소 권한만 부여하고, SELinux 문제인지도 별도로 확인해야 합니다.
403과 404는 어떻게 다른가요?
403은 서버가 요청을 이해했지만 접근을 허용하지 않는 경우이고, 404는 요청한 리소스를 찾지 못했거나 노출하지 않도록 처리한 경우입니다. 실제 원인은 Nginx 오류 로그와 적용 설정을 함께 확인해야 정확히 판단할 수 있습니다.
공식 참고자료
- Nginx — ngx_http_index_module: https://nginx.org/en/docs/http/ngx_http_index_module.html
확인 내용:index지시어의 기본값과 인덱스 파일 처리 방식을 확인했습니다. 조회일: 2026년 9월 20일. - Nginx — ngx_http_core_module: https://nginx.org/en/docs/http/ngx_http_core_module.html
확인 내용:root,alias,internal등 요청 경로 처리 관련 지시어를 확인했습니다. 조회일: 2026년 9월 20일. - Red Hat — SELinux User's and Administrator's Guide: SELinux Contexts – Labeling Files
확인 내용: 사용자 정의 웹 콘텐츠 경로에httpd_sys_content_t를 영구 적용하는semanage fcontext와restorecon사용 방법을 확인했습니다. 조회일: 2026년 9월 20일. - CentOS Project — CentOS Linux: https://www.centos.org/centos-linux/
확인 내용: CentOS Linux 7의 지원 종료일이 2024년 6월 30일임을 확인했습니다. 조회일: 2026년 9월 20일.
마무리
CentOS 7에서 Nginx 403 Forbidden 오류가 발생하면 먼저 error.log에서 정확한 메시지를 확인한 뒤 문서 루트와 인덱스 파일, Unix 권한, SELinux 컨텍스트, Nginx 접근 제어 규칙 순서로 점검하면 원인을 효율적으로 좁힐 수 있습니다. 특히 무분별한 chmod 777이나 SELinux 비활성화보다는 필요한 권한과 컨텍스트만 정확하게 수정하는 것이 중요합니다.
비전 IDC는 일본서버 호스팅 환경을 포함한 다양한 리눅스 서버 운영 환경에서 장애 원인을 정확하게 진단하고 복구하는 데 도움이 되는 기술정보를 지속적으로 제공하겠습니다.
