| | |

LFCA 68 🐧 Backing Up with tar

The previous chapter covered the theory of full, differential, and incremental backups. This chapter puts that theory into practice with the tool that has been the standard for Linux backups since the 1970s: tar. Its name comes from “tape archive” — it was designed for writing backups to magnetic tape — but it is used today for archiving files to disk, transferring directory trees over the network, and creating compressed backups of any size.

The LFCA exam places backup and recovery under System Administration Fundamentals, which carries 20% of the total weight. The competency list includes “Implement backup strategies” and “Disaster Recovery” . tar is the tool that implements those strategies on the command line. Knowing the flags, the compression options, the include/exclude patterns, and the extraction workflow is the practical skill the exam tests.

Key point: tar bundles many files into one archive. By itself, the archive is not compressed — it is a concatenation of files with headers. Compression is applied by an additional flag: -z for gzip, -j for bzip2, -J for xz, or --zstd for zstd. The archive can then be extracted to restore the original directory tree, with permissions and metadata intact .


Why tar exists

Every backup tool solves the same problem: many files must become one thing that can be stored, moved, and restored. tar solves it by writing a stream — a sequence of file headers and file contents — that a single command can produce, transfer, and read back.

The many-files problem. A filesystem contains millions of files. Backing them up one at a time is impossible to manage. tar takes a list of paths and writes them to a single file, preserving the directory structure, permissions, ownership, timestamps, and symbolic links . This is the fundamental value of tar: it turns a tree into a stream.

The portability problem. The stream that tar produces is not tied to any filesystem. It can be written to disk, sent over SSH, stored on tape, or piped to another process. The tar format is old enough that virtually every Unix-like system can read it. GNU tar, BSD tar, and busybox tar all understand the base format, and most extensions are backward-compatible .

The metadata problem. A simple cp of a directory loses ownership, loses permissions, follows symlinks, and mangles timestamps. tar preserves all of these by default in -p mode. For system backups — /etc, /var, /home, application directories — preserving metadata is not optional. A restored /etc/passwd with the wrong ownership is a security problem .

The compression problem. Uncompressed archives are large. A tar archive of a 10 GB directory tree might be 8 GB of actual data, with the rest being filesystem overhead and unused blocks. Adding gzip reduces it to perhaps 3 GB. Adding xz reduces it further to 2 GB. tar integrates with the compression tools through simple flags, so the choice between speed and compression ratio is a single character .

The trade-off. tar is old and its syntax is idiosyncratic. The order of flags matters, and some combinations that seem obvious are wrong. The -f flag must be followed by the filename, and it must come after the other flags if they are combined. GNU tar accepts tar -czf archive.tar.gz /path, but POSIX tar wants tar -cf archive.tar /path and rejects combined flags. The exam tests the standard GNU behavior, and familiarity with the common patterns is enough to avoid confusion .


a. Creating Archives: tar cf, czf, cjf, cJf

The tar command to create an archive always uses the c flag and the f flag. The c means “create,” and the f means “file” — the archive is written to a file rather than to standard output . The order is tar -c -f archive.tar paths..., or the combined form tar -cf archive.tar paths....

# Create an uncompressed archive
tar -cf backup.tar /home/user

# Create a gzip-compressed archive
tar -czf backup.tar.gz /home/user

# Create a bzip2-compressed archive
tar -cjf backup.tar.bz2 /home/user

# Create an xz-compressed archive
tar -cJf backup.tar.xz /home/user

The naming convention is a tar file with a second extension indicating the compression: .tar.gz for gzip, .tar.bz2 for bzip2, .tar.xz for xz. This is not required by tar — the extension is just a convention for humans — but it is universal and should be followed.

The compression methods have different characteristics. gzip is the fastest and most compatible, with moderate compression. bzip2 compresses more but is slower. xz compresses best but is slowest and uses more memory. zstd (via --zstd) is the modern choice — faster than gzip and compresses nearly as well as xz . For most backups, gzip or zstd is the right trade-off.

# Create a zstd-compressed archive (modern)
tar --zstd -cf backup.tar.zst /home/user

The tar command stores paths exactly as written. tar -cf backup.tar /home/user stores the file with the full path /home/user/.... Extracting it in a different location recreates /home/user/... from that location’s root. The conventional alternative is to change into the directory first:

# Store relative paths
cd /home && tar -czf /backup/user.tar.gz user

This stores user/... rather than /home/user/.... Extracting it anywhere recreates the user/ directory relative to the current directory. This is safer, because extracting an absolute-path archive can overwrite system files if run from the wrong directory .


