
맥 미니를 이용해 홈서버 구축하기 (2)
첫 번째 글에서 '이어지는 포스팅에서는 맥 미니를 서버로 설정하는 법을 다뤄보겠다'라고 말해 놓고 시간이 많이 지났습니다. 제대로 정리해 두려면 최소한 서버라도 포맷을 하고 다시 되짚어가며 정리를 해야할텐데 잘 돌아가고 있는 서버를 갈아 엎는게 쉽지 않았기 때문입니다.
그래도 최근 맥 미니의 macOS를 Sequoia에서 Tahoe로 업그레이드하기로 마음먹으면서, 기왕 오랜만에 서버 작업을 하는 김에 초기화부터 시작해서 서버 구성을 다시 처음부터 해보며 기록해 보았습니다.
맥 미니 설정

초기화를 하니 첫 구매의 설렘이 다시 느껴지는 것 같았습니다. 안내에 따라 언어나 지역 등의 설정을 해주었습니다.

유선으로 연결해 서버로 사용할 것이므로, Wi-Fi와 Bluetooth는 전력 소모를 줄이기 위해 비활성화해 주었습니다. 그 후 맥 미니가 자동으로 업데이트되지 않도록 [일반 > 소프트웨어 업데이트]에서 자동 업데이트의 i 아이콘을 눌러 '사용 가능할 때 새로운 업데이트 다운로드'와 'macOS 업데이트 설치' 옵션을 비활성화해 주었습니다.

[일반 > 공유]에서 '화면 공유'와 '원격 로그인'을 활성화해 주었습니다. 화면 공유는 맥북의 '화면 공유' 앱으로 GUI에 접근할 때, 원격 로그인은 SSH로 맥 미니에 접근할 때 사용합니다.

맥 미니가 자동으로 잠자기 모드에 들어가지 않고 정전이 발생해도 자동으로 켜질 수 있도록 [에너지]에서 '디스플레이가 꺼져 있을 때 자동으로 잠자지 않게 하기'와 '정전 후 자동으로 시작하기' 옵션을 활성화해 주었습니다.
배포 환경 설정
배포 환경에 필요한 도구들을 설치했습니다. 백엔드 서버를 빌드할 수 있는 Rust와 Nuxt 프론트엔드 서버를 구동할 수 있는 Node.js, 그리고 데이터베이스로 MariaDB를 설치했습니다. 시스템 리소스를 모니터링할 수 있는 macmon이라는 도구도 설치했습니다.
# https://brew.sh/
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Next Steps 지침을 따라 명령어 입력
# https://rustup.rs/
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
brew install node
brew install macmon
brew install mariadb
brew services start mariadb
MariaDB에 개발용 계정을 만들어 주고, 원격 개발에도 사용할 수 있도록 0.0.0.0 주소에 바인드해 주었습니다.
mariadb
> CREATE USER '{username}'@'%' IDENTIFIED BY '{password}';
> GRANT ALL PRIVILEGES ON *.* TO '{username}'@'%';
> FLUSH PRIVILEGES;
> exit;
echo '[mysqld]' >> /opt/homebrew/etc/my.cnf
echo 'bind-address=0.0.0.0' >> /opt/homebrew/etc/my.cnf
brew services restart mariadb
로컬 네트워크 및 포트 포워딩

앞서 설치한 Rust로 간단한 테스트용 웹서버를 작성해 로컬 네트워크에서 접속이 제대로 이루어지는지 확인해 보았습니다. 웹 프레임워크로는 Axum을 사용했습니다.
[dependencies]
axum = "0.8"
tokio = { version = "1.49", features = ["full"] }
use axum::{Router, routing::get};
#[tokio::main]
async fn main() {
let listener = tokio::net::TcpListener::bind("0.0.0.0:80").await.unwrap();
let router = Router::new().route("/", get(|| async { "Hello, World!" }));
axum::serve(listener, router).await.unwrap();
}

접속이 안 된다면 [개인정보 보호 및 보안 > 로컬 네트워크]에서 접근 권한을 활성화시켜 주어야 합니다.

로컬 네트워크에서 접속을 확인했으니 이제 외부에서도 접속할 수 있도록 공유기에서 포트 포워딩을 설정해 주었습니다. HTTPS(443)와 HTTP(80)은 그대로 포워딩해 주고, SSH(22)와 MariaDB(3306)는 혹시 모를 공격에 대비해 다른 포트를 사용해 포워딩해 두었습니다.

포트 포워딩 후 웹서버가 공인 IP로도 접속이 가능한지 확인했습니다.
도메인 및 DNS 설정
Cloudflare에 가입했습니다. Cloudflare에서는 도메인 구매부터 관리, DDoS 방어나 트래픽 추적같이 웹사이트 운영에 필수적인 여러 가지 서비스를 한 곳에서 제공합니다.
등록 기관 비용만으로 도메인을 구입할 수 있는 Cloudflare Registrar에서 .dev 도메인을 구입했습니다. 그 후 대시보드에서 구입한 도메인 페이지의 [DNS > 레코드]에서 A 레코드를 추가해 도메인과 공인 IP를 연결해 주었습니다. A 레코드란 도메인 이름을 IPv4 주소에 매핑하는 DNS 레코드로, 사용자가 도메인을 입력했을 때 어떤 서버로 연결할지를 지정하는 역할을 합니다.
이때 A 레코드의 프록시 상태를 활성화(주황색 구름 아이콘)해 두면, 사용자의 트래픽이 Cloudflare를 거쳐 서버로 전달됩니다. 이렇게 하면 서버의 실제 IP가 외부에 노출되지 않고, Cloudflare의 DDoS 방어나 캐싱 같은 부가 기능도 함께 이용할 수 있습니다.
TLS
.dev 도메인의 특징은 웹사이트가 TLS를 반드시 사용해야 한다는 점입니다. .dev 도메인이면서 TLS를 사용하지 않는다면 브라우저가 접속을 차단할 수 있기 때문에 필히 구성해야 합니다.
Cloudflare를 사용한다면 사용자의 접속을 앞단에서 프록시로 처리해 주기 때문에 서버에 별도의 TLS 구성을 하지 않을 수도 있습니다. 하지만 Cloudflare는 몇 가지 암호화 모드 중 Cloudflare와 서버의 연결도 TLS를 통해 암호화하는 '전체' 혹은 '전체(엄격)' 모드를 추천합니다.

그래서 Cloudflare 대시보드의 개별 도메인 페이지에서 [SSL/TLS > 원본 서버]에서 원본 서버 인증서를 발급받아 프론트엔드 서버에 적용함으로서 암호화 모드를 '전체(엄격)'로 세팅할 수 있었습니다.
한 가지 특이한 점은 Cloudflare에서 발급받은 원본 서버 인증서는 오직 Cloudflare와 서버 간의 통신에서만 유효하다는 것입니다. 만약 일시적으로 Cloudflare 프록시를 끄거나 서버 IP로 직접 접속하는 경우에도 유효한 TLS를 적용하고자 한다면 Let's Encrypt와 같은 서비스를 이용해 인증서를 발급받아야 합니다.
마치며
macOS 초기화 및 설정부터 시작해 네트워크 설정, 도메인 연결, TLS 적용까지 맥 미니를 웹 서버로 사용하기 위한 기본적인 인프라 구성을 마쳤습니다. 처음 서버 세팅을 진행했을 때의 기억을 되짚어가며 다시 진행해 보았는데, 생각보다 까다로운 부분은 없었습니다. 한 번 해두면 크게 바뀔 일이 없는 설정들이라 오히려 이렇게 기록해 두는 게 중요하다는 생각이 들었습니다.