2026-07-07
Every so often a tool comes along that feels like it shouldn't be legal. criu — Checkpoint/Restore In Userspace — freezes a running process (or an entire process tree), dumps its memory, open files, sockets, timers, and pending signals into a directory of image files, and then resumes it later. Same box. Different box. Hours later. It doesn't care.
Podman, LXC, and OpenVZ all use it under the hood for live container migration. Almost nobody knows they can drive it themselves for a bare process.
First, sanity-check that your kernel exposes the knobs criu needs:
criu check --all
Now the party trick. Start a long-running Python job in one terminal:
$ python3 -c 'import time,itertools
for i in itertools.count(): print(i); time.sleep(1)'
0
1
2
In another terminal, freeze it to disk:
mkdir /tmp/ckpt
sudo criu dump -t $(pgrep -f 'itertools.count') \
-D /tmp/ckpt --shell-job --leave-running
--shell-job tells criu the process is attached to a controlling terminal it should reconnect. --leave-running keeps the original alive after the snapshot — omit it and criu kills the source, which is what you want for migration.
Kill the original, wait a while, then bring it back exactly where it left off:
sudo criu restore -D /tmp/ckpt --shell-job
7
8
9
The counter picks up mid-stream. Same PID (if available), same memory, same open file descriptors.
Where this earns its keep:
rsync the checkpoint directory to another machine and criu restore there. Works for TCP connections too with --tcp-established.gdb.The TCP trick deserves its own callout. Add --tcp-established on both dump and restore, and criu will freeze the socket state, negotiate with the kernel's tcp_repair mode, and hand a live connection back to the restored process — the peer never notices. Combine with iptables to briefly drop packets during the swap and you get true live migration of a server holding open sockets.
Incremental checkpoints work via --track-mem and --prev-images-dir: the first dump is full, subsequent ones capture only pages that changed. This is how container platforms do warm-swap upgrades.
Some things criu can't handle without help: external state it doesn't own (a mounted NFS handle a peer has forgotten), some exotic file descriptor types (perf, some netlink), and process trees that opened namespaces in unusual configurations. It'll tell you exactly which fd it choked on and you can whitelist it with --ext-unix-sk, --ext-mount-map, and friends.
The mainstream alternative to criu is… there isn't one. You either write your program to serialize its own state (weeks of work, and you'll get it wrong), or you don't do checkpoint/restore at all. criu does it for arbitrary binaries you didn't write.
