Tomcat이 갑자기 멈췄습니다. 로그는 /opt/tomcat/logs/catalina.out에 있다는데 권한 오류로 파일을 읽을 수가 없습니다. systemctl status는 뭔가 출력하는데 해석이 안 됩니다. 로그를 보려면 권한을 알아야 하고, 권한을 이해하려면 파일시스템 구조를 알아야 합니다.
매일 쓰는 명령어들이지만 제대로 이해하고 쓰는 것과 그냥 외워서 쓰는 것은 장애 대응 속도에서 바로 차이납니다.
- 1/opt, /var/log, /etc, /tmp, /home, /usr/local 각 디렉터리의 용도를 설명할 수 있다
- 2chmod 숫자 모드로 파일/디렉터리 권한을 설정할 수 있다
- 3chown으로 파일 소유자와 그룹을 변경할 수 있다
- 4visudo로 sudo 권한을 안전하게 설정할 수 있다
- 5systemctl로 서비스를 시작/중지/재시작하고 자동 시작을 설정할 수 있다
du -sh /opt /var/log /etc /tmp 2>/dev/nullid && groupssudo -l 2>/dev/null | head -10systemctl list-units --type=service --state=running | wc -lLinux 디렉터리 구조
인프라 엔지니어가 꼭 알아야 할 디렉터리
파일을 어디에 두느냐는 단순한 정리 습관이 아니라 운영 문제입니다. 로그가 /var/log가 아닌 곳에 쌓이면 모니터링 스크립트가 그 파일을 찾지 못하고, /tmp에 설정 파일을 올리면 재부팅 하나로 모든 것이 사라집니다. 각 디렉터리의 목적을 알아야 파일을 올바른 위치에 두고, 디스크 풀 같은 장애 상황에서도 빠르게 원인을 좁힐 수 있습니다.

디스크가 꽉 찼다는 알림이 왔는데 어디서 공간을 잡아먹고 있는지 찾을 수 없었습니다. /var/log 아래 로그 파일이 수십 GB로 불어있었지만 그 경로가 어디인지 몰랐던 것입니다. Tomcat 로그가 어디에 쌓이는지, 설정 파일이 /etc 에 있어야 하는데 /home 에 올려뒀다면 — 백업 스크립트도, 모니터링도 그 파일을 찾지 못합니다. 각 디렉터리의 목적을 알아야 파일을 올바른 위치에 두고, 장애 시에도 빠르게 찾을 수 있습니다.
Linux FHS(Filesystem Hierarchy Standard)에서 각 디렉터리는 목적이 명확합니다. 잘못된 위치에 파일을 두면 나중에 찾기도 어렵고, 백업이나 모니터링 스크립트도 제대로 작동하지 않습니다.
| 디렉터리 | 용도 | 실무 사용 예 |
|---|---|---|
/opt | 서드파티 소프트웨어 설치 | Tomcat, JBoss, 사내 미들웨어 |
/etc | 시스템 및 서비스 설정 파일 | /etc/nginx/, /etc/ssh/sshd_config |
/var/log | 서비스 로그 파일 | /var/log/nginx/, /var/log/messages |
/var/run | 실행 중인 프로세스 PID 파일 | nginx.pid, httpd.pid |
/tmp | 임시 파일 (재부팅 시 삭제) | 배포 파일 임시 보관, 빌드 임시 파일 |
/home | 일반 사용자 홈 디렉터리 | /home/deploy, /home/ops-admin |
/usr/local | 로컬 설치 소프트웨어 | 직접 컴파일 설치한 바이너리 |
/proc | 실행 중인 프로세스 정보 (가상 FS) | /proc/meminfo, /proc/cpuinfo |
# 각 디렉터리 실제 크기 확인
du -sh /opt /var/log /etc
# /var/log에서 가장 큰 로그 파일 찾기 (디스크 꽉 찰 때 자주 씀)
sudo find /var/log -type f -name "*.log" -exec du -sh {} + | sort -rh | head -10
# /tmp에 오래된 파일 있는지 확인
find /tmp -type f -mtime +7 | wc -l
주의: /tmp는 재부팅 시 자동으로 정리되거나(tmpfs), logrotate/tmpwatch로 주기적으로 정리됩니다. 영구 보관이 필요한 파일은 절대 /tmp에 두지 마세요.

