이 글은 한국디지털미디어고등학교 2학기 공업일반 수행평가를 위한 글이다.
2학기 주제는 필자가 가지고 있는 서버들을 관리하는 것을 주된 주제로 삼고, 서버를 관리하기 위한 여러 방법들과 실제 겪은 시행착오들을 중심으로 글을 적어볼 예정이다.
나는 왜 서버를 운영하는가
필자는 현재 디미고 내부 서비스(페이, 인트라넷, 위키) 등을 운영하고 있다. 그럼 이러한 서비스는 어느 컴퓨터에서 실행되고 있는가? 그것이 바로 서버이다.
서비스를 운영하기 위해서 서버는 필수적인 요소이다. 호스팅 서비스를 사용하고 있다 하더라도 그것 또한 서버의 일부분을 빌려 운영하는 것이기에 서버이다.
서버는 필자처럼 서비스를 운영하기 위해 운영하는 경우도 있고, NAS 등 클라우드 환경을 만들기 위해, 다른 서버를 관리하거나 로그를 분석하기 위해서 사용하는 경우도 있다.
그럼 서버는 일반 컴퓨터와는 무엇이 다를까? 작은 미니 PC나 개인 PC로도 서버를 운영할 수 도 있지만, 일반적인 서버의 특징으로는 24시간 쉬지않고 돌아가며 서비스의 가용성을 유지해야 하기 때문에 매우 비싸고 내구성이 뛰어난 장비들로 구성되어있다는 특징이 있을 것이다. 나머지는 일반적인 컴퓨터와 크게 다를 것은 없다.
서버 사양과 구성 소개
필자는 다음과 같은 3개의 서버를 직접 운영하고 있다.
| 번호 | CPU | MEM | 호스팅 | 방화벽 |
|---|---|---|---|---|
| 1 | Intel Xeon 6Core | 12GB | X | X |
| 2 | 1vcpu | 1GB | Oracle Cloud Infrastructure | O |
| 3 | 2vcpu | 2GB | Digital Ocean | O |
1번 서버는 실제 서버실 랙 장비에 장착하여 운영하고 있다. 항온항습기도 갖춘 제대로 된 서버실에서 돌아가고 있기 때문에 자체 운영이어도 큰 걱정은 없다.
이와 달리 2, 3번 서버는 호스팅 서비스를 이용해서 서버의 일부분을 빌려 사용하고 있다. Oracle Cloud Infrastructure(OCI)와 Digital Ocean은 가격도 없거나 저렴해서 필자가 서버를 사용하는데 큰 도움을 주고있다. 호스팅 서비스의 장점은 방화벽이나 네트워크 구성등을 연계된 대규모 서비스들을 이용해서 내 입맛대로 구성할 수 있다는 점에 있을 것이다.
그럼 방화벽을 따로 구성하지 않은 1번 서비스는 위험한 것인가? 모든 서버에서는 웹서비스를 운영하고 있으며, 서버 앞단에 Cloudflare 프록시를 달아서 운영중이기 때문에 어느정도 대규모 공격은 Cloudflare에서 알아서 차단해준다.
물론 Cloudflare를 거치지 않고 IP를 통해 바로 들어오는 요청에 대한 차단은 어렵긴 하다. 이는 Ufw 같은 OS 방화벽으로 별도의 보완이 필요하다. Cloudflare는 방화벽이 없는 환경에서 공격 부담을 줄여주는 도구인 것이다.
서버 OS 선택