b. Inspecting and Extracting Archives

Before extracting an archive, it is good practice to inspect its contents. The t flag lists the files in the archive without extracting them .

# List files in a gzip-compressed archive
tar -tzf backup.tar.gz

# List with details (permissions, size, date)
tar -tvzf backup.tar.gz

# Search for a specific file in the archive
tar -tzf backup.tar.gz | grep "important.conf"

The tar -tvzf output resembles ls -l: it shows permissions, owner, group, size, timestamp, and filename. This is how you verify that the archive contains what you expect before overwriting anything .

Extraction uses the x flag. The full form is tar -xzf archive.tar.gz for a gzip archive, and tar -xJf archive.tar.xz for an xz archive. The archive is unpacked into the current directory by default, preserving the paths stored in the archive.

# Extract to the current directory
tar -xzf backup.tar.gz

# Extract to a specific directory
tar -xzf backup.tar.gz -C /tmp/restore

# Extract a single file
tar -xzf backup.tar.gz home/user/important.conf -C /tmp/restore

The -C flag changes to the specified directory before extracting. This is the standard way to restore without affecting the current working directory. The directory must exist; tar does not create it.

Extracting a single file or directory from an archive is done by naming it after the archive. The path must match exactly what tar -t shows. This is useful for recovering one file from a large backup .

# Extract only the etc directory
tar -xzf full-backup.tar.gz etc/

# Extract only one file
tar -xzf full-backup.tar.gz etc/nginx/nginx.conf

One safety note: tar extraction can overwrite files. Modern GNU tar refuses to extract absolute paths by default and strips the leading slash, which is a security measure. It also refuses to follow symlinks that would write outside the extraction directory . This behavior is on by default and should not be disabled.


c. Include/Exclude Patterns and Incremental Backups

Real backups rarely include everything. Some directories should be excluded: /proc, /sys, /dev, /tmp, /run, cache directories, and anything else that is regenerated on boot. The --exclude flag tells tar to skip them .

# Exclude pseudo-filesystems
tar -czpf /backup/system.tar.gz / \
  --exclude=/proc \
  --exclude=/sys \
  --exclude=/dev \
  --exclude=/tmp \
  --exclude=/run \
  --exclude=/mnt \
  --exclude=/media \
  --exclude=/lost+found

The --exclude patterns are matched against the archive member names. --exclude=/proc excludes the directory named proc at the root. --exclude='*.log' excludes every file ending in .log anywhere in the archive. Patterns can use wildcards and must be quoted if the shell would interpret them .

The exclusion can also come from a file. The -X flag reads exclusion patterns from a file, one per line. This is cleaner when there are many patterns :

# backup-exclude.txt
# /proc
# /sys
# /dev
# /tmp
# /run
# /mnt
# /media
# /lost+found

tar -czpf /backup/system.tar.gz / -X backup-exclude.txt

The -p flag, used in the examples above, preserves permissions and ownership when extracting as root. It is only meaningful when the archive is being read by a user with the appropriate privileges. For a backup made by root and restored by root, -p ensures that the restored files have the same ownership as the originals .

For differential backups with tar, the --newer option creates an archive of files modified after a reference date. The reference date is typically stored in a file when the last full backup ran .

# Store the timestamp of the full backup
date +%F > /backup/last-full-date

# Create a differential backup (changes since the full)
tar -czpf /backup/diff-$(date +%F).tar.gz \
  --newer="$(cat /backup/last-full-date)" \
  /etc /home

The --newer flag (or its long form --after-date) includes only files with modification times after the specified date. This produces a differential backup: everything that changed since the full backup . GNU tar also supports --newer-mtime for cases where the ctime and mtime differ, and -N as a shorthand for --newer.

For incremental backups with the GNU tar --listed-incremental option, the process is different. A snapshot file records the state of the filesystem at the last backup, and subsequent backups compare against that snapshot :

# First full backup (creates the snapshot file)
tar -czpf /backup/full.tar.gz \
  --listed-incremental=/backup/snapshot.snar \
  /etc /home

# Later incremental backup (compares to the snapshot)
tar -czpf /backup/inc-$(date +%F).tar.gz \
  --listed-incremental=/backup/snapshot.snar \
  /etc /home

The --listed-incremental option reads from and writes to the snapshot file. The first run creates the snapshot and produces a full backup. Each subsequent run compares against the snapshot, includes only changed files, and updates the snapshot . Restoration requires extracting the full backup first, then each incremental in order — the same chain as described in the previous chapter.


Complete Example Session