- /opt/ 아래에 설치된 미들웨어(tomcat, nginx 등)가 보이면 수동 설치 환경
- /var/log/ 아래 nginx/, apache2/ 같은 디렉터리가 있으면 해당 서비스 설치된 것
- systemd/system/에 .service 파일이 있으면 재부팅 시에도 자동 시작되는 서비스
파일 권한 — chmod / chown
chmod 숫자 모드 완전 이해
배포 후 서비스가 설정 파일을 읽지 못해 기동에 실패했는데, 파일 권한이 600으로 되어 있어 서비스 계정이 접근하지 못했습니다.
반대로 DB 비밀번호가 담긴 설정 파일에 644를 걸어둔 채 운영했다가 보안 감사에서 적발된 경우도 있습니다. 숫자 하나 차이가 서비스 장애가 되기도 하고 보안 사고가 되기도 합니다. 인프라 엔지니어가 가장 자주 쓰는 권한 값은 5가지입니다. 이것만 외워두면 됩니다.
권한 계산: r=4, w=2, x=1
7 = 4+2+1 = rwx (읽기+쓰기+실행)
6 = 4+2+0 = rw- (읽기+쓰기)
5 = 4+0+1 = r-x (읽기+실행)
4 = 4+0+0 = r-- (읽기 전용)
0 = 0+0+0 = --- (접근 불가)
자주 쓰는 권한 패턴:
# 755: 실행 파일, 디렉터리 표준 (owner: rwx, group/others: r-x)
chmod 755 /opt/tomcat/bin/startup.sh
chmod 755 /opt/app # 디렉터리
# 644: 일반 파일 표준 (owner: rw-, group/others: r--)
chmod 644 /etc/nginx/nginx.conf
# 640: 설정 파일 (비밀번호 포함) — others 읽기 차단
chmod 640 /opt/app/config/database.yml
# 600: 개인 키, 비밀 파일 — owner만 읽기/쓰기
chmod 600 ~/.ssh/id_rsa
chmod 600 /etc/ssl/private/server.key
# 700: 관리자 전용 디렉터리
chmod 700 /opt/app/scripts
# 재귀적으로 적용 (-R 옵션)
chmod -R 755 /opt/tomcat/bin
chmod -R 640 /opt/app/config
# 현재 권한 확인
ls -la /opt/tomcat/bin/startup.sh
# -rwxr-xr-x 1 tomcat tomcat 2573 Jan 15 10:00 /opt/tomcat/bin/startup.sh
# stat으로 상세 확인
stat /opt/tomcat/bin/startup.sh
# Access: (0755/-rwxr-xr-x) Uid: ( 999/ tomcat) Gid: ( 999/ tomcat)
chown으로 소유자/그룹 변경
배포 스크립트가 root 권한으로 WAR 파일을 복사했는데 서비스 계정인 tomcat이 그 파일을 읽지 못해 기동 실패가 났습니다. 파일 소유자는 root인데 실행 주체는 tomcat이었기 때문입니다. 배포할 때마다 이 실수가 반복되는 팀들이 많습니다. chown을 배포 스크립트에 포함시키지 않으면 권한 오류는 반복됩니다.
파일의 소유자(owner)와 그룹(group)을 변경합니다. 배포 후 파일 소유자가 잘못 설정되어 서비스가 파일을 읽지 못하는 경우가 자주 발생합니다.
# 소유자만 변경
chown tomcat /opt/tomcat/webapps/app.war
# 소유자와 그룹 동시 변경
chown tomcat:tomcat /opt/tomcat/webapps/app.war
# 그룹만 변경
chgrp tomcat /opt/tomcat/logs
# 재귀적으로 하위 전체 변경
chown -R tomcat:tomcat /opt/tomcat/webapps
chown -R nginx:nginx /var/log/nginx
# 심볼릭 링크 포함 변경
chown -Rh tomcat:tomcat /opt/tomcat
배포 후 권한 설정 패턴 (실무에서 반복해서 씀):
# WAR 파일 배포 후 소유권 정리
sudo cp /tmp/app-1.2.3.war /opt/tomcat/webapps/app.war
sudo chown tomcat:tomcat /opt/tomcat/webapps/app.war
sudo chmod 644 /opt/tomcat/webapps/app.war
# 설정 파일 배포 후 권한 정리
sudo cp /tmp/application.yml /opt/app/config/
sudo chown appuser:appuser /opt/app/config/application.yml
sudo chmod 640 /opt/app/config/application.yml
- config.yml(640): 소유자 읽기/쓰기, 그룹 읽기만, others 접근 불가 — 설정 파일 표준
- secret.key(600): 소유자만 읽기/쓰기 — SSH 키, DB 패스워드 파일 표준
- deploy.sh(750): 소유자 실행 가능, 그룹 읽기/실행, others 접근 불가 — 실행 스크립트 표준
- stat 명령어로 숫자(a)와 rwx(A) 형식을 동시에 확인 가능
sudo 설정
visudo로 sudo 권한 안전하게 설정
배포 계정에 NOPASSWD: ALL을 걸어줬다가 보안 감사에 걸렸습니다. 모든 명령어를 root 권한으로 실행할 수 있다는 것은 사실상 root 계정을 하나 더 만든 셈이기 때문입니다. 반대로 권한이 너무 좁게 설정되면 배포 스크립트가 실행 중간에 멈춥니다. 어떤 명령어에만 sudo를 허용할지 정확히 지정해야 보안과 운영 편의성을 동시에 잡을 수 있습니다.
/etc/sudoers 파일을 직접 편집하면 문법 오류 시 sudo 전체가 망가집니다. 반드시 visudo를 사용하세요.
# sudoers 파일 편집 (문법 검증 포함)
sudo visudo
# 또는 /etc/sudoers.d/ 에 별도 파일로 관리 (권장)
sudo visudo -f /etc/sudoers.d/deploy
실무에서 자주 쓰는 설정 패턴:
# /etc/sudoers.d/deploy 파일 내용
# deploy 사용자가 비밀번호 없이 서비스 재시작 가능
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart tomcat
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
# ops-admin 그룹은 모든 sudo 가능 (패스워드 필요)
%ops-admin ALL=(ALL) ALL
# 특정 명령어만 허용 (보안 강화)
capistrano ALL=(ALL) NOPASSWD: /bin/cp, /bin/mv, /bin/chown
# 현재 sudo 권한 확인
sudo -l
# sudo로 다른 사용자로 명령 실행
sudo -u tomcat /opt/tomcat/bin/startup.sh
# sudo 이력 확인 (audit 목적)
sudo grep sudo /var/log/auth.log | tail -20 # Ubuntu
sudo grep sudo /var/log/secure | tail -20 # RHEL
주의: NOPASSWD: ALL은 매우 위험합니다. 특정 명령어만 NOPASSWD로 설정하는 것이 원칙입니다.
systemctl 서비스 관리
systemctl 핵심 명령어
서버를 재부팅했더니 Tomcat이 자동으로 뜨지 않았습니다. systemctl enable을 빠뜨렸기 때문입니다. start는 지금 당장 서비스를 켜는 것이고, enable은 부팅 때 자동으로 켜지도록 등록하는 것입니다. 이 차이를 모르면 서버 재시작 후 "서비스가 죽었다"는 알람을 받게 됩니다.
systemd 기반의 현대 Linux에서 서비스 관리는 systemctl로 합니다. service 명령어는 내부적으로 systemctl을 호출하는 wrapper로 더 이상 직접 사용하지 않습니다.
자주 쓰는 systemctl 명령어:
# 서비스 상태 확인
systemctl status nginx
systemctl status tomcat
# 서비스 시작/중지/재시작
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
# 설정 파일 재로드 (재시작 없이 — Nginx에서 자주 씀)
sudo systemctl reload nginx
# 부팅 시 자동 시작 등록 (start와 enable은 독립적)
sudo systemctl enable nginx
sudo systemctl enable --now nginx # enable + start 동시
# 부팅 자동 시작 해제
sudo systemctl disable nginx
# 실행 중인 서비스 목록
systemctl list-units --type=service --state=running
# 실패한 서비스 목록 (장애 시 가장 먼저 확인)
systemctl list-units --type=service --state=failed
# 서비스 로그 확인 (journald)
journalctl -u nginx --since "1 hour ago"
journalctl -u tomcat -n 100 --no-pager # 마지막 100줄
journalctl -u nginx -f # 실시간 팔로우
서비스 상태 해석:
systemctl status nginx
# ● nginx.service - A high performance web server
# Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
# Active: active (running) since Thu 2025-01-15 14:30:00 KST; 2h 30min ago
# Process: 1234 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
# Main PID: 1235 (nginx)
# CGroup: /system.slice/nginx.service
# ├─1235 nginx: master process /usr/sbin/nginx
# └─1236 nginx: worker process
# Loaded 줄: enabled → 부팅 시 자동 시작, disabled → 자동 시작 안 됨
# Active 줄: active(running) → 정상 실행 중
# failed → 시작 실패
# inactive(dead) → 중지 상태
custom systemd service 파일 작성 (자체 앱 등록):
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application Server
After=network.target
[Service]
Type=forking
User=appuser
Group=appuser
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start.sh
ExecStop=/opt/myapp/bin/stop.sh
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
# 새 unit 파일 등록
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
ls -la /opt/myapp/
# drwxr-xr-x 5 appuser appuser 4096 Jan 15 14:30 .
# drwxr-xr-- 3 appuser appuser 4096 Jan 15 14:30 bin
# drwxr-x--- 2 appuser appuser 4096 Jan 15 14:30 config
# drwxr-xr-x 2 appuser appuser 4096 Jan 15 14:30 logs
bin(755): 모든 사용자가 실행 가능config(750): 소유자와 같은 그룹만 읽기 가능logs(755): 모든 사용자가 접근 가능 (로그 수집 에이전트 고려)
실제 업무에서 이 지식이 쓰이는 상황:
파일 권한과 systemctl은 매일 쓰입니다. 특히 배포 직후에는 반드시 확인해야 합니다.
배포 체크리스트 예시:
- WAR/JAR 파일이 올바른 위치에 있는가? (
ls -la /opt/app/webapps/) - 파일 소유자가 서비스 계정인가? (
ls -la) - 설정 파일 권한이 640인가? (비밀번호 노출 방지)
- 서비스가 정상 시작됐는가? (
systemctl status) - 로그에 에러가 없는가? (
journalctl -u servicename -n 50)
"배포했는데 안 됩니다"라는 제보의 절반은 이 체크리스트 중 하나가 빠진 경우입니다.
다음 모듈에서는 실행 중인 서비스의 상태를 프로세스/포트/리소스 관점에서 점검하는 방법을 다룹니다.