Node.js용 Linux 서버 보안 설정 방법 (초보자 친화적, 단계별)
Source: Dev.to
🧠 보안 철학 (간단 설명)
우리는 세 가지 기본 규칙을 따릅니다:
- 앱을 루트로 실행하지 않기
- 각 앱마다 별도의 사용자를 만들기
- 앱은 자신의 파일만 접근하도록 하기
공격자가 앱에 침투하더라도 다음과 같은 행동을 할 수 없어야 합니다:
- 암호화 채굴기 설치
- 시스템 파일 수정
- 사용자 추가
- 다른 앱에 영향 주기
가정 사항
- Ubuntu 22.04 / 24.04
- 서버에 SSH 접속 가능
root계정으로 시작 (새 클라우드 서버)
Step 1: 비루트 관리자 사용자 만들기
본인용 일반 사용자를 생성합니다 (예: dev).
adduser dev
강력한 비밀번호를 설정한 뒤, 루트로 로그인하지 않고 시스템을 관리할 수 있도록 합니다:
usermod -aG sudo dev
왜?
- 루트 SSH 접근은 위험합니다
- 일반 사용자 + sudo 조합이 더 안전하고 감사 가능
Step 2: SSH 키 로그인 설정
로컬 머신에서 SSH 키를 생성합니다 (키가 없을 경우):
ssh-keygen -t ed25519
공개 키를 서버에 복사합니다:
mkdir -p /home/dev/.ssh
nano /home/dev/.ssh/authorized_keys # 여기서 공개 키를 붙여넣기
권한을 수정합니다:
chown -R dev:dev /home/dev/.ssh
chmod 700 /home/dev/.ssh
chmod 600 /home/dev/.ssh/authorized_keys
컴퓨터에서 테스트합니다:
ssh dev@YOUR_SERVER_IP
작동한다면 계속 진행해도 됩니다.
Step 3: SSH 잠금 (매우 중요)
SSH 설정 파일을 편집합니다:
sudo nano /etc/ssh/sshd_config
다음 라인들이 주석 처리되지 않았는지 확인합니다:
PermitRootLogin no
PubkeyAuthentication yes
파일 하단에 다음을 추가합니다:
Match all
PasswordAuthentication no
SSH를 안전하게 재로드합니다:
sudo systemctl reload ssh
이것이 하는 일
- 루트 SSH 로그인 ❌ 비활성화
- 비밀번호 로그인 ❌ 비활성화
- SSH 키 ✅ 필수
💡 클라우드 복구 콘솔은 여전히 작동하므로 잠기지 않습니다.
Step 4: 방화벽 활성화
활성화하기 전에 필요한 포트를 허용합니다:
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
방화벽을 켭니다:
sudo ufw enable
상태를 확인합니다:
sudo ufw status verbose
왜?
- 무작위 인터넷 스캔 차단
- 명시적으로 허용한 것만 열림
Step 5: Node.js 설치 (시스템 전역)
공식 저장소를 이용해 Node.js를 설치합니다 (예: Node 24 LTS):
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
확인:
node -v
which node
예상 출력:
/usr/bin/node가root소유
왜 nvm을 쓰지 않을까?
- 시스템 서비스(systemd)는 nvm과 잘 맞지 않음
- 루트 소유 Node가 더 안전하고 예측 가능
Step 6: 전용 앱 사용자 만들기
관리자 계정으로 앱을 실행하지 마세요. 서비스 사용자를 생성합니다 (예: svc-nextjs):
sudo adduser \
--system \
--no-create-home \
--group \
--shell /usr/sbin/nologin \
svc-nextjs
의미
- SSH 접근 불가
- 쉘 없음
- sudo 없음
- 오직 앱 실행만을 위해 존재
Step 7: 앱 파일 격리
앱용 디렉터리를 만듭니다:
sudo mkdir -p /var/apps/nextjs
sudo chown -R svc-nextjs:svc-nextjs /var/apps/nextjs
sudo chmod 750 /var/apps/nextjs
관리자 계정으로 테스트 (실패해야 함):
cd /var/apps/nextjs
서비스 사용자로 테스트 (성공해야 함):
sudo -u svc-nextjs ls /var/apps/nextjs
Step 8: systemd 로 앱 실행 (보안 강화)
서비스 파일을 생성합니다:
sudo nano /etc/systemd/system/nextjs.service
다음 내용을 붙여넣습니다:
[Unit]
Description=Next.js Application (Hardened)
After=network.target
[Service]
Type=simple
User=svc-nextjs
Group=svc-nextjs
WorkingDirectory=/var/apps/nextjs
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=3
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/apps/nextjs
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
RestrictNamespaces=true
LockPersonality=true
MemoryDenyWriteExecute=true
CapabilityBoundingSet=
AmbientCapabilities=
UMask=0077
[Install]
WantedBy=multi-user.target
systemd를 재로드합니다:
sudo systemctl daemon-reload
Step 9: 보안 점수 확인
실행:
systemd-analyze security nextjs.service
점수가 2–3 정도면 웹 서비스에 아주 좋습니다.
이것이 방어하는 대상
- 권한 상승
- 시스템 파일 수정
- 커널 악용
- 암호화 채굴기
- 횡 이동
앱이 해킹당하더라도 OS는 안전합니다.
Step 10: 최종 점검
SSH 설정을 확인합니다:
sudo sshd -T | egrep 'permitrootlogin|passwordauthentication|pubkeyauthentication'
예상 출력:
permitrootlogin no
passwordauthentication no
pubkeyauthentication yes
방화벽 상태 확인:
sudo ufw status
달성한 내용
- ✅ 루트 SSH 비활성화
- ✅ 비밀번호 로그인 비활성화
- ✅ 키 전용 접근
- ✅ 방화벽 활성화
- ✅ 앱당 서비스 사용자
- ✅ 파일 시스템 격리
- ✅ 강력한 systemd 샌드박스
이는 실제 운영 환경 보안이며 이론에 그치지 않습니다.
최종 조언
- 하나의 앱 = 하나의 서비스 사용자
- 절대 루트로 앱 실행 금지
- systemd가 보안을 강제하도록 함
- SSH는 단순하고 잠궈두기
이제 Node.js, Python, 혹은 어떤 백엔드 서비스든 안전한 Linux 기반을 갖추었습니다.
행복한 배포 🚀
올바른 서버 하드닝에 오신 것을 환영합니다.