본문 바로가기
Q&A해결2026년 8월 6일1분 읽기

systemd로 노드 앱 띄우니 80포트에서 EACCES 나는데 루트로 돌리기는 찜찜해요

s
systemd_narae
조회 629댓글 2

우분투 서버에서 노드(express) 앱을 systemd 서비스로 등록해서 80포트로 직접 서빙하려는데, 서비스 시작하면 바로 죽습니다. journalctl 보니 이거네요.

Error: listen EACCES: permission denied 0.0.0.0:80
    at Server.setupListenHandle [as _listen2] (node:net:...)

3000포트로 하면 잘 뜹니다. 1024 이하 포트라 권한 문제인 건 알겠는데, User=를 root로 바꾸면 되긴 하더라고요. 근데 앱을 루트로 돌리는 게 영 찜찜해서요. 더 나은 방법이 있을까요?

댓글 2

김김영삼2개월 전
루트로 돌리는 건 안 하시는 게 맞아요. 1024 미만은 리눅스에서 특권 포트라 원래 루트나 그에 준하는 권한이 필요한 건데, 앱 전체를 루트로 올리는 대신 '그 포트에 바인딩하는 권한'만 딱 줄 수 있어요.

systemd 유닛 파일 [Service] 섹션에 이 두 줄 넣으세요.

AmbientCapabilities=CAP_NET_BIND_SERVICE
User=nodeapp

CAP_NET_BIND_SERVICE가 딱 '1024 미만 포트에 바인딩 가능' 능력만 주는 캐패빌리티라, 앱은 일반 유저(nodeapp)로 돌면서 80만 열 수 있게 됩니다. 루트 권한 나머지는 안 갖고요. 수정하고 systemctl daemon-reload 후 재시작하면 EACCES 사라져요.

참고로 setcap으로 노드 바이너리 자체에 캐패빌리티 박는 방법도 도는데, 그건 그 노드로 실행되는 모든 스크립트가 그 권한을 갖게 돼서 추천 안 해요. 그리고 실무에선 보통 앱은 그냥 3000에 두고 앞에 nginx를 리버스프록시로 세워서 80/443을 nginx가 받게 합니다. 어차피 TLS 종료나 정적파일 서빙 때문에 nginx 둘 거면 그게 제일 깔끔해요. 지금처럼 앱 단독이면 AmbientCapabilities가 간단합니다.
ssystemd_narae(guest)2개월 전
AmbientCapabilities 한 줄로 해결됐네요. 나중에 https 붙일 때 nginx 앞단도 고려해볼게요. 덕분에 루트 안 쓰고 됐습니다 감사해요!
Ctrl+Enter로 등록