This session demonstrates a full system backup, a differential backup, an incremental backup, verification, and extraction.

# ============================================
# PART 1: THE BASIC FULL BACKUP
# ============================================

# Back up /etc, /home, and /var/www
sudo tar -czpf /backup/full-$(date +%F).tar.gz /etc /home /var/www

# Check the size
ls -lh /backup/full-*.tar.gz

# ============================================
# PART 2: THE EXCLUSION FILE
# ============================================

# /etc/backup-exclude.txt
cat /etc/backup-exclude.txt
# /proc
# /sys
# /dev
# /tmp
# /run
# /mnt
# /media
# /lost+found
# /var/cache
# /var/tmp

# Full system backup excluding regenerable directories
sudo tar -czpf /backup/system-$(date +%F).tar.gz / \
  -X /etc/backup-exclude.txt

# ============================================
# PART 3: THE DIFFERENTIAL BACKUP
# ============================================

# Store the timestamp of the full backup
sudo date +%F > /backup/last-full-date

# Days later, create a differential backup
sudo tar -czpf /backup/diff-$(date +%F).tar.gz \
  --newer="$(cat /backup/last-full-date)" \
  /etc /home

# ============================================
# PART 4: THE INCREMENTAL BACKUP (GNU)
# ============================================

# Create the snapshot file with the first full backup
sudo tar -czpf /backup/inc-full.tar.gz \
  --listed-incremental=/backup/snapshot.snar \
  /etc /home

# Next day, incremental backup
sudo tar -czpf /backup/inc-$(date +%F).tar.gz \
  --listed-incremental=/backup/snapshot.snar \
  /etc /home

# The incremental archive contains only changed files.

# ============================================
# PART 5: INSPECTING AN ARCHIVE
# ============================================

# List all files in the archive
tar -tzf /backup/full-$(date +%F).tar.gz | head -20

# List with details
tar -tvzf /backup/full-$(date +%F).tar.gz | head -10

# Count the files
tar -tzf /backup/full-$(date +%F).tar.gz | wc -l

# Search for a specific file
tar -tzf /backup/full-$(date +%F).tar.gz | grep "nginx.conf"

# ============================================
# PART 6: EXTRACTING TO A TEST DIRECTORY
# ============================================

# Create the test directory
mkdir -p /tmp/restore-test

# Extract the full backup
sudo tar -xzpf /backup/full-$(date +%F).tar.gz -C /tmp/restore-test

# Verify the structure
ls /tmp/restore-test/etc/nginx/

# ============================================
# PART 7: EXTRACTING A SINGLE FILE
# ============================================

# Extract just nginx.conf
mkdir -p /tmp/single-file
sudo tar -xzf /backup/full-$(date +%F).tar.gz \
  etc/nginx/nginx.conf \
  -C /tmp/single-file

# The file is now at /tmp/single-file/etc/nginx/nginx.conf

# ============================================
# PART 8: THE PIPE-TO-STDOUT PATTERN
# ============================================

# Use - to write the archive to stdout
# This is useful for piping over SSH

# Send a backup over SSH
tar -czf - /etc | ssh user@remote "cat > /backup/etc-$(date +%F).tar.gz"

# Receive and extract on the remote
ssh user@remote "tar -xzf /backup/etc-$(date +%F).tar.gz -C /restore"

# ============================================
# PART 9: THE VERIFICATION STEP
# ============================================

# Verify that a gzip archive is complete
gzip -t /backup/full-$(date +%F).tar.gz && echo "Archive OK"

# Or simply list the archive — if it lists, it is readable
tar -tzf /backup/full-$(date +%F).tar.gz > /dev/null && echo "Archive OK"

# ============================================
# PART 10: THE AUTOMATED BACKUP SCRIPT
# ============================================

#!/bin/bash
# /usr/local/bin/backup.sh

BACKUP_DIR="/backup"
DATE=$(date +%F)
EXCLUDE_FILE="/etc/backup-exclude.txt"

# Full backup on Sundays
if [ "$(date +%u)" -eq 7 ]; then
    tar -czpf "$BACKUP_DIR/full-$DATE.tar.gz" / -X "$EXCLUDE_FILE"
    echo "$DATE" > "$BACKUP_DIR/last-full-date"
else
    # Differential backup on other days
    tar -czpf "$BACKUP_DIR/diff-$DATE.tar.gz" \
        --newer="$(cat "$BACKUP_DIR/last-full-date")" \
        /etc /home
fi

