Node.js용 Linux 서버 보안 설정 방법 (초보자 친화적, 단계별)

발행: (2025년 12월 15일 오후 06:51 GMT+9)
7 min read
원문: Dev.to

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/noderoot 소유

왜 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 기반을 갖추었습니다.

행복한 배포 🚀

올바른 서버 하드닝에 오신 것을 환영합니다.

Back to Blog

관련 글

더 보기 »