서버에 파일을 올렸더니 Permission denied, 구글링하면 일단 chmod 777 하라는 답이 먼저 보이죠. 저도 처음엔 그렇게 넘어갔는데, 나중에 보니 그게 제일 위험한 해결책이더라고요. 결론부터 말하면 chmod 755 는 rwxr-xr-x(소유자는 전부, 나머지는 읽기·실행), 644 는 rw-r--r--(소유자만 쓰기, 나머지는 읽기)예요. 숫자는 읽기 r=4, 쓰기 w=2, 실행 x=1을 더한 값을 소유자·그룹·기타 순서로 세 자리 적은 8진수이고, 보통 디렉터리와 실행 파일은 755, 일반 파일은 644, 비밀 파일은 600이 기본이에요.
이 글에서는 ls -l 에 보이는 -rwxr-xr-x 를 읽는 법, 숫자 계산법, 자주 쓰는 권한 값과 쓰임새, 파일과 디렉터리에서 r·w·x가 다르게 동작하는 부분, 새 파일의 기본 권한을 정하는 umask, setuid·setgid·sticky bit 같은 특수 권한, 그리고 777이 왜 위험하고 대신 무엇을 해야 하는지 정리할게요. 숫자와 rwx를 바로 바꿔 보고 싶다면 chmod 계산기를 같이 열어 두세요.
핵심 요약
권한은 소유자(u)·그룹(g)·기타(o) 세 묶음이고, 각각 r=4·w=2·x=1을 더해 한 자리 숫자로 적어요. 7=rwx, 6=rw-, 5=r-x, 4=r--.
755는 디렉터리·스크립트, 644는 일반 파일, 600은 SSH 키·비밀 설정, 700은 개인 디렉터리에 써요.
디렉터리의 x는 "실행"이 아니라 "안으로 들어가 파일에 접근할 권한"이고, 파일 삭제 여부는 파일이 아니라 디렉터리의 w로 정해져요.
777은 누구나 고칠 수 있다는 뜻이에요. 권한 문제는 대부분 소유자(chown)나 그룹을 맞추는 게 정답이에요.
ls -l의 rwxr-xr-x 읽는 법
ls -l 을 치면 맨 앞에 10글자짜리 권한 문자열이 나와요.
-rwxr-xr-x 1 smith staff 1204 Oct 15 09:30 deploy.sh
drwxr-xr-x 5 smith staff 160 Oct 15 09:31 public
첫 글자는 파일 종류예요. - 는 일반 파일, d 는 디렉터리, l 은 심볼릭 링크예요. 나머지 9글자를 3글자씩 끊으면 소유자(user) · 그룹(group) · 기타(other) 의 권한이에요. 각 묶음은 항상 r, w, x 순서이고, 없는 권한은 - 로 비워요.
| 위치 | 대상 | deploy.sh 의 값 | 의미 |
|---|---|---|---|
| 2~4번째 | 소유자 (smith) | rwx | 읽기·쓰기·실행 |
| 5~7번째 | 그룹 (staff) | r-x | 읽기·실행 |
| 8~10번째 | 기타 (그 외 모두) | r-x | 읽기·실행 |
리눅스는 접근하는 사람이 소유자면 소유자 칸만, 소유자가 아니고 그룹 소속이면 그룹 칸만, 둘 다 아니면 기타 칸만 봐요. 위에서부터 하나만 골라 적용하는 거라서, 소유자 칸이 --- 이고 기타 칸이 rwx 라면 소유자 본인은 접근이 안 되는 이상한 상황도 생길 수 있어요. 단, root는 읽기·쓰기 검사를 건너뛰어요.
chmod 숫자 계산법: r=4, w=2, x=1
권한 숫자는 각 묶음의 3비트를 8진수 한 자리로 적은 거예요. 3비트는 0~7을 표현하니까 8진수 한 자리와 딱 맞아요.
| 숫자 | 2진수 | 문자 | 계산 |
|---|---|---|---|
| 7 | 111 | rwx | 4 + 2 + 1 |
| 6 | 110 | rw- | 4 + 2 |
| 5 | 101 | r-x | 4 + 1 |
| 4 | 100 | r-- | 4 |
| 3 | 011 | -wx | 2 + 1 (거의 안 씀) |
| 2 | 010 | -w- | 2 (거의 안 씀) |
| 1 | 001 | --x | 1 |
| 0 | 000 | --- | 없음 |
그래서 rwxr-xr-x 는 rwx(7) · r-x(5) · r-x(5) = 755, rw-r----- 는 rw-(6) · r--(4) · ---(0) = 640이에요. 거꾸로 숫자를 문자로 바꿀 땐 각 자리에서 4, 2, 1을 차례로 빼 보면 돼요. 6이면 4를 빼고(r) 2를 빼면(w) 0이 되니까 rw- 예요.
755를 10진수로 읽으면 493이에요
권한 숫자는 8진수라서 10진수로 바꾸면 전혀 다른 값이 돼요. 이게 코드에서 실제로 사고가 나는 지점이에요. 파이썬에서 os.chmod(path, 755) 라고 쓰면 10진수 755(= 8진수 1363)가 들어가서 엉뚱한 권한이 걸려요. 반드시 0o755 처럼 8진수 접두어를 붙이고, Node.js도 fs.chmodSync(path, 0o755) 또는 문자열 '755' 로 넘겨야 해요. 진법 변환 원리는 2진수 16진수 변환 원리 글에서 자세히 다뤘어요.
기호 모드: u+x, g-w, o=r
숫자 대신 기호로도 쓸 수 있어요. 대상은 u(소유자), g(그룹), o(기타), a(모두), 연산은 +(추가), -(제거), =(정확히 이것만)이에요.
chmod u+x deploy.sh # 소유자에게 실행 추가 (나머지는 그대로)
chmod go-w config.yml # 그룹·기타의 쓰기 제거
chmod a=r notice.txt # 모두 읽기만 (444)
chmod u=rw,go= .env # 600과 같음
기호 모드의 장점은 다른 비트를 건드리지 않는다는 거예요. 실행 권한만 하나 추가하고 싶을 때 숫자로 덮어쓰면 기존 권한을 잘못 지울 수 있지만, u+x 는 그 비트 하나만 바꿔요.
자주 쓰는 권한 값 755 644 600 700
| 권한 | 문자 | 주로 쓰는 곳 |
|---|---|---|
| 755 | rwxr-xr-x | 디렉터리, 실행 스크립트, 웹 루트 폴더 |
| 644 | rw-r--r-- | HTML·CSS·이미지, 일반 설정 파일 |
| 600 | rw------- | SSH 개인 키, .env, DB 비밀번호가 든 설정 |
| 700 | rwx------ | ~/.ssh 디렉터리, 개인 스크립트 폴더 |
| 750 | rwxr-x--- | 같은 그룹만 들어가야 하는 앱 디렉터리 |
| 640 | rw-r----- | 웹 서버 그룹이 읽어야 하는 비밀 설정 |
| 775 / 664 | rwxrwxr-x / rw-rw-r-- | 팀이 같은 그룹으로 함께 쓰는 공유 폴더 |
| 444 / 400 | r--r--r-- / r-------- | 실수로 고치면 안 되는 파일 |
SSH는 권한을 엄격히 검사해요. 개인 키가 644 처럼 다른 사람이 읽을 수 있으면 UNPROTECTED PRIVATE KEY FILE! 경고와 함께 키 사용을 거부하니, 개인 키는 600, ~/.ssh 는 700 으로 맞춰 두세요.
디렉터리에서 r, w, x는 뜻이 달라요
파일의 r·w·x는 이름 그대로인데, 디렉터리에서는 의미가 달라서 여기서 많이 헷갈려요. 디렉터리는 "파일 이름 목록"이 든 특수한 파일이라고 생각하면 이해가 쉬워요.
| 권한 | 파일에서 | 디렉터리에서 |
|---|---|---|
| r | 내용 읽기 | 안에 있는 이름 목록 보기 (ls) |
| w | 내용 수정 | 안의 파일 생성·삭제·이름 변경 (x도 필요) |
| x | 프로그램으로 실행 | 안으로 들어가기(cd), 이름으로 파일에 접근 |
그래서 이런 일이 생겨요.
- r만 있고 x가 없으면
ls로 이름은 보이는데 파일을 열 수 없고,ls -l하면 크기·권한이?로 나와요. - x만 있고 r이 없으면 목록은 못 보지만 정확한 이름을 알면 파일을 열 수 있어요.
- 파일 삭제는 디렉터리 권한으로 정해져요. 파일이
444여도 디렉터리에 w와 x가 있으면 지울 수 있어요. 반대로 파일이777이어도 디렉터리에 w가 없으면 못 지워요. - 경로의 모든 상위 디렉터리에 x가 있어야 해요.
/home/smith/public/index.html이 644여도/home/smith가 700이면 웹 서버는 파일에 닿지 못하고 403을 내요.
chmod -R 755를 조심하세요
폴더 전체를 chmod -R 755 로 바꾸면 안에 있는 일반 파일까지 전부 실행 가능해져요. 디렉터리와 파일을 나눠서 바꾸는 게 맞아요. 대문자 X 는 "디렉터리이거나 이미 누군가에게 실행 권한이 있는 파일에만 x를 붙이라"는 뜻이라 한 줄로도 처리돼요.
find ./site -type d -exec chmod 755 {} +
find ./site -type f -exec chmod 644 {} +
# 또는
chmod -R u=rwX,go=rX ./site
umask 022, 새 파일의 기본 권한이 정해지는 방식
새로 만든 파일이 왜 644 이고 디렉터리는 755 인지는 umask가 정해요. 기본값은 파일 666, 디렉터리 777 에서 출발하고, umask에 켜진 비트를 꺼요. 파일은 출발점부터 x가 없어서, 새로 만든 스크립트에 chmod +x 를 따로 해 줘야 하는 거예요.
| umask | 새 파일 | 새 디렉터리 | 쓰임 |
|---|---|---|---|
| 022 | 644 | 755 | 대부분 배포판 기본값 |
| 002 | 664 | 775 | 사용자별 개인 그룹을 쓰는 배포판, 팀 공유 |
| 027 | 640 | 750 | 기타 사용자 차단이 필요한 서버 |
| 077 | 600 | 700 | 개인 비밀 파일 작업 |
umask는 빼기가 아니라 비트를 끄는 연산이에요. umask가 033 이면 666 − 033 = 633이 아니라, 666에서 033에 켜진 비트(그룹·기타의 w와 x)를 끈 644가 돼요. 원래 없던 x 비트는 끌 것도 없기 때문이죠. 현재 값은 umask 명령으로 확인하고, 셸에서 바꾸면 그 세션에서만 적용돼요.
setuid, setgid, sticky bit 특수 권한
세 자리 앞에 한 자리를 더 붙이면 특수 권한이에요. 4는 setuid, 2는 setgid, 1은 sticky bit예요.
| 특수 권한 | 숫자 | 표시 위치 | 효과 | 대표 예 |
|---|---|---|---|---|
| setuid | 4000 | 소유자 x 자리에 s | 실행하는 사람이 아니라 파일 소유자 권한으로 실행 | /usr/bin/passwd (-rwsr-xr-x, 4755) |
| setgid | 2000 | 그룹 x 자리에 s | 파일: 소유 그룹 권한으로 실행. 디렉터리: 안에 만든 파일이 디렉터리 그룹을 물려받음 | 팀 공유 폴더 2775 |
| sticky | 1000 | 기타 x 자리에 t | 디렉터리 안 파일을 소유자만 삭제·이름 변경 | /tmp (drwxrwxrwt, 1777) |
passwd 는 일반 사용자가 실행해도 root만 쓸 수 있는 비밀번호 파일을 고쳐야 해서 setuid가 붙어 있어요. 그만큼 setuid 파일에 버그가 있으면 바로 root 권한 탈취로 이어져서, 보안 점검 때 find / -perm -4000 으로 목록을 확인하는 게 기본이에요. 리눅스는 셸 스크립트의 setuid를 무시하니, 스크립트에 붙여도 효과가 없어요.
/tmp 는 누구나 쓸 수 있어야 하지만 남의 파일을 지우면 안 되니 sticky bit가 붙어 있어요. 표시가 대문자 S 나 T 로 보이면 특수 비트는 켜졌는데 그 자리의 x가 없다는 뜻이에요.
chmod 777이 위험한 이유와 대신 할 것
777 은 서버의 모든 사용자와 모든 프로세스가 그 파일을 읽고, 고치고, 실행할 수 있다는 뜻이에요. 문제가 되는 장면은 이래요.
- 웹 업로드 폴더가 777이면 취약한 플러그인 하나로 올라온 악성 스크립트가 그대로 실행될 수 있어요.
- 크론이 root로 실행하는 스크립트가 777이면 일반 계정 하나만 뚫려도 그 스크립트를 고쳐 root 권한을 얻어요.
- 홈 디렉터리나
~/.ssh가 다른 사람에게 쓰기 가능하면 sshd가 키 인증을 거부해서 오히려 로그인이 막혀요.
Permission denied 가 나면 777 대신 이렇게 확인해 보세요.
ls -l과id로 파일 소유자와 지금 실행하는 사용자가 누구인지 봐요. 웹 서버는 보통www-data나nginx로 돌아요.- 소유자가 다르면
chown으로 소유자를 맞추거나, 공통 그룹을 만들어chgrp후775/664를 줘요. - 경로상 상위 디렉터리에 x가 다 있는지
namei -l /경로/파일로 한 번에 확인해요. - 도커 볼륨이라면 컨테이너 안 사용자 UID와 호스트 파일 UID가 맞는지 확인해요. 777이 제일 많이 등장하는 곳이 여기예요.
참고로 Git은 권한 중 실행 비트 하나만 기록해요(파일 모드 100755 또는 100644). 그래서 저장소에서 받은 파일이 600이나 777로 오지는 않고, 스크립트 실행 권한은 git update-index --chmod=+x 파일 로 커밋할 수 있어요.
자주 묻는 질문
chmod 755와 644 중 무엇을 써야 하나요?
실행하거나 들어가야 하는 것(디렉터리, 셸 스크립트, 바이너리)은 755, 읽기만 하면 되는 것(HTML, 이미지, 설정 파일)은 644예요. 일반 파일에 755를 주면 실행 권한이 불필요하게 열려요.
현재 권한을 숫자로 보려면 어떻게 하나요?
리눅스는 stat -c '%a %n' 파일, macOS는 stat -f '%Lp %N' 파일 로 755 같은 숫자를 바로 볼 수 있어요. ls -l 의 문자를 4·2·1로 더해 직접 계산해도 돼요.
파일 권한이 444인데 삭제가 돼요. 왜 그런가요?
삭제는 파일 내용이 아니라 디렉터리의 이름 목록을 고치는 일이라서, 파일이 아니라 디렉터리의 w·x 권한으로 정해져요. 남이 지우지 못하게 하려면 디렉터리에 sticky bit를 걸거나 디렉터리 쓰기 권한을 막아야 해요.
chmod 4755처럼 네 자리는 무슨 뜻인가요?
맨 앞자리는 특수 권한이에요. 4는 setuid, 2는 setgid, 1은 sticky bit이고, 뒤 세 자리는 일반 권한이에요. 4755는 setuid가 걸린 rwxr-xr-x라서 ls -l 에 -rwsr-xr-x 로 보여요.
심볼릭 링크의 권한은 왜 항상 rwxrwxrwx인가요?
리눅스에서 심볼릭 링크 자체의 권한은 쓰이지 않고, 실제 접근은 링크가 가리키는 대상 파일의 권한으로 검사해요. 그래서 링크에 chmod를 하면 링크가 아니라 대상 파일의 권한이 바뀌어요.
정리
chmod 숫자는 r=4·w=2·x=1을 더한 값을 소유자·그룹·기타 순으로 적은 8진수예요. 755(rwxr-xr-x)는 디렉터리와 실행 파일, 644(rw-r--r--)는 일반 파일, 600·700은 SSH 키와 비밀 파일에 쓰는 게 기본이에요. 디렉터리의 x는 통과 권한이고 파일 삭제는 디렉터리의 w로 정해지며, 새 파일 권한은 umask(보통 022)가 비트를 꺼서 만들어요.
Permission denied 를 777로 덮지 말고 소유자와 그룹부터 맞추세요. rwx 체크박스로 숫자를 만들거나 반대로 풀어 보려면 chmod 계산기를, 8진수·2진수 자체가 헷갈리면 진법 변환기를 써 보세요. 크론으로 스크립트를 돌릴 때 권한과 함께 자주 막히는 부분은 크론 표현식 읽는 법 글에 정리해 두었어요.