서버에 들어갈 OS를 고르는건 이후 구축 과정을 어떻게 가져갈 것인가, 어떤 서비스를 운영할 것인가 등을 종합적으로 고려해서 진행된다.
요즘은 대부분은 Linux 계열의 서버를 많이 선호하는 분위기다. OS 자체도 다루기 쉽고, 높은 확장성을 제공하기 때문이다.
필자도 현재 모든 서버를 Linux의 배포판인 Ubuntu를 이용해서 운영중에 있다. Ubuntu는 Debian 기반의 Linux 배포판으로, 초보자도 쉽게 사용할 수 있을 만큼 설치와 운용이 어렵지 않다.
여담으로 우리나라의 오래된 서비스나 기업에서는 윈도우 서버를 쓰는 경우를 종종 볼 수 있다.
서버 초기 세팅
필자는 서버 세팅 과정에서 가장 먼저 하는 것은 SSH를 설정하는 것이다.
서버를 수정하거나 새로운 배포를 올릴 때 매번 서버실에 가서 작업하는 것은 여간 귀찮은 일이 아닐 수 없다.
이를 해결하기 위해 원격에서도 서버를 관리하는 방법이 사용되는데, 이것이 SSH(Secure SHell)이다.
SSH의 설정은 SSH 서버가 설치·실행된 상태에서, 키 인증을 위해 관리자의 공개키를 등록하는 과정이다. 접속할 땐 사용자 이름과 서버의 IP, 필자의 개인키로 접속할 수 있다. 비밀번호 방식도 사용할 수 있지만 보안의 문제로 권장되진 않는다.
이후 필요에 따라 사용자 계정과 권한 설정을 해주고, OS 방화벽 등을 설정해주면 서버 운용을 위한 초기 세팅은 얼추 마무리 된다.
Docker 설치하기
서버 기초 구성이 끝났다면, 이제 실제 서비스를 운영해볼 차례이다.

필자는 Docker를 이용해서 컨테이너 방식으로 서비스를 운영한다. 컨테이너는 서버 내에 호스트의 커널을 공유하는 샌드박스 형태로 미니 서버를 더 만든다고 생각하면 쉽다. 여러 서비스가 한 번에 돌아가는 서버에서 서비스별로 환경을 분리함으로써 라이브러리 충돌 등을 방지할 수 있고, 버전관리 및 배포가 매우 용이하다는 장점이 있다.
Docker는 앞서 말했듯 컨테이너로 구성되는데, 이 컨테이너는 이미지를 실행한 결과이다. 서비스를 배포할 땐 배포를 위한 이미지를 만들고 이를 서버에서 컨테이너 형식으로 실행하면 되는 것이다.
Docker는 컨테이너 이미지를 만들고 실행하는 도구이고, Kubernetes는 컨테이너화된 서비스의 배치·복구·확장·업데이트를 관리하는 플랫폼이다. 여러 서버의 서비스를 일관되게 운영할 때 유용하지만, 도입할 때는 필요한 기능과 운영 복잡도를 함께 고려해야 한다.
도커는 다음 명령어를 이용해 설치할 수 있다.
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
sudo systemctl start docker짧게 설명하자면 공식 GPG 키 및 저장소 등록, 다운로드, 실행의 과정을 거친다.
Dokploy로 배포 관리하기
그럼 이제 진짜진짜 서비스를 배포할 차례이다.
필자는 Dokploy라는 PaaS(Platform as a Service)를 사용할 것이다.

Dokploy의 장점은 최초 1회의 서버 설정 이후는 GUI 관리 콘솔에서만으로도 모든 서비스의 배포, 업데이트, 백업, 관리, 모니터링을 수행할 수 있다. 웹 서버 설정, Traefik 설정까지 알아서 다 진행해주기 때문에 소규모 서비스를 많이 운영하고자 한다면 이만한게 없을 것이다.
그럼 Dokploy를 설치해보며 설명을 이어가보자.
curl -sSL https://dokploy.com/install.sh | shDokploy는 놀랍게도 이 한 줄로 설정을 마칠 수 있다.
그런데 필자는 처음 Dokploy를 설치할 때 설치는 잘 되었지만, 내부 기능이 잘 작동하지 않는 문제가 있었다. 이 문제를 해결하기 위해 하루 넘게 사투했던 기억이 있다.
문제는 커널(Kernel)의 호환성 문제였다. Dokploy는 한 줄로 자동 설치를 지원하기 때문에 시스템의 환경을 자동으로 인식해서 진행한다. 하지만 필자가 사용하고 있는 서버의 환경이 컨테이너 서버였기 때문에 기본적으로 설치되어있던 커널이 Dokploy 시스템의 환경 인식에 오류를 일으킨 것이 원인이었다.
이 문제를 해결하기 위해 필자는 커널을 바꾼다는 선택을 하였다. 서버가 사용중이지 않았기 때문에 내릴 수 있던 결정이었다. 커널을 교체한 이후 Dokploy를 다시 설치하니 잘 작동하였다.

