Encrypted Vault for VPN Secrets and Residual Logs
TL;DR: A LUKS2 file-backed vault holds VPN configuration files, private keys, PKI certificates, and any leftover runtime logs. It protects sensitive assets if a powered-off or decommissioned VPS disk is imaged or inspected.
This article is Part 2 of a 7-part series on building a multi-hop, fail-closed VPS VPN chain with Ansible, LUKS encrypted vaults, Telegram monitoring, and zero-log policy routing.
- Part 1: VPS Baseline: Install, Harden, and Disable Logs
- Part 2: Encrypted Vault for VPN Secrets and Residual Logs
- Part 3: Telegram Alerts Without Leaking the Exit IP
- Part 4: Ansible Playbook for Edge Hop Installation
- Part 5: VPN Chain and End-to-End Encryption Without Persisted Logs
- Part 6: VPN Failover Between VPS Nodes
- Part 7: Operational Tasks: Heal, Add, Remove, and Replace Hops
In Part 1, we hardened the OS baseline and redirected system logs to volatile RAM. However, cryptographic secrets—such as WireGuard private keys and OpenVPN CA certificates—must reside on the node to terminate tunnels.
By creating a LUKS2 file-backed container, /etc/wireguard, OpenVPN PKI data, and /var/log are mounted inside an encrypted block device:
/var/lib/vpn-vault.img LUKS2 container (~5 GB)
└── /vault
├── wireguard -> bind mounted to /etc/wireguard
├── openvpn -> bind mounted to /opt/openvpn-vpn
├── secrets -> Telegram bot tokens & API keys (/vault/secrets)
├── bin -> custom administrative & monitoring scripts (/vault/bin)
└── log -> bind mounted to /var/log
If the underlying VPS host is powered down, snapshotted, or returned to the hosting provider, the disk contains only encrypted ciphertext.
Create a 5 GB file container and format it with LUKS2 encryption:
# Create the image container
fallocate -l 5G /var/lib/vpn-vault.img
cryptsetup luksFormat --type luks2 /var/lib/vpn-vault.img
# Open the mapped device
cryptsetup open /var/lib/vpn-vault.img vpn-vault
mkfs.ext4 /dev/mapper/vpn-vault
mkdir -p /vault
mount /dev/mapper/vpn-vault /vault
Configure automatic boot unlocking via /etc/crypttab:
# Generate a secure keyfile
dd if=/dev/urandom of=/etc/vpn-vault.key bs=512 count=1
chmod 0400 /etc/vpn-vault.key
cryptsetup luksAddKey /var/lib/vpn-vault.img /etc/vpn-vault.key
# Append to /etc/crypttab
echo "vpn-vault /var/lib/vpn-vault.img /etc/vpn-vault.key luks" >> /etc/crypttab
Note: If the root partition is unencrypted, keep a backup of /etc/vpn-vault.key in a secure offline password manager. Without this key, vault data cannot be recovered after an OS reinstall.
Migrate existing configurations into the vault and configure /etc/fstab bind mounts:
mkdir -p /vault/wireguard /vault/openvpn /vault/secrets /vault/bin /vault/log
rsync -aH /etc/wireguard/ /vault/wireguard/
rsync -aH /opt/openvpn-vpn/ /vault/openvpn/
rsync -aH /var/log/ /vault/log/
# Add bind mounts to /etc/fstab
cat <<'EOF' >> /etc/fstab
/vault/wireguard /etc/wireguard none bind 0 0
/vault/openvpn /opt/openvpn-vpn none bind 0 0
/vault/log /var/log none bind 0 0
EOF
systemctl daemon-reload
mount -a
Ensure systemd service units for WireGuard ([email protected]) and OpenVPN load after cryptsetup.target and /vault mounts are active.
A LUKS vault protects offline data at rest. It does not protect against a root compromise on an active, running server. If an attacker gains root access while the server is live, they can read /etc/vpn-vault.key and access /vault directly.
A live compromise must be treated as a total loss of that specific hop node.
For high-security nodes, implement an automated wipe script that destroys the vault header and keyfile if the node loses internet connectivity for an extended period:
- A cron job executes every 2 minutes, probing reliable external IP targets (
1.1.1.1,8.8.8.8). - If connectivity fails continuously for more than 15 minutes, the script wipes the LUKS header using
cryptsetup eraseand shreds/etc/vpn-vault.key. - To prevent false triggers during DNS failures, probe raw IP targets directly rather than hostnames.
- Provide an override lockfile (
/etc/vpn-vault-disarm) to temporarily suspend wipes during scheduled maintenance.
Deploy vault configuration idempotently:
ansible-playbook -i hosts.yaml playbooks/vpn-node-vault.yaml \
-e target_vpn=vpn-1
The playbook verifies that the vault image exists, /etc/crypttab is configured, bind mounts are active, and systemd units order VPN startup after unlock.
Validate the encrypted vault status:
cryptsetup status vpn-vault
findmnt /vault
findmnt /etc/wireguard
systemctl is-active wg-quick@wg0
Reboot the server once to verify that the keyfile unlocks the volume automatically and VPN interfaces initialize without manual intervention.
Next in the series: Part 3: Telegram Alerts Without Leaking the Exit IP - Monitoring SSH logins, daily node status, and bandwidth caps via out-of-band Telegram notifications.