htpasswd 생성기: 설치 없이 파일 만들기

Apache나 Nginx로 Basic 인증을 걸려면 "사용자명:해시" 형식의 줄이 담긴 .htpasswd 파일이 있어야 합니다. 이 파일을 만드는 공식 명령어는 htpasswd지만, 서버나 개발 PC에 Apache 관련 패키지가 없어 이 명령어 자체가 없는 경우가 흔합니다.
.htpasswd 한 줄은 비밀번호를 SHA-1이나 SHA-256으로 해시한 값을 정해진 표기법으로 적은 텍스트일 뿐이라, 그 표기법만 알면 명령어 설치 없이도 똑같은 줄을 직접 만들 수 있습니다.
요약 ① .htpasswd 한 줄은
사용자명:해시구조이며, 콜론(:)이 필드를 구분합니다. ②{SHA}는 SHA-1,{SHA256}는 SHA-256으로 비밀번호를 해시한 뒤 그 결과 바이트를 base64로 인코딩한 값 앞에 알고리즘 이름을 붙인 표기입니다. ③ Apache는AuthUserFile, Nginx는auth_basic_user_file지시자로 이 파일 경로를 인증 설정에 연결합니다.
이런 상황에서 막힙니다
배포 전인 스테이징 서버나 아직 공개하면 안 되는 관리자 페이지를, 팀원 몇 명만 들어오도록 Basic 인증으로 잠깐 막아두려는 경우가 흔합니다. Nginx 설정에 auth_basic 두 줄만 추가하면 되니 인증을 거는 것 자체는 간단합니다.
문제는 그 인증에 쓸 .htpasswd 파일입니다. 이 파일을 만드는 htpasswd 명령어는 원래 Apache 배포판(Debian·Ubuntu의 apache2-utils, RHEL 계열의 httpd-tools)에 들어 있는 도구라, Nginx만 설치된 서버나 최소 구성 컨테이너 이미지에는 아예 없는 경우가 많습니다.
이럴 때 새 패키지를 설치하는 것 자체가 배포 파이프라인에 손을 대는 일이라 부담스럽습니다. 필요한 건 파일 한 줄뿐인데, 그 한 줄을 만들자고 패키지를 새로 설치하는 건 배보다 배꼽이 더 큰 셈입니다.
.htpasswd 한 줄을 직접 만드는 방법
.htpasswd 파일은 계정마다 한 줄씩, 사용자명:해시를 줄바꿈으로 나열한 평범한 텍스트 파일입니다. 콜론이 구분자이므로 사용자명 안에는 콜론이 들어갈 수 없고, 공백도 보통 허용되지 않습니다.
{SHA} 표기는 비밀번호를 SHA-1으로 해시한 뒤, 그 원시 바이트를 base64로 인코딩하고 앞에 {SHA}를 붙인 것입니다. openssl이 있으면 명령어 한 줄로 직접 계산할 수 있습니다.
printf '%s' 'test1234' | openssl dgst -sha1 -binary | openssl base64
# m8NFSdVl2VBbKH3gzSCsd74dPyw=
이 값 앞에 {SHA}를 붙이고 사용자명과 콜론으로 이으면 admin:{SHA}m8NFSdVl2VBbKH3gzSCsd74dPyw=가 됩니다. Apache의 htpasswd 명령어에 있는 -s 옵션(SHA-1 해싱)으로 같은 비밀번호를 처리해도 정확히 같은 값이 나옵니다.
{SHA256}도 원리는 같고 다이제스트 알고리즘만 sha256으로 바꾸면 됩니다.
printf '%s' 'test1234' | openssl dgst -sha256 -binary | openssl base64
# k36NX7tIvUlJU2zWW401xCa4DS+DDFwwjizexCKuIkQ=
{SHA256}와 -2 옵션은 다른 표기입니다
htpasswd 명령어의 -2 옵션은 이름이 "SHA-256 해싱"이지만, 실제로는 {SHA256} 표기가 아니라 시스템 crypt() 함수의 SHA-256 형식($5$로 시작하는 문자열)을 만듭니다. 이름은 같아도 결과 형식이 다른 별개의 표기입니다.
그래서 {SHA256}으로 만든 줄이 서버에서 실제로 인증에 통하는지는 Apache·Nginx 버전과 모듈 구성에 따라 달라질 수 있는 부분입니다.
bcrypt는 별도 체계입니다
bcrypt 방식($2y$로 시작)은 이것과 아예 다른 체계입니다. 해시 안에 솔트가 포함돼 있어 같은 비밀번호라도 계산할 때마다 다른 문자열이 나옵니다.
브라우저의 Web Crypto API에는 bcrypt 연산이 없어 직접 계산할 수 없고, htpasswd -B나 openssl passwd -bcrypt 같은 서버 쪽 도구로 만드는 방식입니다.
저희 도구로 확인하기.
사용자명·비밀번호를 입력하면 {SHA}·{SHA256} 해시 htpasswd 라인을 브라우저에서 바로 계산합니다. Web Crypto로만 처리되어 서버 전송이 없습니다.