# Verify the archive
if tar -tzf "$BACKUP_DIR/"*.tar.gz > /dev/null 2>&1; then
    echo "Backup completed: $DATE"
else
    echo "Backup FAILED: $DATE" >&2
    exit 1
fi

The ten parts cover the basic full backup, the exclusion file, the differential backup, the incremental backup, inspecting an archive, extracting to a test directory, extracting a single file, the pipe-to-stdout pattern, the verification step, and the automated backup script.


Quick Reference

The Core Operations

OperationFlagExample
Create-ctar -cf archive.tar /path
Extract-xtar -xf archive.tar
List-ttar -tf archive.tar
Append-rtar -rf archive.tar newfile
Update-utar -uf archive.tar newfile

The Compression Flags

FlagCompressionExtension
-zgzip.tar.gz
-jbzip2.tar.bz2
-Jxz.tar.xz
--zstdzstd.tar.zst
(none)Uncompressed.tar

The Useful Options

OptionPurpose
-vVerbose output
-pPreserve permissions
-C dirChange to directory
--exclude=patternExclude files
-X fileExclude from file
--newer=dateInclude only newer files
--listed-incremental=fileGNU incremental backup
-f -Write to stdout

The Common Patterns

TaskCommand
Full backuptar -czpf backup.tar.gz /path
Extract to directorytar -xzf backup.tar.gz -C /tmp
List contentstar -tzf backup.tar.gz
Extract one filetar -xzf backup.tar.gz path/to/file
Backup over SSHtar -czf - /path | ssh host "cat > file"
Differentialtar --newer=date -czpf diff.tar.gz /path
Incremental (GNU)tar --listed-incremental=snap -czpf inc.tar.gz /path

Best Practices

✅ Do This:

# Use the conventional extension for compression
tar -czpf backup.tar.gz /path                                   # ✅
# Store relative paths by changing into the parent directory
cd /home && tar -czpf /backup/user.tar.gz user                  # ✅
# Exclude pseudo-filesystems from system backups
tar -czpf system.tar.gz / --exclude=/proc --exclude=/sys        # ✅
# Test the restore before relying on the backup
tar -xzf backup.tar.gz -C /tmp/restore-test                     # ✅
# Verify the archive after creating it
tar -tzf backup.tar.gz > /dev/null && echo "OK"                 # ✅

❌ Don’t Do This:

# Don't store absolute paths without -P
tar -cf backup.tar /home/user                                   # ⚠️ extracts to /home/user
# Don't forget -p for system files
tar -czf backup.tar.gz /etc                                     # ❌ loses ownership
# Don't extract untrusted archives as root
sudo tar -xzf untrusted.tar.gz                                  # ❌ security risk
# Don't back up /proc, /sys, /dev
tar -czf backup.tar.gz /proc /sys /dev                          # ❌ regenerated on boot

Common Pitfalls

PitfallWhy It HappensFix
Permission errorsNot running as root for system filesUse sudo
Extraction goes to wrong placeArchive stored absolute pathsUse relative paths or -C
Archive larger than expectedNot excluding regenerable dirsUse --exclude or -X
Compression not appliedForgot the -z flagAdd -z, -j, -J, or --zstd
Restored files have wrong ownerMissing -p flagUse -p and run as root
Backup silently corruptedNever tested the archiveVerify with tar -tzf

Real-World Examples

1. Full Directory Backup

tar -czpf /backup/home-$(date +%F).tar.gz /home

2. System Backup with Exclusions

tar -czpf /backup/system.tar.gz / -X /etc/backup-exclude.txt

3. Differential Backup

tar -czpf /backup/diff.tar.gz --newer="$(cat /backup/last-full-date)" /etc

4. Incremental Backup (GNU)

tar -czpf /backup/inc.tar.gz --listed-incremental=/backup/snap.snar /etc

5. Extract to Directory

tar -xzf /backup/home.tar.gz -C /tmp/restore

6. Extract One File

tar -xzf /backup/home.tar.gz home/user/.bashrc -C /tmp

7. List with Details

tar -tvzf /backup/home.tar.gz | head

8. Backup over SSH

tar -czf - /etc | ssh user@remote "cat > /backup/etc.tar.gz"

9. Extract from SSH

ssh user@remote "tar -czf - /etc" | tar -xzf - -C /tmp/restore

10. Verify Archive

tar -tzf /backup/home.tar.gz > /dev/null && echo "OK"

Visual

The tar Pipeline

