OCI Image Containers in Proxmox VE 9.1: Setup and Tradeoffs

Create OCI image containers in Proxmox VE 9.1 with a single command. Learn the setup steps, storage requirements, and key tradeoffs for reliable production runs.

Proxmox PulseProxmox Pulse
7 min read
Glass container modules floating in a dim server room near brushed-steel storage cubes and brass locks.

Proxmox VE 9.1 lets you spin up LXC containers directly from OCI-compliant images, so you can pull an Alpine or custom-registry image with a single command and run it as a container without writing a config from scratch. This guide walks through pulling an image, configuring the container, and getting it running — plus the tradeoffs to weigh before you commit.

Key Takeaways

  • One-command setup — pct create pulls an OCI image and builds the container rootfs in a single step.
  • Unprivileged by default — OCI containers run with the unprivileged user mapping on, which keeps them isolated from the host.
  • Storage matters — OCI rootfs needs an ext4 or ZFS-backed storage; not every datastore will accept the image.
  • Registry flexibility — use the docker:// prefix for Docker Hub and the full reference for any other OCI registry.

What Are OCI Images and Why Do They Matter for LXC Containers?

OCI (Open Container Initiative) images are the standard format used by Docker, Podman, and just about every container runtime out there. Proxmox VE 8.0 first added the ability to pull those images and turn them into LXC containers, and by 9.1 the feature is mature enough to use in everyday work without surprises.

The appeal is straightforward: if you already build and push images to a registry, you can run them on Proxmox without maintaining a separate template library. You get the reproducibility of an image build plus Proxmox's lightweight virtualization and snapshot-based backups, all in the same tool you already manage.

To use this you need Proxmox VE 9.1 (or 8.0+). If you are still on 8.x, the upgrade path to 9.1 is well documented and worth doing before you lean on OCI containers in production.

How to Create a Container from an OCI Image

The fastest way in is pct create with an image reference. Proxmox pulls the image, extracts the rootfs, and creates the container in one shot.

For a Docker Hub image, prefix the reference with docker://:

pct create 100 docker://alpine:3.19

Alpine is tiny — the pulled rootfs lands at around 4 MB — so this typically finishes in a few seconds on a normal connection.

For an image hosted on any other OCI registry, drop the prefix and pass the full reference, including the registry host:

pct create 100 ghcr.io/some-org/some-image:1.4.2

If you want to cache the image in storage before building the container (handy on a slow link or a multi-node setup), use pull-oci to store the rootfs first:

pct pull-oci local 100 docker://alpine:3.19

This pulls the Alpine image and stores the rootfs for vmid 100 in the local storage, so a later create does not re-download it.

A couple of notes on the create command: Proxmox auto-fills the architecture and ostype from the image, so you usually do not need to pass them. And by default the resulting container is unprivileged, which is what keeps it sandboxed from the host. You can list what you have with pct list.

Choosing the Right Storage for OCI Images

Not every storage type plays nice with OCI rootfs. Proxmox writes the image as an ext4 disk image, so you want a storage that supports that cleanly — an ext4 directory store or a ZFS pool.

If you are laying down new storage for containers, the ZFS pools and datasets best-practices guide covers the layout choices that hold up under snapshots and clones. ZFS is a common pick because it snapshots the OCI rootfs for free, which pairs nicely with Proxmox Backup Server for versioned restores off-host.

The common failure mode is pointing the pull at a storage that cannot host the ext4 image — you get an error at create time rather than a silently broken container. Pick ext4 or ZFS and the pull succeeds; avoid exotic or network-only datastores for the initial pull and see whether they accept the image before you rely on them.

Configuring the OCI Container

Once created, the container lives in /etc/pct/100.conf. You can view it with pct config 100 or edit it with pct edit 100.

A typical OCI container config looks like this:

arch: amd64
ostype: other
cores: 2
memory: 512
rootfs: local:100/rootfs/vm-100-rootfs.ext4
unprivileged: 1

Proxmox auto-fills arch and ostype from the image (shown here as amd64/other), so you rarely need to set them. The line that matters most for security is unprivileged: 1. It maps the container's root to an unprivileged host UID, so even a misbehaving process stays confined inside the container. Keep it on unless an image genuinely needs full root.

Some images expect to nest or need extra mount flexibility. Enable nesting when the image runs its own container runtime or needs loopback and cgroup access:

features[nesting]: 1

Apply runtime changes with pct set while the container is stopped, then start it again. For example, bumping memory is pct set 100 --memory 1024.

Running and Managing Your Container

Start the container and poke at it without leaving the host:

pct start 100
pct exec 100 -- uname -a
pct exec 100 -- cat /etc/os-release

pct exec runs a command inside the container and returns its output, which is great for health checks and one-off commands. To drop into an interactive shell, use pct enter:

pct enter 100

Stop it the usual way with pct stop 100, and snapshot it with pct snapshot 100 my-first-oci if you want a rollback point before you start making changes.

OCI Image Containers vs. Native LXC Templates: Which Is Right for You?

Both approaches produce a working LXC container; they just differ in where the rootfs comes from and how much you control up front.

Aspect OCI Image Container Native LXC Template
Rootfs source Any OCI registry (Docker Hub, ghcr.io, private) Proxmox template repository
Setup One command from an image reference Download and unpack a template
Pre-create control Image baked in; tweak config after Full config before creation
Customization Limited to config + image layers Full control over config
Best for Docker-like workflow and reproducibility Fine-grained, Proxmox-native setup

If your team already standardizes on registry images, the OCI path removes a whole category of template maintenance. If you need tight control over the config before the container exists, the native template is still the cleaner fit.

Honest Tradeoffs and Gotchas

The biggest tradeoff is control versus convenience. OCI images hand you the rootfs, which means less setup work — but the image also dictates the base layout, so you cannot reorder the rootfs the way you can with a native template.

A few real gotchas I have hit in production:

  • The docker:// prefix only works for Docker Hub. Use the full registry reference for anything else, or the create fails.
  • Unprivileged is the default, and some images built assuming a full root environment (many web images that USER root) can misbehave. Flipping it off with pct set 100 --unprivileged 0 is possible but often means recreating the container, so pick the right mode up front.
  • Storage has to support the ext4 rootfs. ext4 directory stores and ZFS pools work; double-check before you point the pull at an unusual datastore.
  • Pulling the same image twice costs bandwidth. Use pull-oci or a shared registry mirror to cache it.

Conclusion

Proxmox VE 9.1 turns OCI images into runnable LXC containers with a single pct create command, unprivileged by default and backed by your chosen ext4 or ZFS storage. Start with a small Alpine image, get comfortable with pct exec and pct enter, then work a custom registry image into your workflow. Your next step: pull one image, snapshot the container, and confirm the snapshot restores cleanly before you rely on it in production.

Share
Proxmox Pulse

Written by

Proxmox Pulse

Sysadmin-driven guides for getting the most out of Proxmox VE in production and homelab environments.

Related Articles

View all →