Dokploy를 설치하면 이렇게 GUI로 된 콘솔에 들어올 수 있다. 사이드바를 보면 벌써 수많은 기능들을 한 곳에서 처리할 수 있을 것 같은 예감이 든다.
이 콘솔에서 서비스를 배포하고, Env를 관리하며 모니터링을 한 번에 수행할 수 있다. 자세히 보면 Schedule을 이용해서 Cron Job을 등록할 수도 있고, 자동 백업도 수행할 수 있음을 알 수 있다.
한 번 실제 서비스를 배포하는 과정을 따라가보자. 현재 보고있는 이 블로그의 배포 환경을 예시로 들어보겠다.
Project 추가하기

먼저 Dokploy에서 프로젝트를 추가한다. 프로젝트는 여러개의 컨테이너를 하나의 서비스 단위로 묶는 작업이다.
서비스 추가하기

다음은 필요한 서비스들을 적절히 추가해준다. 참고로 올라가있는 서비스들은 다음과 같다.
- og-image : 게시글의 공유 이미지를 생성하기 위한 이미지 서버
- db : 블로그의 모든 정보를 저장하는 MySQL DB
- ghost : 블로그의 심장. Ghost 엔진
- activitypub : 블로그 구독을 위한 소셜 서비스
- traffic-analytics : ghost와 연동 가능한 웹 트래픽 분석 도구
현재 보고있는 이 블로그는 5개의 컨테이너가 함께 돌아가며 작동하는 것이라 이해할 수 있겠다.
환경변수 추가하기
환경변수, 흔히 env라고 한다. 서비스를 돌리기 위한 비밀키(DB 비밀번호, API key 등)을 설정하는 과정이다.
원래라면 각 컨테이너별로 다른 env를 주입해주어야 하는 번거로움이 있지만, Dokploy에서는 Project Env를 통해 Env를 통합 관리할 수 있다.
DOMAIN=https://vvcnyy.me
ADMIN_DOMAIN=https://vvcnyy.me
HTTP_PORT=80
HTTPS_PORT=443
DATABASE_ROOT_PASSWORD=
DATABASE_PASSWORD=
DATABASE_USER=
TINYBIRD_API_URL=
TINYBIRD_WORKSPACE_ID=
TINYBIRD_ADMIN_TOKEN=
TINYBIRD_TRACKER_TOKEN=
SALT_STORE_TYPE=
mail__transport=SMTP
mail__options__host=
mail__options__port=
mail__options__secure=
mail__options__auth__user=
mail__options__auth__pass=
mail__from=
MYSQL_DATA_LOCATION=./data/mysql필자는 이정도의 env를 가지고 서비스를 운영한다.
배포하기
모든 설정을 끝마쳤다면 각 컨테이너를 실행해 서비스를 배포하면 된다.
Traefik으로 도메인 연결하기
이렇게 벌써 하나의 서비스가 성공적으로 배포되었다. 다만, 아직 한 가지의 일이 더 남았다. 서버에서 서비스는 열심히 돌아가고 있지만, 아직 사람들이 서비스에 접근할 방법이 없다.
원래라면 Apache2, Nginx, Caddy같은 웹서버를 앞단에 붙여서 서버로 들어오는 웹 트래픽을 처리해주는 단을 설정하는 과정이 필요하다. 하지만 Dokploy에서는 자체 Traefik을 통해 이를 아주 손쉽게 설정할 수 있도록 해준다.
Traefik으로 도메인을 연결하기 위해서는 우선 연결하고자 하는 서비스에 들어가 Domain 탭에 접속한다. 그곳에서 도메인을 연결하면 된다.

필자는 vvcnyy.me와 www.vvcnyy.me 두 개의 도메인을 ghost 블로그 엔진에 연결하였다. 참고로 Dokploy에서는 요청을 non-www로 바꿔주는 기능도 제공하여 www.vvcnyy.me로 접근하면 자동으로 vvcnyy.me로 리다이렉트된다.
이렇게까지 하면 정말 서비스 운영을 위한 모든 준비가 끝난다. 일반 사용자가 vvcnyy.me 도메인을 통해 내 서비스에 접근할 수 있게 된것이다.
운영 중인 서버 살펴보기
필자는 위와 같은 방법으로 여러 서비스들을 Dokploy에 등록해두고 서비스하고 있다.