┌──────────────────────────────────────────────┐
│  TAR PIPELINE                                │
│                                              │
│  Files ──> tar ──> [compressor] ──> archive  │
│                                              │
│  tar -c : reads files, writes headers        │
│  tar -z : pipes to gzip                      │
│  tar -f : writes to the named file           │
│                                              │
│  Reverse for extraction:                     │
│  archive ──> [decompressor] ──> tar ──> files│
│                                              │
└──────────────────────────────────────────────┘

The tar Flag Anatomy

┌──────────────────────────────────────────────┐
│  tar -czpf archive.tar.gz /path              │
│                                              │
│  c : create                                  │
│  z : gzip compress                           │
│  p : preserve permissions                    │
│  f : write to file (next arg is filename)    │
│                                              │
│  The order matters: -f must precede the name.│
│  Combined flags must all precede the filename│
│  unless -f is separate.                      │
│                                              │
└──────────────────────────────────────────────┘

The Full, Differential, Incremental Chain

┌──────────────────────────────────────────────┐
│  BACKUP CHAIN WITH tar                       │
│                                              │
│  Sunday:  tar -czpf full.tar.gz /etc /home   │
│           date +%F > last-full-date          │
│                                              │
│  Monday:  tar --newer=last-full-date         │
│             -czpf diff-mon.tar.gz /etc /home │
│                                              │
│  Tuesday: tar --newer=last-full-date         │
│             -czpf diff-tue.tar.gz /etc /home │
│                                              │
│  The differential includes everything since  │
│  the full. It grows each day.                │
│                                              │
│  Restore: full.tar.gz + most recent diff.    │
│                                              │
└──────────────────────────────────────────────┘

The Exclude Patterns

┌──────────────────────────────────────────────┐
│  EXCLUDE PATTERNS                            │
│                                              │
│  --exclude=/proc                             │
│    └─ Excludes /proc at archive root         │
│                                              │
│  --exclude='*.log'                           │
│    └─ Excludes any file ending in .log       │
│                                              │
│  --exclude='/home/*/.cache'                  │
│    └─ Excludes .cache in any home directory  │
│                                              │
│  -X /etc/backup-exclude.txt                  │
│    └─ Reads one pattern per line             │
│                                              │
└──────────────────────────────────────────────┘

Summary

ItemValue
Create archivetar -cf archive.tar /path
Gzip compression-z → .tar.gz
bzip2 compression-j → .tar.bz2
xz compression-J → .tar.xz
zstd compression--zstd → .tar.zst
Extracttar -xf archive.tar
Listtar -tf archive.tar
Change directory-C /path
Preserve permissions-p
Exclude--exclude=pattern or -X file
Differential--newer=date
Incremental (GNU)--listed-incremental=snapshot
Pipe to stdout-f -

Key takeaways:

  • tar bundles files into a single archive, and compression is an additional flag. -z for gzip, -j for bzip2, -J for xz, --zstd for zstd. The archive is not compressed without one of these flags .
  • Create with -c, extract with -x, list with -t. All three take the -f flag followed by the archive name, and all three accept the compression flags in the same position. The pattern is consistent across operations.
  • Use relative paths by changing into the parent directory. cd /home && tar -czpf /backup/user.tar.gz user stores user/... rather than /home/user/.... This is safer for extraction, because the archive will not overwrite system files if extracted from the wrong location .
  • Exclude regenerable directories from system backups. /proc, /sys, /dev, /tmp, /run, /mnt, /media, and cache directories should not be backed up. They are regenerated on boot or contain no useful data. Use --exclude or -X .
  • -p preserves permissions and ownership. This is essential for system backups made and restored by root. Without it, restored /etc files may have the wrong ownership and break services .
  • Use --newer for differential backups with tar. The flag includes only files modified after the reference date. Store the full backup date in a file, and reference it for each differential .
  • Use --listed-incremental for GNU incremental backups. The snapshot file records the state at the last backup. Each run compares against the snapshot, includes only changes, and updates the snapshot. Restore requires the full backup plus every incremental in order .
  • Always verify the archive after creating it. tar -tzf archive.tar.gz > /dev/null reads every header and confirms that the archive is readable. A backup that cannot be listed cannot be restored. Run the verification in the backup script and alert on failure.

Remember: tar is the workhorse of Linux backups. It turns a directory tree into a stream, preserves metadata, integrates with compression, and can write to disk, tape, or another process over SSH. Learn the three operations — create, extract, list — and the compression flags. Use relative paths and exclusions. Preserve permissions with -p. Use --newer for differential backups and --listed-incremental for GNU incremental backups. Verify every archive. And test the restore. A tar archive that has never been extracted is not a backup; it is a file that might be a backup.


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!