Matte black server drive standing like a vault door in a dark datacenter, an emerald keyhole seal on its face lit by a single laser beam arriving from off-frame
Guide

Encrypt a VPS disk with LUKS

Encrypting a disk is the easy part. Doing it on a machine you cannot physically touch — so it still reboots at 04:00 without you sitting at a console — is the part most guides skip. And being clear about what encryption actually buys you on rented hardware is the part almost all of them skip. This guide does all three: a LUKS2 root volume installed from rescue mode, unlocked remotely over SSH, with a plain account of the threats it stops and the ones it does not.

“Is my data encrypted?” is the question we get most often, and the honest answer is: not unless you encrypt it. We do not encrypt your disks for you, and that is deliberate — a key we hold is a key we can be compelled to produce. Our documentation says so in one line; this guide is the long version, with the commands.

What follows is the procedure we actually use: a small unencrypted /boot, everything else inside a LUKS2 container, and a tiny SSH server living in the initramfs so the passphrase can be typed from anywhere in the world at boot time. It works identically on all four of our regions — Paris, Reykjavík, Zürich and Bucharest — because the hardware is identical. It also works on any other provider that gives you a rescue mode. The last section states the limits, because a guide that only tells you what encryption fixes is selling something.

What disk encryption on a VPS actually protects

Encryption is not a general-purpose privacy setting. It answers exactly one question: can someone read these blocks without the key? Everything else — who knows you rented the server, whether traffic is attributable to you, whether a court can compel anything — lives elsewhere.

On a VPS, LUKS meaningfully defends against:

  • Decommissioned and failed hardware. NVMe drives are replaced. Secure-erase on a failed device is not always possible — sometimes it is dead enough that the controller no longer accepts commands, and it leaves the rack anyway.
  • An offline image. A volume copied while the server is powered off — during a seizure, a migration, a mistake — is ciphertext and stays ciphertext.
  • Backups and snapshots that travel. Anything leaving the machine leaves encrypted if it is taken from the block layer below your control, and should be encrypted client-side if it is taken from above it.
  • Residual blocks. When you destroy a server, the underlying extents are eventually reused. Encryption makes the leftovers noise rather than data.

It does not defend against a running machine. While your server is up, the master key sits in kernel memory, and anyone able to dump that memory reads your disk regardless of the passphrase. On rented infrastructure that means the hypervisor operator. We say this on our privacy notice and we will say it here: no provider's disk-encryption feature changes this, including ours, and any provider claiming otherwise is describing marketing rather than cryptography.

Three models, and which one you actually need

Before touching a terminal, pick the model. They differ enormously in effort, and most people need the first one.

1. An encrypted data volume. The system boots normally and unencrypted; one directory tree — a maildir, a database, an archive — lives inside a LUKS container that you open by hand after each boot. Ten minutes of work, no rescue mode, no risk of locking yourself out. If what you care about is one dataset rather than the whole machine, stop here; you get most of the benefit for almost none of the fragility. This is the pattern we recommend on the anonymous mail server page.

2. An encrypted root volume with remote unlock. Everything except /boot is encrypted, and every boot pauses in the initramfs until you SSH in and supply the passphrase. This is the model the rest of this guide builds. It costs an hour the first time and one SSH command per reboot, and it is the only model where logs, package caches, shell history and swap are covered too — the places data leaks to without anyone deciding it should.

3. An encrypted root that unlocks itself against a key server you control. Same as model 2, but Clevis fetches the unlock material from a Tang server on a machine in another jurisdiction, so reboots are unattended. The trade-off is precise and worth understanding: the server can now decrypt itself as long as your key server says yes, which means you have moved the secret rather than removed it — but you have also gained a remote kill switch. Covered further down.

Why we do not encrypt your disk for you

Plenty of hosts advertise “encryption at rest” as a checkbox. It is worth being precise about what that phrase usually means, because two very different things hide behind it.

Encryption with a key the provider holds protects against a stolen drive and nothing else. If the provider can boot your server without asking you anything, the provider can decrypt your server without asking you anything — and so can anyone who can compel the provider. It is a real control against theft and a purely decorative one against legal process.