자주 틀리는 지점
가장 흔한 실수 세 가지는 이렇습니다.
| 실수 | 결과 |
|---|---|
| 사용자명에 공백·콜론 포함 | 콜론이 필드 구분자와 겹쳐 파일 파싱이 깨지거나 의도한 사용자명으로 인식되지 않음 |
| {SHA} 또는 {SHA256} 표기를 서버가 인식하지 못하는 상태로 배포 | 해시 값 자체는 맞게 계산했어도 서버가 그 표기 방식을 못 읽으면 인증이 항상 실패함 |
| bcrypt와 {SHA} 계열을 같은 것으로 착각 | bcrypt는 솔트가 해시 안에 포함돼 매번 다른 문자열이 나오므로, 이미 있는 {SHA} 해시를 bcrypt로 "변환"할 수는 없고 비밀번호부터 다시 해시해야 함 |
이 중 두 번째가 가장 발견하기 어렵습니다. 해시 값을 정확히 계산했는데도 인증이 실패한다면, 대개 접두사 표기를 서버가 못 읽는 경우입니다. 이럴 땐 상대적으로 오래 검증된 {SHA} 표기로 다시 만들어보고, 그래도 안 되면 서버 쪽 인증 모듈 로그를 확인하는 순서가 원인 파악에 도움이 됩니다.
정리
- .htpasswd 한 줄은
사용자명:해시이고, 콜론이 구분자라 사용자명에 공백·콜론을 넣을 수 없습니다. {SHA}는 SHA-1,{SHA256}는 SHA-256 다이제스트의 원시 바이트를 base64로 인코딩한 값 앞에 알고리즘 이름을 붙인 표기입니다.- Apache htpasswd의
-s옵션은{SHA}와 동일한 결과를 내지만,-2옵션이 만드는 "SHA-256"은{SHA256}표기와는 다른 crypt() 형식입니다. - Apache는
AuthUserFile, Nginx는auth_basic_user_file로 파일 경로를 인증 설정에 연결합니다. - bcrypt는 솔트가 포함된 별개 형식이라 {SHA} 계열과 서로 변환할 수 없습니다.
사용자명·비밀번호를 입력하면 {SHA}·{SHA256} 해시 htpasswd 라인을 브라우저에서 바로 계산합니다. Web Crypto로만 처리되어 서버 전송이 없습니다.
자주 묻는 질문
{SHA}와 {SHA256}은 뭐가 다른가요?
비밀번호를 해시하는 알고리즘이 다릅니다. {SHA}는 SHA-1 다이제스트(20바이트)를, {SHA256}는 SHA-256 다이제스트(32바이트)를 각각 base64로 인코딩한 값 앞에 알고리즘 이름을 표기합니다. 두 방식 모두 솔트가 없어 같은 비밀번호를 넣으면 항상 같은 해시가 나옵니다.
bcrypt로는 만들 수 없나요?
이 도구는 브라우저 내장 Web Crypto API(crypto.subtle.digest)로 해시를 계산하는데, 이 API에는 bcrypt 연산이 포함돼 있지 않습니다. 그래서 SHA-1({SHA})과 SHA-256({SHA256}) 두 방식만 제공합니다. bcrypt가 필요하면 htpasswd -B나 openssl passwd -bcrypt 같은 서버 쪽 도구를 사용해야 합니다.
입력한 비밀번호가 서버로 전송되나요?
아닙니다. 해시 계산은 전부 브라우저 안에서 이뤄지고, 사용자명·비밀번호는 어디로도 전송되거나 저장되지 않습니다.
만든 .htpasswd 파일을 서버에 어떻게 연결하나요?
Apache는 설정에 AuthType Basic, AuthUserFile /경로/.htpasswd, Require valid-user를 넣습니다. Nginx는 auth_basic "문구";로 인증창에 표시할 문구를, auth_basic_user_file /경로/.htpasswd;로 파일 경로를 지정합니다. 두 경우 모두 파일 안 각 줄이 사용자명:해시 형식이어야 합니다.
