Ubuntu 26.04 강좌 / Ubuntu 서버 구축·운영 인수인계 종합 실습
Ubuntu 서버 구축의 완료 기준은 설치 성공이 아니라 다른 관리자가 접근·변경·복구할 수 있는 상태입니다. 이 종합 실습은 전용 26.04 LTS VM에 필요한 서비스만 구성하고 허용·거부 접근, 재시작, 백업 복원을 검증해 실제 결과를 인수인계 문서에 남깁니다.
실습 범위와 성공 조건 확정하기
기본 과제는 LAN 안의 SSH 관리와 Nginx 웹 서비스입니다. 전용 VM·콘솔·주소 계획·허용 관리 클라이언트·독립 백업 위치를 준비합니다. 공개 HTTPS는 소유한 도메인과 외부 검증 경로가 있을 때 추가하고, Samba나 컨테이너는 필요할 때 선택합니다. 모든 서비스를 설치하는 것을 목표로 삼지 않습니다.
| 검증 대상 | 완료 판정에 필요한 증거 |
|---|---|
| 관리 접근 | 허용 클라이언트의 새 키 인증 성공과 제외 경로의 접근 거부 |
| 웹 서비스 | 실제 Host·URL에서 의도한 응답과 제외된 호스트 처리 |
| 재시작 | 계획된 재부팅 뒤 주소·대상 서비스·접속 재확인 |
| 백업 | 별도 위치 복원과 내용·권한·앱 동작 확인 |
| 운영 기록 | 담당자·갱신/보존 정책·변경 및 복구 절차와 미완료 항목 |
의존 순서대로 구성하고 변경을 작게 나누기
- 설치 직후 콘솔에서 버전·장치·시간·현재 주소를 기록하고 업데이트와 필요한 재부팅을 마칩니다.
- Netplan 또는 NetworkManager의 실제 관리 범위를 확인하고 주소 변경은 콘솔·백업·try 확인을 갖추어 적용합니다.
- SSH 키 인증을 새 세션으로 확인한 뒤 관리 정책을 조정합니다. 포트는 실제 리스너와 서비스/소켓 구성을 기준으로 확인합니다.
- 필요한 서비스만 설치하고 설정 백업·구문 검사 후 반영합니다. UFW와 외부 방화벽에서 실제 클라이언트·포트를 제한합니다.
- 독립 백업·복원 시험과 실패 알림 경로를 준비하고 재부팅 시험 전 상태를 저장합니다.
단계별 확인에 실패하면 다음 변경을 더하지 말고 이번 차이와 로그를 조사합니다. 관리 포트·인증·방화벽을 동시에 바꾸면 연결이 끊긴 원인과 되돌릴 대상을 찾기 어려워집니다. 콘솔 복구 경로도 실제로 열 수 있는지 확인합니다.
로컬 확인과 LAN 서비스를 분리하기
Nginx 강좌의 127.0.0.1:8080 사이트는 서버 안에서만 확인합니다. alpha.example.test를 서버의 192.168.56.20으로 연결해도 루프백 리스너에 외부 접속할 수 없습니다. 서버에서 아래 --resolve로 이름과 루프백 목적지를 지정해 alpha-site 응답을 먼저 확인합니다. 컨테이너 예제는 8081, 이번 LAN 실습은 8082를 사용합니다.
curl --fail --show-error --resolve alpha.example.test:8080:127.0.0.1 http://alpha.example.test:8080/
LAN 검증에는 5·15강의 호스트 전용망과 서버 .20·Linux 클라이언트 .10을 준비합니다. 23강의 문서 루트가 있는 전용 VM에서 아래 새 사이트를 추가합니다. 실제 주소·경로가 다르면 전부 일관되게 바꾸고 포트 충돌을 먼저 확인합니다. 기존 파일이 있으면 중단합니다.
(
set -eu
site=/etc/nginx/sites-available/ubuntu-course-lan
enabled=/etc/nginx/sites-enabled/ubuntu-course-lan
sudo test -f /srv/ubuntu-course-alpha/index.html
if ! ip -4 -o address show | grep -Fq ' 192.168.56.20/24 '; then
printf 'Configure the verified server lab address first.\n' >&2; exit 1
fi
for path in "$site" "$enabled"; do
if sudo test -e "$path" || sudo test -L "$path"; then
printf 'Existing lab site: inspect before changing.\n' >&2; exit 1
fi
done
backup_dir=$(sudo mktemp -d /root/nginx-before-lan.XXXXXX)
sudo cp -a /etc/nginx "$backup_dir/"
sudo sh -c 'set -C; cat > "$1"' sh "$site" <<'EOF'
server {
listen 192.168.56.20:8082;
server_name course-lab.example.test;
root /srv/ubuntu-course-alpha;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
EOF
sudo ln -s "$site" "$enabled"
sudo nginx -t
sudo systemctl reload nginx
sudo ss -lntp
printf 'LAN site backup: %s\n' "$backup_dir"
)
UFW 강좌처럼 기본 수신 거부와 SSH 관리 접속을 보존한 환경에서 아래 규칙을 추가합니다. 다른 광범위한 8082 허용 규칙이 있으면 제외 시험이 성립하지 않으므로 실제 규칙을 검토합니다. 호스트 전용망의 8082를 인터넷에 포워딩하지 않습니다.
sudo ufw allow from 192.168.56.10 to 192.168.56.20 port 8082 proto tcp
sudo ufw status numbered
허용 Linux 클라이언트 .10에서 다음 curl을 실행해 alpha-site를 확인합니다. 별도의 제외 클라이언트(예: 호스트 .1)에서 같은 새 연결은 정책에 따라 차단되어야 합니다. 이름이 다른 요청을 거부하는 정책이 필요하면 별도의 기본 거부 가상 호스트도 설계해야 하며, server_name만으로 방화벽이나 인증을 대신하지 않습니다.
curl --fail --show-error --connect-timeout 5 --max-time 10 --resolve course-lab.example.test:8082:192.168.56.20 http://course-lab.example.test:8082/
정리할 때는 이번 사이트와 UFW 규칙만 기록과 대조해 제거하고 nginx -t 성공 후 reload합니다. 23강의 루프백 사이트나 다른 서비스는 유지합니다. 재부팅 검증에서는 서버 주소·실제 리스너·허용 및 제외 접속을 다시 측정합니다.
작은 HTTP 상태 점검 스크립트 만들기
아래 전체 스크립트를 ~/check-web-lab.sh로 저장합니다. Bash와 curl이 필요하며 실제 URL과 기대 문자열을 인수로 받습니다. 23강 로컬 확인은 서버 자신의 /etc/hosts에 alpha.example.test를 127.0.0.1로 연결한 뒤 bash ~/check-web-lab.sh http://alpha.example.test:8080/ alpha-site로 실행합니다. 앞의 --resolve는 curl 한 번에만 적용되므로 스크립트의 이름 해석을 바꾸지 않습니다.
set -eu
if [ "$#" -ne 2 ]; then
printf "Usage: bash check-web-lab.sh URL EXPECTED_TEXT\n" >&2
exit 2
fi
url=$1
expected=$2
case "$url" in
http://*|https://*) ;;
*) printf "Use an HTTP or HTTPS URL.\n" >&2; exit 2 ;;
esac
if [ -z "$expected" ]; then
printf "Expected text must not be empty.\n" >&2
exit 2
fi
body_file=$(mktemp)
trap 'rm -f -- "$body_file"' EXIT
if ! curl --fail --silent --show-error --connect-timeout 5 --max-time 10 "$url" -o "$body_file"; then
printf "FAIL: request or TLS verification failed\n" >&2
exit 1
fi
if ! grep -Fq -- "$expected" "$body_file"; then
printf "FAIL: expected text missing\n" >&2
exit 1
fi
printf "PASS: %s %s\n" "$(date -u +%FT%TZ)" "$url"
성공은 종료 코드 0과 PASS, 요청·인증서·본문 검사 실패는 1, 인수 오류는 2로 구분합니다. 존재하지 않는 기대 문자열을 전달해 실패도 감지되는지 확인하세요. HTTP 응답만 검사하므로 DB 쓰기·로그인·백업 성공을 대신하지 않습니다. URL에 비밀번호나 비밀 토큰을 넣지 말고, 자동화 시 종료 코드와 실행 시각을 수집할 방법을 별도로 정합니다.
LAN 상태 확인은 .10 클라이언트의 /etc/hosts 또는 관리 DNS에서 course-lab.example.test를 192.168.56.20으로 연결한 뒤 bash ~/check-web-lab.sh http://course-lab.example.test:8082/ alpha-site로 실행합니다. hosts 수정 전 원본을 보관하고 기존 이름 항목을 중복으로 넣지 않습니다. 로컬·LAN·공개 HTTPS URL을 혼용하지 말고, 예상된 차단과 서비스 장애를 구분합니다.
허용·거부·재부팅·복원을 기록한다
서버 자신의 curl 성공에 더해 실제 허용 클라이언트와 제외 클라이언트에서 시험합니다. 기존 SSH 연결을 유지한 상태에서 새 연결을 만들고, 재부팅은 작업 시간을 정한 뒤 수행해 다시 접속합니다. 백업은 비어 있는 별도 복원 위치에서 내용과 권한을 확인하고 앱이 요구하는 검증도 수행합니다. 실행하지 않은 항목은 미완료로 남깁니다.
Ubuntu의 방화벽 안내를 바탕으로 실제 적용 규칙과 접속 시험을 함께 기록합니다.
인수인계 문서는 실제 확인값으로 채운다
다음 양식은 운영 기록 파일의 시작점입니다. 대괄호를 실제 확인값으로 바꾸고 비밀 값은 문서에 쓰지 않고 승인된 보관 위치만 적습니다. 담당자와 복구 책임을 정하며, 예제 IP나 설치 성공 가정을 그대로 실측 결과로 복사하지 않습니다.
System: [hostname, purpose, owner]
Platform: [Ubuntu release, kernel, VM host, console route]
Network: [interface, renderer, address, gateway, DNS]
Access: [allowed clients, actual SSH listener, key custody location]
Services: [versions, configuration paths, validation/reload commands]
Exposure: [listeners, UFW rules, external firewall, container bindings]
TLS: [hostnames, renewal mechanism, expiry/failure monitoring]
Backup: [scope, independent destination identity, retention, key custody]
Restore test: [time, destination, content/permission/app results]
Acceptance: [test, client, expected/actual result, evidence location]
Rollback: [change boundary, preserved baseline, restoration procedure]
Pending: [unperformed checks, unresolved risks, owner, target date]
검증 기록과 변경 이력을 함께 보관하고 다른 관리자가 절차만 읽고 접속·점검·복원 준비를 할 수 있는지 검토합니다. 알림을 받는 사람과 업데이트·인증서·백업 점검 주기가 정해져 있고 남은 작업의 책임자가 명확하면, 서버를 만든 사람의 기억에 의존하지 않고 운영을 이어갈 수 있습니다.