Encryption with a key you hold is the meaningful version, and it breaks unattended reboot by construction. That is not a flaw to be engineered away; it is the property doing the work.

We ship the second option only, unconfigured, and let you decide. What we do hold is narrower and documented: server root passwords are stored AES-256-CBC encrypted at the row level, we retain no flow logs or packet captures, and a signed warrant canary is published on a schedule. None of that is a substitute for your own key — it is the part we can be held to in the meantime.

Cipher, key size and the Argon2 memory trap

The defaults are good. Two of them are worth overriding.

Cipher. aes-xts-plain64 with a 512-bit key is the default and the right answer — the 512 bits are two 256-bit keys, so this is AES-256 in XTS mode, and every CPU we run has AES-NI. On a machine without AES acceleration you would prefer xchacha20,aes-adiantum-plain64, but that is not our hardware and probably not yours.

Key derivation. LUKS2 defaults to Argon2id, which is memory-hard on purpose. cryptsetup benchmarks your machine at format time and picks a memory cost from the RAM it can see — and here is the trap that produces most “my encrypted server will not boot” reports: the initramfs has less usable memory than the running system, and if you formatted the volume in a rescue environment with more RAM than the target plan has, the unlock can fail or be killed at boot. Pin it explicitly. One GiB of Argon2 memory is a serious cost for an attacker and comfortably within reach of an S1 with 4 GB:

cryptsetup luksFormat --type luks2 \
  --cipher aes-xts-plain64 --key-size 512 --hash sha256 \
  --pbkdf argon2id --pbkdf-memory 1048576 --pbkdf-parallel 4 \
  /dev/vda2

--pbkdf-memory is in KiB, so 1048576 is 1 GiB. Check what actually landed in the header afterwards with cryptsetup luksDump /dev/vda2 — the keyslot section prints the memory and iteration counts it will use, and reading that once is cheaper than a failed boot.

The passphrase. Argon2 buys time against a weak passphrase; it does not rescue one. Use a diceware phrase of at least six words. It is the only secret in the system and no key-derivation function compensates for a bad one.

How remote unlock actually works

A Linux boot with an encrypted root has a chicken-and-egg problem: the kernel and the initramfs must load before anything can ask for a passphrase, and they live on the disk you are trying to unlock. The standard answer is a small unencrypted /boot partition holding the kernel, the initramfs and the bootloader. Everything else goes inside LUKS.

The initramfs then pauses and asks for the passphrase. On a laptop you type it. On a server three thousand kilometres away, you need one of two things:

  • The console. Every server in your dashboard has a noVNC console, and it works — but the keystrokes traverse our infrastructure, which is precisely the party your key is supposed to exclude. Fine for a one-off recovery, wrong as a routine.
  • An SSH server inside the initramfs. dropbear-initramfs is about 200 KB, brings up the network, listens on a port you choose, accepts one of your public keys, and drops you straight into the unlock prompt. The passphrase is encrypted end-to-end from your laptop to the initramfs. This is the right answer.

Two details catch people out. The initramfs Dropbear has its own host key, so its fingerprint differs from your normal SSH daemon's — that is expected, not a man-in-the-middle, and it deserves its own known_hosts file rather than a habit of typing yes. And the interface name must be right: virtio NICs on Debian 13 usually come up as ens3 or enp1s0, not eth0. Check with ip -br link before you write the config, because getting it wrong means an initramfs with no network and a trip to the console.

Unattended reboots with Clevis and Tang

If the machine must come back on its own — after a kernel update, a host reboot, a power event — typing a passphrase is not viable. Clevis binds a LUKS keyslot to an external policy, and Tang is a tiny key-exchange server implementing the simplest useful one.

# on a small server you control, elsewhere
apt install -y tang
systemctl enable --now tangd.socket

# on the encrypted VPS
apt install -y clevis clevis-luks clevis-initramfs
clevis luks bind -d /dev/vda2 tang '{"url":"http://tang.internal:7500"}'
update-initramfs -u -k all