Dokploy에서는 이와 같이 서버를 모니터링할 수 있는 탭을 제공한다.
이 화면에서는 CPU, 메모리, 디스크, 네트워크 사용량 등 서버의 자원 상태를 확인할 수 있다.

아까도 잠시 나왔었지만, 지금 이 서버에서 돌아가는 서비스의 수는 이정도가 된다. 굉장히 많은게 돌아가고 있다. 관리적 측면에서는 그리 좋은 상태는 아니지만 Dokploy로 간편하게 볼 수 있어 그렇게 버겁지 않다.
여러 서버 관리하기

Dokploy에서는 아주 편리하게 여러 서버를 함께 관리할 수 있는 도구를 제공한다.
Remote Server탭에서 서버를 추가하고, 인증을 위한 SSH 설정을 모두 마치면 본 서버의 Dokploy가 리모트 서버에 접속해 알아서 Dokploy 원격 배포를 위한 설정을 진행한다.

여기서 주목할 점은 Server Type은 Deploy Server와 Build Server 중에서 고를 수 있다는 것이다.
Deploy Server는 본 서버와 같이 실제 서비스를 해당 서버에서 배포하고 운영하기 위한 목적으로 서버를 구성하는 것이고, Build Server는 빌드만 리모트 서버에서 진행하고, 서비스의 배포 및 운영은 본 서버에서 처리할 수 있도록 하기위한 목적으로 설정하는 것이다.
설정을 모두 마치고 나면 하나의 Dokploy로 여러 서버를 관리할 수 있게 된다. Dokploy 웹 GUI에서 다른 서버의 Console에도 접근할 수 있기 때문에 매우 편리하다고 할 수 있다.

실제로 서비스를 배포할 때 어느 서버에서 배포할 것인지를 고를 수 있게 된다. 관리는 한 곳에서 하고 배포는 여러 곳에서 한다는게 약간 쿠버네티스의 향기가 나는 것 같기도 하다.
데이터 백업하고 복구하기

Dokploy에서는 서비스를 만들 때 다양한 선택지를 제공한다. 이번에는 그 중 Database부분에 주목해볼 것이다.
Application 또한 백업을 지원하지만, Database로 배포를 하면 데이터베이스를 관리하기에 더 적합한 환경을 제공해주게 된다.
그 중 Backup 탭에 들어가면 간편하게 데이터베이스를 백업할 수 있다.

Schedule은 Cron 표현식으로 작성한다. 필자는 일주일에 1번씩 minio s3 버킷에 DB를 백업하는 일정을 짜두었다.
로컬에 S3 호환 버킷을 설치하거나, AWS S3, Cloudflare R2 등을 설정해서 등록하는 과정이 필요하다
이렇게 백업이 된 내용은 필자가 설정해준 S3 버킷 안에서 확인할 수 있다.

Blog의 DB가 복구를 위한 SQL 형태로 덤프되어 S3 버킷에 잘 올라가있는 모습을 확인할 수 있다.
그럼 이제 만약의 경우로 데이터가 날아간 상황을 가정해보자. 데이터가 날아간 것이 확인되면 가장 최근에 백업된 내용으로 DB를 restore하면 될 것이다.
복구하기 위해서는 백업된 SQL 파일을 다운받아 mysql 콘솔에서 불러오거나 실행하는 방법이 있다. 다만 필자는 Dokploy를 사용하고 있기 때문에 Dokploy Backup 탭에서 제공하는 복구 도구를 사용할 것이다.

Dokploy의 Restore Backup에 들어가면 S3 버킷에서 어떤 시점의 백업 파일을 가져올 것인지 선택할 수 있다.
선택 후 Restore 버튼을 누르면 Dokploy가 DBMS 엔진에 따라 복구 작업을 자동으로 수행해준다.
마무리
Dokploy를 사용하면서 여러 서버의 배포와 백업 작업을 한곳에서 관리할 수 있었다. 다만 설치 과정의 호환성 문제나 서버의 접근 제어까지 도구가 모두 해결해 주는 것은 아니었다. 앞으로는 백업 설정뿐 아니라 실제 복구 가능 여부도 점검하면서 운영 방식을 개선해 나가고자 한다.


