우분투 서버를 설치하고 나면 빈 도화지가 주어진다. 문제는 이 도화지가 인터넷에 연결된 순간부터 공격 대상이라는 것이다. 외부에 노출된 SSH 포트에는 자동화된 로그인 시도가 쉴 새 없이 들어온다. 서비스를 올리기 전에 기초 공사부터 하자. 아래 5단계는 순서대로 진행해야 한다 — 순서를 바꾸면 스스로 서버에서 잠기는 사고가 난다.
전체 과정의 공식 레퍼런스는 우분투 서버 공식 문서다.
1단계 — 작업용 sudo 사용자 만들기
root로 일상 작업을 하지 않는다. 실수 한 번의 피해 범위가 다르다.
adduser jungho
usermod -aG sudo jungho
이후 모든 작업은 이 계정으로 하고, 관리 명령만 sudo를 붙인다.
2단계 — SSH 키 인증 전환
비밀번호 인증은 무차별 대입 공격의 표적이다. 키 인증으로 바꾼다. 내 PC에서:
ssh-keygen -t ed25519
ssh-copy-id jungho@서버IP
키로 로그인되는 것을 확인한 뒤, 서버의 /etc/ssh/sshd_config에서 비밀번호 인증을 끈다.
PasswordAuthentication no
PermitRootLogin no
sudo systemctl restart ssh 후 기존 터미널을 끊지 말고 새 터미널에서 접속 테스트를 한다. 이 습관이 중요하다 — 설정이 잘못됐을 때 돌아갈 문을 남겨두는 것이다.
3단계 — ufw 방화벽: 필요한 것만 연다
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose
기본 정책은 “들어오는 것 모두 차단, SSH만 허용”이 된다. 이후 서비스를 추가할 때마다 해당 포트만 명시적으로 연다. 주의: ufw enable 전에 반드시 SSH 허용 규칙부터 넣어야 한다. 순서가 바뀌면 원격 접속이 그 자리에서 끊긴다.
4단계 — 자동 보안 업데이트
홈서버는 매일 들여다보는 기계가 아니다. 보안 패치만큼은 사람 손을 거치지 않고 적용되게 한다. 우분투의 unattended-upgrades가 이 역할을 한다 (공식 안내).
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
기본 설정은 보안 업데이트만 자동 적용한다. 일반 패키지 업그레이드까지 자동화하면 서비스 호환성이 깨질 수 있어, 보안 패치만 자동으로 두는 것이 홈서버에서는 균형점이다.
5단계 — 시간 동기화와 로그 한도
사소해 보이지만 나중에 효자가 되는 두 가지다.
- 시간 동기화 확인:
timedatectl명령으로 NTP 동기화 상태(System clock synchronized: yes)와 시간대(Asia/Seoul)를 확인한다. 시간이 어긋나면 크론 작업 시각과 로그 타임스탬프가 전부 미덥지 않게 된다. - 저널 로그 용량 제한: systemd 저널은 방치하면 수 GB까지 자란다.
/etc/systemd/journald.conf에서SystemMaxUse=500M정도로 한도를 정해두면 “디스크가 꽉 찼는데 범인이 로그”인 상황을 예방한다.
보너스 — 서버의 내부 IP 고정
초기 설정에서 자주 빠뜨리는 것이 서버의 내부 IP 고정이다. 공유기의 DHCP가 서버 IP를 어느 날 바꿔버리면, 포트포워딩·NFS 마운트·북마크가 한꺼번에 깨진다. 방법은 두 가지인데, 서버 쪽에서 정적 IP를 설정하는 것보다 공유기의 DHCP 주소 예약(MAC 주소에 IP 고정 할당)을 쓰는 쪽을 권한다. 설정이 공유기 한 곳에 모여 있어 관리가 쉽고, 서버를 재설치해도 IP가 유지되기 때문이다.
같은 김에 호스트네임도 정해두자. sudo hostnamectl set-hostname myserver 한 줄이면 되고, 이후 로그·알림·SSH 설정 어디서든 “어느 장비 이야기인지”가 명확해진다. 장비가 한 대일 때는 사소해 보여도, NAS와 서버를 함께 운영하기 시작하면 이름의 가치를 알게 된다.
마무리 점검표
| 항목 | 확인 명령 | 기대 결과 |
|---|---|---|
| sudo 사용자 | groups jungho | sudo 포함 |
| 키 인증 전용 | sudo sshd -T | grep passwordauth | no |
| 방화벽 | sudo ufw status | active, SSH만 허용 |
| 자동 업데이트 | systemctl status unattended-upgrades | active |
| 시간 동기화 | timedatectl | synchronized: yes |
고백하자면, 위 점검표로 지금 이 서버를 검사하면 방화벽 줄에서 걸린다 — ufw가 inactive다. 게으름이 아니라 선택인데, 이 서버는 공유기에서 인터넷으로 열어둔 포트가 WireGuard용 UDP 단 하나(SSH 포함 나머지는 0개)이고, WireGuard는 유효한 키 없이 온 패킷에는 응답조차 하지 않는 설계라 바깥에서 보이는 문 자체가 없기 때문이다. 물론 이것은 “집 안 네트워크는 믿는다”는 가정 위의 균형이라, SSH가 인터넷에 노출되는 구성이라면 2·3단계는 타협 없이 본문 순서대로가 맞다. 이 구조에서 굳어진 습관이 하나 있다. 새 서비스를 올릴 때 “몇 번 포트를 열까”가 아니라 “이게 인터넷에서 보일 필요가 있나”부터 묻는 것 — 답이 ‘아니오’인 한, 방화벽 규칙을 늘리는 것보다 노출 자체를 만들지 않는 구조가 먼저다.
여기까지가 모든 서비스의 공통 기반이다. 다음 글에서는 이 위에 도커 컴포즈로 서비스를 올리는 구조를 다룬다. 외부에서 서버에 접속할 일이 있다면 VPN과 포트포워딩 비교를 먼저 읽어보길 권한다.