At boot the initramfs performs a McCallum-Relyea exchange with Tang and recovers the key without the Tang server ever learning it or seeing the passphrase. The properties are worth stating precisely:

  • The VPS decrypts itself only while it can reach Tang. Shut Tang down, or rotate its keys, and the next boot stops dead. That is a genuine remote kill switch — unusual and useful.
  • Tang should not be on the public internet. Reach it over WireGuard or as a Tor onion service; we cover the tunnel side in the WireGuard guide.
  • Put Tang in a different jurisdiction from the data. Our jurisdiction pages exist for exactly this kind of split.
  • Keep a passphrase in another keyslot. Clevis is a convenience layer, not your only way in.

Understand what you have built: an unattended machine holds its own key by proxy, so an adversary who seizes the VPS while it is running, or who can reach your Tang server, gets the data. That is a real weakening compared with a passphrase in your head. Choose it when availability matters more than the last increment of secrecy, and not by default.

Swap, temp files and the places plaintext leaks

An encrypted root covers most of the surface, but a few paths write outside it or survive it.

  • Swap. Anything in RAM can be paged to disk — keys, message bodies, decrypted buffers. If swap lives inside the encrypted volume as a swapfile, it is covered. A separate swap partition is not, unless you add it to /etc/crypttab with a random key that changes every boot: cryptswap /dev/vda3 /dev/urandom swap,cipher=aes-xts-plain64,size=256. On a VPS the swapfile is simpler and there is no reason to prefer the partition.
  • /tmp. Mount it as tmpfs (tmpfs /tmp tmpfs defaults,nosuid,nodev,size=512M 0 0) so it never touches the disk at all. Faster too.
  • Hibernation. Writes the whole of RAM, including your master key, to the swap device. Do not enable it. It is off by default on our images.
  • The unencrypted /boot. Kernels, initramfs images and GRUB config are readable and, more importantly, writable by anyone with offline access to the disk. LUKS gives you confidentiality, not boot integrity. If your threat model includes someone tampering with the bootloader, encryption alone will not catch it — record the hashes of /boot after each kernel update and check them from outside, or accept the gap consciously.
  • Existing snapshots and old volumes. Encrypting today does nothing for an image taken yesterday. If the server ever ran unencrypted with data you care about, treat that data as exposed and rotate anything derived from it.

Performance: what it costs and what to tune

The overhead is small enough that it should not drive the decision, but it is not zero. Measure before you speculate:

cryptsetup benchmark

On our EPYC nodes, aes-xts at a 512-bit key benchmarks in the low gigabytes per second per core — comfortably above what a single NVMe volume will demand. The cost that actually shows up is latency and CPU on small random writes, not throughput.

Two LUKS2 flags matter on NVMe, where the kernel's dm-crypt work queues add latency instead of removing it. Set them and make them stick in the header:

cryptsetup refresh cryptroot \
  --perf-no_read_workqueue --perf-no_write_workqueue --persistent

The third flag, --allow-discards, passes TRIM through to the underlying device. It keeps write amplification down over the life of the volume, at the cost of revealing which blocks are unused — which leaks the approximate size and shape of your data to anyone reading the raw device. Enable it for a general-purpose server; leave it off if the fact that a volume is 3% full is itself sensitive. There is no universally right answer, only a decision you should make on purpose.

The header, the key slots and the day something goes wrong

The LUKS header is roughly 16 MB at the front of the partition, and it holds the encrypted copies of the master key. Damage it — a mistyped dd, a partition tool that helpfully rewrites the start of the device — and every byte behind it is gone. There is no recovery service. We do not have a copy.

# back it up, off the server, before you put data on the volume
cryptsetup luksHeaderBackup /dev/vda2 \
  --header-backup-file luks-header-$(date +%F).img

# add a second passphrase while you still have the first
cryptsetup luksAddKey /dev/vda2

# see what is in the header
cryptsetup luksDump /dev/vda2

Two things about that backup. It is as sensitive as the disk: it contains keyslots, so an old header restored after you changed your passphrase will happily accept the old one. Store it the way you store the passphrase, and destroy stale copies when you rotate. Second, LUKS2 gives you 32 keyslots — use at least two, with the spare being a long random passphrase held somewhere your daily one is not. The failure mode this prevents is boring and common: you rotate the passphrase, mistype it identically twice, and discover it at the next reboot rather than at the next login.

