Say you've got a three-node Proxmox cluster and one of those nodes needs a RAM upgrade. Or maybe you just noticed one node is running hot on CPU while another sits mostly idle. Either way, you've got LXC containers sitting on the node you need to touch, and you don't want to destroy and rebuild them just to move house. That's what container migration is for, and it's one of the more underused features in a Proxmox cluster because people assume it works exactly like VM migration. It doesn't, and that difference trips up a lot of beginners.

What You Will Learn

By the end of this tutorial you'll know how to:

  • Move an LXC container from one cluster node to another, both from the web interface and from the command line
  • Understand why containers can't live-migrate the way virtual machines can, and what that means for downtime
  • Use pct migrate with the right flags for your storage setup
  • Fix the most common migration failure: local bind mount points
  • Read the migration task log so you're not guessing when something goes wrong

What Is This Feature?

An LXC container, if you're new to the term, is a lightweight way to run an isolated Linux system that shares the host's kernel instead of emulating its own hardware like a virtual machine does. That's why containers start in a second or two and use a fraction of the RAM a comparable VM would. Proxmox VE builds container support on top of LXC (Linux Containers) and manages everything through a command-line tool called pct, short for Proxmox Container Toolkit.

Migration, in a Proxmox cluster, means moving a container's configuration and its disk (called the rootfs) from one physical node to another node in the same cluster. The container ends up running on different hardware, but from inside the container nothing looks different — same hostname, same IP, same files.

Here's the part that catches people off guard: Proxmox can live-migrate a running virtual machine with essentially zero downtime, but it cannot do the same for a running container. Proxmox's own documentation is blunt about it — running containers cannot be live-migrated due to technical limitations in how LXC checkpointing works. So instead, Proxmox uses what it calls a restart migration for containers that are running.

Why Would You Use It?

The obvious reason is node maintenance. You want to reboot a node for a kernel update, or pull it offline to swap a failing drive, and you'd rather not have your Pi-hole or Nextcloud container going down along with it.

The second reason is load balancing. If you built your cluster gradually and now one node has six containers while another has one, migration lets you spread things out without rebuilding anything.

There's also decommissioning. If you're retiring an old node from the cluster, every container living on it needs to move somewhere else first, and doing that with pct migrate is a lot less painful than backup-and-restore for a dozen containers.

One thing migration is not good for: disaster recovery. If a node dies unexpectedly, you can't migrate a container off it — migration needs the source node to be alive and reachable. For that scenario you want backups and, if you've set it up, storage replication, which is a different feature covered elsewhere.

Prerequisites

Before you try this, make sure you actually have the pieces in place:

  • A working Proxmox VE cluster with at least two nodes joined and showing green (quorum OK) in the web interface under Datacenter. A single standalone node has nowhere to migrate to.
  • An existing LXC container you want to move. If you don't have one yet, create a test container first — don't practice this on something you care about.
  • A user account with the VM.Migrate permission on the container, or you're logged in as root, which has it by default.
  • Enough free RAM and disk space on the target node to actually host the container. Proxmox will refuse the migration if the target can't fit it.
  • If the container uses local storage (like local-lvm or local-zfs), the same storage ID needs to exist and be enabled on the target node, or you'll need to map it to a different one during migration.

It also helps to know whether your storage is shared or local, because it changes what migration actually does under the hood. Shared storage — think NFS, Ceph, or iSCSI with LVM — is reachable from every node at once, so the container's disk doesn't need to move at all; only the config and the running process do. Local storage, like a ZFS pool or LVM-thin volume that only exists on one physical node, has to be copied byte-for-byte across the network to the target node as part of the migration.

Step-by-Step Tutorial

Option 1: Migrating from the Web Interface

This is the easiest way if you're not comfortable on the command line yet.

  1. Log in to the Proxmox web interface at https://your-node-ip:8006.
  2. In the left-hand tree, click the container you want to move.
  3. Click Migrate in the top-right corner of the container's summary panel.
  4. In the dialog, pick the Target node from the dropdown.
  5. If the container is currently running, you'll see a Mode option — leave it on restart mode unless you specifically know you need something else (more on why below).
  6. Click Migrate and watch the task log that opens. When it finishes with TASK OK, the container is on the new node.

Option 2: Migrating from the Command Line

Open a shell on the source node — the one currently hosting the container — either through the web console or SSH, and run:

pct migrate 105 pve2

Here, 105 is the container's VMID and pve2 is the name of the target node exactly as it appears under Datacenter in the GUI. If the container is stopped, this does a plain offline migration: Proxmox copies the config and the disk data, then you start the container manually on the new node with pct start 105.

If the container is running, plain pct migrate without any extra flags will refuse to proceed and tell you the container needs to be stopped first. To migrate it while it's live, add the restart flag:

pct migrate 105 pve2 --restart

This shuts the container down, moves it, and starts it back up on pve2 automatically. If your container sits on shared storage, this whole process usually takes well under a second of actual downtime, because there's no disk data to copy — just a stop and a start. If it's on local storage, the downtime lasts as long as the disk copy takes, which for a container with a few gigabytes of data is usually well under a minute, but can take longer for anything bigger.

By default, a restart migration waits up to 180 seconds for the container to shut down cleanly before forcing it. You can shorten or extend that with --timeout:

pct migrate 105 pve2 --restart --timeout 60

If you need to change which storage the container lands on — say the target node calls its ZFS pool something different — map it explicitly:

pct migrate 105 pve2 --restart --target-storage local-zfs

And if you're migrating over a shared or slow network link and don't want the transfer to saturate it, cap the bandwidth in KiB/s:

pct migrate 105 pve2 --restart --bwlimit 51200

