Ubuntu 26.04 강좌 / Ubuntu 설정·패키지 목록·사용자 데이터 백업하기
Ubuntu 백업은 복원할 설정·사용자 자료·앱 데이터를 정하고 원본 장애와 분리된 위치에 보관한 뒤 실제로 되살릴 수 있는지 확인해야 합니다. 패키지 목록과 VM 스냅샷만으로는 자료 복구가 완성되지 않습니다. 이 글은 백업 범위를 정리하고 원본을 덮어쓰지 않는 작은 복원 실습을 제공합니다.
무엇을 되살릴지 먼저 정하기
| 대상 | 보관할 내용과 확인 사항 |
|---|---|
| 설정 | 변경한 /etc 파일·적용 이유·서비스 버전. 인증서·비밀 키는 접근 제한 |
| 사용자 자료 | 실제 홈·공유 경로, UID·GID, 권한·ACL·확장 속성 필요 여부 |
| 앱 데이터 | 데이터베이스 덤프·볼륨·업로드 파일·앱 버전과 일관성 확보 절차 |
| 패키지 정보 | APT 수동 설치 목록·전체 버전·Snap 목록·저장소 정보 |
| 복구 수단 | 설치 매체·콘솔·암호화 해제 키·백업 복호화 키와 보관 책임 |
실행 중인 데이터베이스의 파일을 단순 tar로 복사하면 서로 다른 시점의 내용이 섞일 수 있습니다. 앱이 지원하는 덤프나 정지·동결 절차를 사용하고 여러 저장소를 함께 복원해야 하는지 확인합니다. ACL·확장 속성이 필요한 자료는 선택한 도구가 이를 보존하고 복원하는지 별도로 시험합니다.
패키지와 설정 위치 기록하기
다음 명령은 일반 사용자 홈 아래 새 목록 폴더를 만들며 패키지를 설치하거나 제거하지 않습니다. 목록에는 사용자명·저장소 주소 등 운영 정보가 들어갈 수 있으므로 접근을 제한합니다. 이 목록 자체에는 설정 파일이나 사용자 파일의 내용이 들어 있지 않습니다.
(
set -eu
umask 077
inventory_dir=$(mktemp -d "$HOME/ubuntu-inventory.XXXXXX")
apt-mark showmanual > "$inventory_dir/apt-manual.txt"
dpkg-query -W -f='${binary:Package}\t${Version}\n' > "$inventory_dir/dpkg-versions.tsv"
if command -v snap >/dev/null 2>&1; then
snap list > "$inventory_dir/snap-list.txt"
fi
cat /etc/os-release > "$inventory_dir/os-release.txt"
printf "%s\n" "$inventory_dir"
)
복원 시 목록 전체를 무조건 재설치하지 말고 현재 릴리스에서 필요한 패키지와 저장소가 지원되는지 검토합니다. 서버를 새로 만드는 경우 machine-id·SSH 호스트 키·고정 IP처럼 기기별로 달라야 할 값은 설정 백업과 구분합니다. 동일 서버 복구와 별도 서버 복제는 다른 작업입니다.
작은 자료로 백업·복원 왕복 시험하기
아래 전체 코드를 ~/backup-roundtrip-lab.sh에 저장하고 bash ~/backup-roundtrip-lab.sh로 실행합니다. tar·sha256sum·cmp가 필요하며 sudo는 사용하지 않습니다. 새 임시 폴더의 예제 파일만 다룹니다. 같은 디스크 안의 실습이므로 독립 백업 보관을 대신하지 않습니다.
set -eu
umask 077
lab_dir=$(mktemp -d)
mkdir "$lab_dir/source" "$lab_dir/restored"
printf "original data\n" > "$lab_dir/source/note with spaces.txt"
tar -C "$lab_dir/source" -cpf "$lab_dir/data.tar" .
(
cd "$lab_dir"
sha256sum data.tar > data.tar.sha256
sha256sum -c data.tar.sha256
)
tar -tf "$lab_dir/data.tar"
tar -C "$lab_dir/restored" -xpf "$lab_dir/data.tar"
cmp "$lab_dir/source/note with spaces.txt" "$lab_dir/restored/note with spaces.txt"
printf "Round trip passed: %s\n" "$lab_dir"
체크섬은 아카이브가 기록 당시와 같은지 확인하고, tar 목록은 포함된 이름을 확인합니다. 마지막 cmp가 성공하고 Round trip passed가 표시되어야 예제 파일 내용이 복원되었다고 판단할 수 있습니다. 암호화·접근 권한·앱 실행까지 검증한 것은 아닙니다. 알 수 없는 아카이브를 관리자 권한으로 풀지 말고 실제 복원도 격리된 빈 디렉터리에서 시작합니다.
실제 Nginx 설정과 사용자 폴더 백업하기
Nginx 실습을 마친 서버의 /etc/nginx와 홈 안의 일반 문서 폴더 하나를 대상으로 합니다. 실제 폴더를 정하고 편집·동기화·앱 쓰기를 멈춘 일관된 상태를 준비합니다. 실행 중 DB나 Docker 볼륨을 이 파일 백업으로 대신하지 않습니다. 자동 마운트 강좌의 별도 백업 디스크 마운트 지점·UUID를 기록하고 원본과 다른 장치인지 확인합니다.
다음 전체를 ~/backup-course-data.sh에 저장합니다. Bash·GNU tar·util-linux의 findmnt·coreutils의 realpath/sha256sum이 필요합니다. 첫 인수는 사용자 자료 폴더, 둘째는 디스크 자체의 마운트 지점, 셋째는 UUID입니다. bash ~/backup-course-data.sh "$HOME/Documents/course-data" /srv/backup 실제UUID를 예로 삼되 모두 실제 값으로 바꿉니다.
set -eu
umask 077
if [ "$#" -ne 3 ]; then
printf 'Usage: bash backup-course-data.sh SOURCE_DIR BACKUP_MOUNT EXPECTED_UUID\n' >&2; exit 2
fi
source_dir=$(realpath -- "$1")
backup_mount=$(realpath -- "$2")
expected_uuid=$3
case "$source_dir" in
"$HOME"/*) ;;
*) printf 'Choose a specific ordinary-data folder inside your home.\n' >&2; exit 1 ;;
esac
test -d "$source_dir"
if [ -z "$expected_uuid" ] || [ "$expected_uuid" = REPLACE_WITH_VERIFIED_UUID ]; then
printf 'Record the actual backup filesystem UUID first.\n' >&2; exit 1
fi
actual_uuid=$(findmnt -rn --mountpoint "$backup_mount" -o UUID || true)
if [ "$actual_uuid" != "$expected_uuid" ]; then
printf 'Expected backup filesystem is not mounted; stop.\n' >&2; exit 1
fi
for original in "$source_dir" /etc/nginx; do
original_uuid=$(findmnt -rn --target "$original" -o UUID)
if [ -z "$original_uuid" ] || [ "$original_uuid" = "$actual_uuid" ]; then
printf 'Use a separate verified backup filesystem.\n' >&2; exit 1
fi
done
case "$backup_mount/" in
"$source_dir/"*) printf 'Backup must be outside the source tree.\n' >&2; exit 1 ;;
esac
sudo test -d /etc/nginx
df -h "$source_dir" "$backup_mount"
set_dir=$(sudo mktemp -d "$backup_mount/ubuntu-course-backup.XXXXXX")
sudo chmod 0700 "$set_dir"
sudo tar --acls --xattrs --numeric-owner -C / -cpf "$set_dir/nginx.tar" etc/nginx
sudo tar --acls --xattrs --numeric-owner -C "$source_dir" -cpf "$set_dir/user-data.tar" .
sudo sh -c 'cd "$1" && sha256sum nginx.tar user-data.tar > SHA256SUMS && sha256sum -c SHA256SUMS' sh "$set_dir"
printf 'Backup set: %s\n' "$set_dir"
마운트가 없거나 UUID가 다르면 아카이브 생성 전에 중단합니다. 성공하면 새 세트 경로와 두 체크섬의 OK가 나옵니다. 설정에 비밀 정보가 있을 수 있어 세트는 root 전용 0700으로 제한하지만 이것이 분실 대비 암호화는 아닙니다. 백업 보관·암호화 방침도 정하고 ACL·확장 속성 보존은 실제 파일 시스템에서 복원해 확인합니다.
빈 별도 위치에 복원해 원본과 비교하기
자신이 방금 만든 신뢰하는 세트만 사용합니다. 다음을 ~/restore-course-data.sh로 저장하고 bash ~/restore-course-data.sh 백업세트경로로 실행합니다. 새 /var/tmp 디렉터리에만 풀며 운영 /etc/nginx나 사용자 원본을 덮어쓰지 않습니다. 여유 공간과 UID·GID 대응을 먼저 확인합니다.
set -eu
if [ "$#" -ne 1 ]; then
printf 'Usage: bash restore-course-data.sh BACKUP_SET_DIRECTORY\n' >&2; exit 2
fi
set_dir=$(realpath -- "$1")
sudo test -f "$set_dir/SHA256SUMS"
sudo sh -c 'cd "$1" && sha256sum -c SHA256SUMS' sh "$set_dir"
restore_dir=$(sudo mktemp -d /var/tmp/ubuntu-course-restore.XXXXXX)
sudo chmod 0700 "$restore_dir"
sudo mkdir "$restore_dir/config" "$restore_dir/data"
sudo tar --acls --xattrs --same-owner -C "$restore_dir/config" -xpf "$set_dir/nginx.tar"
sudo tar --acls --xattrs --same-owner -C "$restore_dir/data" -xpf "$set_dir/user-data.tar"
sudo ls -ldn "$restore_dir/config/etc/nginx" "$restore_dir/data"
printf 'Isolated restore: %s\n' "$restore_dir"
출력된 실제 복원 경로를 다음 변수에 넣고 백업 이후 바꾸지 않은 원본과 비교합니다. diff의 무출력·종료 0은 같은 내용, 1은 차이를 뜻합니다. 원본을 백업 이후 고쳤다면 차이가 있다는 이유만으로 백업 손상이라고 단정하지 않습니다. 다른 오류는 권한·파일 존재부터 조사합니다.
restore_dir=/var/tmp/REPLACE_WITH_PRINTED_RESTORE_DIRECTORY
source_dir="$HOME/Documents/course-data"
sudo diff --no-dereference -r /etc/nginx "$restore_dir/config/etc/nginx"
sudo diff --no-dereference -r "$source_dir" "$restore_dir/data"
중요 파일 내용과 ls -ln의 숫자 소유자·모드, 필요하면 getfacl/getfattr의 ACL·확장 속성을 비교합니다. 도구가 없으면 acl·attr 패키지를 준비합니다. 파일 추출만으로 서비스 복원을 완료했다고 보지 않으며, 실제 장애 복구는 별도 서버에서 설정 검사·앱 기능 시험까지 거쳐 적용합니다. 이번 비교 폴더는 경로·내용을 확인한 뒤 자신이 만든 것만 정리합니다.
독립된 저장 위치와 실패 감지 준비하기
외장 디스크나 별도 호스트를 사용할 때 저장 디렉터리가 있다는 이유만으로 연결되었다고 판단하지 않습니다. findmnt의 대상 마운트 SOURCE·UUID를 기록한 값과 비교하고 다르면 쓰기를 중단합니다. 마운트되지 않은 빈 폴더에 쓰면 시스템 디스크를 채울 수 있습니다. 저장 용량·복호화 가능 여부·다른 장소나 오프라인의 백업 세대도 복구 목적에 맞게 설계합니다.
Ubuntu의 셸 스크립트 백업 안내에는 tar와 다른 디렉터리로 복원하는 예제가 있습니다.
자동화는 수동 복원에 성공한 뒤 진행합니다. 종료 코드·마지막 성공 시각·보관 세대·공간 부족을 기록하고 실패 알림이 전달되는지 시험합니다. 해시를 같은 쓰기 가능한 위치에 두는 것만으로는 변조를 막지 못하므로 필요하면 독립 검증 기록이나 변경 불가능한 보관도 검토합니다.
자료와 서비스 동작으로 복구 완료 판단하기
복원 위치에서 파일 수·중요 파일 내용·소유자·권한을 확인하고 앱의 읽기·쓰기와 사용자 로그인을 시험합니다. DNS·인증서·공유·백업 재개도 대상에 따라 확인합니다. 복구 시간과 잃어버린 변경 범위를 기록하고 허용 시간·손실 범위를 넘으면 주기나 절차를 개선합니다. 필요한 자료를 확보하기 전에 장애 원본 디스크를 초기화하지 않습니다.