Have a way back in, too. Rescue mode boots the server from our ISO with your SSH keys injected and the encrypted volume untouched, which means you can cryptsetup open /dev/vda2 rescue && mount /dev/mapper/rescue /mnt and repair a broken crypttab or a bad initramfs without losing the data. Test that once, deliberately, while nothing is wrong.

What encryption cannot do, stated plainly

The most useful thing a guide like this can do is mark its own boundary.

  • It does not protect a running server. The master key is in kernel memory from unlock until shutdown. Hypervisor-level memory access defeats it. Memory encryption — AMD SEV-SNP and equivalents — is the only technology that changes this materially, and we do not expose it today; a provider that claims your running VM is opaque to it, without SEV, is mistaken or lying.
  • It does not make you anonymous. An encrypted disk in Zürich still has an IP, a billing trail and an SSH session that started somewhere. That is a different problem, and we wrote up the ways it goes wrong in the mistakes that deanonymize you.
  • It does not change what a court can order. Jurisdiction governs compulsion; encryption governs readability. In some jurisdictions you can be ordered to disclose a passphrase personally. Our legal-process guide covers what we do and do not action.
  • It does not survive a passphrase you lose. By design, and worth repeating, because the support ticket asking us to help arrives about once a month and the answer is always the same.
  • It does not authenticate the boot chain. Confidentiality is not integrity. /boot is readable and modifiable offline.