That example limits the copy to roughly 50 MB/s, which is a reasonable ceiling on a 1 Gbps link if you still want to use SSH or the web UI while it runs.

Confirming the Migration Worked

Once the task log shows TASK OK, run pct list on the target node. Your container should show up there with a status of running (or stopped, if you migrated it offline). Run the same command on the old node and it should be gone from the list entirely — Proxmox doesn't leave a copy behind.

Commands Explained

FlagWhat it does
pct migrate <vmid> <target>Base command. Works on its own only if the container is stopped.
--restartRequired for a running container. Stops it, migrates it like an offline copy, then starts it on the target node.
--timeout <seconds>How long to wait for a clean shutdown during restart mode before Proxmox forces it. Default is 180.
--target-storage <storage>Maps the container's disk to a specific storage ID on the target node, if it isn't named the same as the source.
--bwlimit <KiB/s>Caps how much network bandwidth the migration is allowed to use.
--onlineTechnically listed in the pct reference, but skip it. Container checkpointing isn't reliable enough for production use, and Proxmox's own docs say running containers can't be truly live-migrated. --restart is the real answer, and it's fast enough that most people never notice.

Worth calling out: pct migrate is the CLI equivalent of clicking Migrate in the GUI. Neither one is "the advanced way" — they run the exact same task on the backend, so pick whichever fits how you work.

Common Errors

"can't migrate running container without --restart or --online"

You tried to migrate a running container without telling Proxmox how to handle that. Add --restart and run it again.

"cannot migrate local bind mount point 'mp0'"

This is the one that catches almost everyone eventually. If your container has a mount point pointing at a raw host directory or block device — a bind mount rather than a Proxmox-managed storage volume — Proxmox has no way to guarantee that same path or device exists on the target node, so it refuses to migrate rather than silently break something. Two ways around it: either make sure the exact same path is available on every node and add shared=1 to that mount point's config line, or move the data onto proper Proxmox storage (like a mount point on your ZFS pool or NFS share) instead of a raw bind mount.

"storage 'local-lvm' is not available on node 'pve3'"

The container's disk lives on a storage ID that either doesn't exist on the target node or isn't enabled there. Check Datacenter > Storage and either enable that storage on the target node or use --target-storage to redirect it somewhere that does exist.

Migration hangs at "volume already locked"

A previous migration, backup, or snapshot operation on that container didn't finish cleanly and left a lock in place. Check pct config <vmid> for a lingering lock: line, and if nothing is actually running against it, clear it with pct unlock <vmid>.

Troubleshooting

When a migration fails and the error message alone doesn't tell you enough, the task log is your best friend. Open it from Datacenter > Tasks, find the failed migration, and read the full output — it almost always names the exact storage, mount point, or permission that's the problem.

If the migration seems to start but then times out partway through, check the network link between the two nodes. Run a quick iperf3 test between them if you have it installed, or just ping and check for dropped packets. A flaky corosync or migration network is a common but easy-to-miss cause.

If the target node rejects the container for lack of resources, check Node > Summary on the target for current RAM and disk usage. Proxmox checks the container's configured maximums against what's free, not what's actually being used, so a container configured for 8 GB of RAM needs 8 GB free on the target even if it normally uses 2.

And if quorum is the issue — you'll usually see a warning about it in the GUI before you even try — a migration won't start at all until the cluster has quorum again. Check Datacenter > Cluster to confirm all expected nodes are online.

Best Practices

Put containers you expect to migrate often on shared storage if you have it. It turns every future migration into a near-instant stop-and-start instead of a full disk copy.

Test migrations during a maintenance window the first few times, even though restart-mode downtime is usually brief. "Usually brief" isn't the same as zero, and you want to know how your specific setup behaves before you're relying on it during an actual emergency.

Avoid raw bind mounts to host paths in containers you plan to move between nodes. They work fine on a single node, but they're the single most common thing that blocks migration later. Use Proxmox-managed mount points instead — they migrate cleanly.

Keep VMIDs unique across the whole cluster, not just per node. Proxmox already enforces this, but if you're scripting container creation, don't assume you can reuse an ID just because it's free on the node you're working from.

If a container is managed by Proxmox's HA stack, you don't need to do anything special — HA tracks the container's location automatically after a manual migration. You don't have to update anything in the HA resource configuration by hand.

Frequently Asked Questions

Can I migrate a container to a node outside my cluster?

pct migrate only works between nodes in the same cluster. Moving a container to an unrelated standalone node means backing it up with vzdump and restoring it there instead.

Will the container's IP address change after migration?

No. The container keeps its configured IP, MAC address, and hostname. Only the physical node underneath it changes.

Does migration work for unprivileged containers?

Yes, both privileged and unprivileged containers migrate the same way. Unprivileged is actually the safer default for most homelab use anyway, since it maps the container's root user to an unprivileged user on the host.

How long does a typical migration take?

On shared storage, seconds. On local storage, it depends entirely on how much data has to cross the network — a 4 GB container over gigabit Ethernet usually finishes in well under a minute.

What happens if the migration fails partway through?

Proxmox is designed to leave the original container intact on the source node if a migration fails before completion. Check the task log for the specific error before retrying.

Can I migrate several containers at once?

The GUI lets you select multiple guests and queue migrations for them, running one after another rather than truly in parallel. From the CLI you'd just call pct migrate once per container, optionally in a small shell loop.

Conclusion

Container migration in Proxmox isn't complicated once you know the one thing that separates it from VM migration: there's no true zero-downtime option, and that's fine. Restart mode is fast enough for the vast majority of homelab and small-business setups, and now you know exactly which flag to reach for depending on whether you're clearing a node for maintenance, rebalancing load, or just tidying up your cluster. Next time a node needs a reboot, you won't have to think twice about the containers sitting on it.