What it does do is remove one entire class of exposure — everything that happens to a disk when it is not running, which is most of what happens to disks. That is worth an hour. Combine it with a no-KYC signup, Monero payment and a jurisdiction chosen on purpose, and each layer covers a different failure. None of them covers all of them.

  1. Deploy the server and boot it into rescue mode

    Deploy any plan and region with a stock Debian 13 image — the installed system is about to be replaced, so the choice of image barely matters. Then go to Server → Recovery → Boot into rescue. The rescue environment injects the SSH keys already on your account and leaves the disk untouched, so you get a root shell with /dev/vda unmounted and free. Note that the rescue host key fingerprint differs from the installed system's; that is expected.

  2. Partition the disk: a small plaintext /boot, one large LUKS container

    Two partitions. One gigabyte for /boot — enough for several kernels — and the rest for the encrypted volume.

    sgdisk --zap-all /dev/vda
    sgdisk -n1:0:+1G   -t1:8300 -c1:boot   /dev/vda
    sgdisk -n2:0:0     -t2:8309 -c2:crypt  /dev/vda
    partprobe /dev/vda && lsblk /dev/vda

    Type 8309 marks the second partition as a Linux LUKS volume. If your server boots in UEFI mode, make partition 1 an ESP (-t1:ef00, formatted FAT32 and mounted at /boot/efi) and add a separate 1 GB /boot; the BIOS layout above is what our images use by default.

  3. Create the LUKS2 volume and open it

    Pin the Argon2 memory cost explicitly so the initramfs can afford it later.

    cryptsetup luksFormat --type luks2 \
      --cipher aes-xts-plain64 --key-size 512 --hash sha256 \
      --pbkdf argon2id --pbkdf-memory 1048576 --pbkdf-parallel 4 \
      /dev/vda2
    
    cryptsetup open /dev/vda2 cryptroot
    mkfs.ext4 -L root /dev/mapper/cryptroot
    mkfs.ext2 -L boot /dev/vda1

    Use a passphrase of at least six diceware words and write it down somewhere physical before you continue. Nobody can recover it for you — that is the property you are paying for.

  4. Install Debian into the encrypted volume

    Mount the new root, debootstrap a base system into it, and bind the kernel filesystems so the chroot behaves.

    mount /dev/mapper/cryptroot /mnt
    mkdir -p /mnt/boot && mount /dev/vda1 /mnt/boot
    
    debootstrap --arch=amd64 trixie /mnt http://deb.debian.org/debian
    
    for d in dev dev/pts proc sys run; do mount --bind /$d /mnt/$d; done
    chroot /mnt /bin/bash

    Inside the chroot, install the pieces that make an encrypted root bootable and reachable:

    apt update && apt install -y linux-image-amd64 grub-pc \
      cryptsetup cryptsetup-initramfs dropbear-initramfs \
      openssh-server ifupdown ca-certificates locales
  5. Write crypttab, fstab and the initramfs network config

    crypttab tells the initramfs which device to unlock; initramfs.conf tells it how to get on the network first. Use the LUKS UUID, never /dev/vda2 — device names move.

    echo "cryptroot UUID=$(blkid -s UUID -o value /dev/vda2) none luks,discard" \
      > /etc/crypttab
    
    cat > /etc/fstab <<'EOF'
    /dev/mapper/cryptroot  /      ext4  defaults,noatime  0 1
    LABEL=boot             /boot  ext2  defaults          0 2
    tmpfs                  /tmp   tmpfs defaults,nosuid,nodev,size=512M 0 0
    EOF
    
    # DHCP on the virtio NIC. Confirm the name with `ip -br link` first.
    echo 'IP=:::::ens3:dhcp' >> /etc/initramfs-tools/initramfs.conf
    echo 'DEVICE=ens3'       >> /etc/initramfs-tools/initramfs.conf

    Drop ,discard from the crypttab line if you would rather not reveal which blocks are unused. For a static address instead of DHCP, the field order is IP=<ip>::<gateway>:<netmask>::<iface>:off.

  6. Put your unlock key in the initramfs and lock Dropbear down

    Only the key you place here can unlock the machine at boot. Keep it separate from your everyday SSH key so that losing one does not lose both.

    install -d -m 0755 /etc/dropbear/initramfs
    cat > /etc/dropbear/initramfs/authorized_keys <<'EOF'
    ssh-ed25519 AAAAC3Nza... unlock@laptop
    EOF
    chmod 0600 /etc/dropbear/initramfs/authorized_keys
    
    cat > /etc/dropbear/initramfs/dropbear.conf <<'EOF'
    DROPBEAR_OPTIONS="-p 2222 -s -j -k -I 180 -c cryptroot-unlock"
    EOF
    
    update-initramfs -u -k all
    dropbearkey -y -f /etc/dropbear/initramfs/dropbear_ed25519_host_key | grep -i fingerprint

    -p 2222 keeps the unlock service off port 22 so it never collides with the running system's sshd; -s forbids password logins, -j and -k disable port forwarding, -I 180 drops idle sessions, and -c cryptroot-unlock makes any successful login go straight to the passphrase prompt. Record that fingerprint now — it is how you will know you are talking to your own initramfs. On Debian 11 and older these files live in /etc/dropbear-initramfs/ instead.

  7. Install the bootloader, set a root password, reboot

    GRUB goes on the disk, not the partition. Because /boot is unencrypted, GRUB_ENABLE_CRYPTODISK is not needed.

    grub-install /dev/vda
    update-grub
    passwd root
    echo 'cryptovps' > /etc/hostname
    exit                    # leave the chroot
    
    umount -R /mnt
    cryptsetup close cryptroot
    reboot

    Then switch the server off rescue mode in the dashboard so it boots from disk. Keep the noVNC console open for this first boot — if the initramfs comes up without a network you will see it there, and you can fix the interface name rather than guess at it.

  8. Unlock remotely and confirm the volume is really encrypted

    Give it thirty seconds, then connect to the initramfs on port 2222. Pin its host key in a file of its own so it never mixes with your normal known_hosts.

    ssh -p 2222 -o UserKnownHostsFile=~/.ssh/known_hosts.initramfs \
        -i ~/.ssh/id_ed25519_unlock root@<server-ip>
    # the passphrase prompt appears immediately; type it, the session closes,
    # and the machine finishes booting into the decrypted root.
    
    # once you are in the running system:
    lsblk -o NAME,FSTYPE,MOUNTPOINT
    cryptsetup status cryptroot
    cryptsetup luksDump /dev/vda2 | head -20

    cryptsetup status should report type: LUKS2, cipher: aes-xts-plain64 and keysize: 512 bits. Now do the two things everyone postpones: back up the LUKS header off the server, and add a second key slot. Then reboot once more on purpose, to prove the unlock path works when you are not expecting it to fail.

Comparison

Three ways to encrypt, and what each costs you

The three practical disk-encryption models on a VPS, compared on the question that decides between them: what happens at the next reboot.
ModelWhat is encryptedAt the next rebootSetup effortBest for
Encrypted data volumeOne directory tree inside a LUKS containerServer boots normally; you open the container by hand~10 minutes, no rescue modeA single sensitive dataset — maildir, database, archive
Encrypted root + remote unlock over SSHEverything except /boot — logs, swap, caches, historyBoot pauses in the initramfs until you SSH in and type the passphrase~1 hour, install from rescue modeA machine whose whole state is sensitive and whose reboots you can attend
Encrypted root + Clevis/TangEverything except /bootUnlocks itself while it can reach your Tang server; stops dead if it cannot~1 hour, plus a second server you controlUnattended machines where availability outweighs the last increment of secrecy
FAQ

أسئلة تستحق الإجابة

Can CryptoVpsHost read the data on my server?

On a running server, yes in principle — and so can any provider of virtualised infrastructure, including the ones that say otherwise. The master key of an unlocked LUKS volume lives in kernel memory, and the hypervisor owns that memory. What LUKS removes is everything else: a powered-off volume, a decommissioned drive, a copied image, a backup. We do not encrypt disks for you precisely because a key we hold is a key we can be compelled to produce, and we would rather say that plainly than sell a checkbox. If your threat model includes the operator of a running machine, no disk-encryption feature from anyone solves it.

Does full-disk encryption slow a VPS down?

Barely, on hardware with AES-NI — which is all of ours. Run cryptsetup benchmark and you will see aes-xts in the low gigabytes per second per core, well above what a single NVMe volume asks for. The measurable cost is a little extra latency and CPU on small random writes, not throughput. On NVMe, setting --perf-no_read_workqueue and --perf-no_write_workqueue with --persistent removes most of what remains.

What happens if I lose the passphrase?

The data is gone. There is no recovery, no master key held in escrow, and no support ticket that changes this — we never had a copy. That is the property you are paying for, and it is why the guide says twice to back up the LUKS header off the server and add a second key slot with a different long passphrase before you put real data on the volume. A passphrase kept in only one place, including only in your head, is a single point of failure.

Is /boot encrypted too?

No, and that is normal. The kernel and the initramfs have to be readable before anything can ask for a passphrase, so they live on a small plaintext partition. GRUB can read an encrypted /boot with GRUB_ENABLE_CRYPTODISK, but it only moves the problem — the bootloader stage before it is still in the clear. The honest framing is that LUKS gives you confidentiality of data at rest, not integrity of the boot chain. If offline tampering with /boot is in your threat model, hash it after each kernel update and verify from outside the machine.

Can the server reboot without me typing anything?

Only if you give it a way to obtain the key, which necessarily weakens the guarantee. The clean version is Clevis bound to a Tang server on a machine you control in another jurisdiction: the VPS unlocks itself while it can reach Tang, and stops dead if it cannot — which doubles as a remote kill switch. Reach Tang over WireGuard or a Tor onion service rather than the public internet, and keep a passphrase in a second keyslot so Clevis is never your only way in.

Can I do this on any OS image, or only Debian?

Any Linux image with a rescue mode works; the commands here are Debian 13 and translate directly to Ubuntu 24.04. On Rocky, Alma and Fedora the tooling is dracut rather than initramfs-tools, so remote unlock uses the dracut-crypt-ssh module or a network-enabled dracut initramfs instead of dropbear-initramfs — the LUKS side is identical. If you would rather not build from a rescue shell at all, upload a custom ISO of up to 4 GiB and use your distribution's installer, which will offer encrypted LVM as a standard option; you then add remote unlock afterwards.

Should I use encryption or a different jurisdiction?

They solve different problems and the question is a false choice. Encryption decides whether blocks are readable; jurisdiction decides who can compel what, and how quickly. A LUKS volume in Paris and a plaintext volume in Zürich fail in completely different ways. Most people who ask this want both, plus a no-KYC signup so there is nothing to disclose in the first place — each layer covers a gap the others leave open. The jurisdiction pages set out what each of our four regions actually offers.

Deploy your offshore server.

اختر منطقة. اختر خطة. الصق مفتاحاً. ادفع. الـ 47 ثانية القادمة على حسابنا.