Part 4: Running Containers with Podman and Cockpit

Febin JoyFebin Joy
4 min read

Welcome to Part 4 of the Ubuntu home lab series. Now that our server is secure, it's time to start running services in containers. We'll use Podman (a daemonless alternative to Docker) and Cockpit (a web-based UI) to make management easy. My strategy is to use containers whenever possible(e.g. PostgreSQL DB). If containerising is not possible, use a VM.

In this part, we'll:

  • Install and configure Podman

  • Set up Cockpit with container and VM support

  • Run our first container (Jellyfin)

  • Set up persistent volumes and startup scripts


🧱 Step 1: Install Podman

Podman is a daemonless container engine that allows you to run containers as non-root users, enhancing security and flexibility. It's designed to be compatible with Docker commands, making it easy to transition between the two. Additionally, Podman can pull and run Docker images, providing seamless integration with existing Docker workflows.

In a home lab setup, Podman offers the advantage of being managed easily through Cockpit, which we have already installed. This simplifies container management without needing additional tools like Portainer, which Docker requires for a web-based UI.

sudo apt update
sudo apt install -y podman podman-remote

You can confirm installation with:

podman --version

🌐 Step 2: Install Cockpit and Plugins

Cockpit is a web-based interface for managing Linux servers, providing a graphical dashboard to monitor and control various aspects of system administration, such as storage, network settings, and system performance. Cockpit allows you to install various plugins to manage VMs, Podman containers, View logs, manage users etc from a remote computer on the same network with ease.

sudo apt install -y \
  qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils \
  cockpit cockpit-sosreport cockpit-machines \
  virt-manager cockpit-podman

Enable and start Cockpit:

sudo systemctl enable --now cockpit.socket

Cockpit will now be accessible at:

https://<your-server-ip>:9090

Use your server’s username/password to log in.

🔒 You can optionally configure SSL certificates for Cockpit.

Add firewall rule:

sudo iptables -A INPUT -p tcp --dport 9090 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4

Cockpit is now available using https://<server-ip>:9090 from any machine in your home lab server’s network. Login with your server username and password.


🎬 Step 3: Run Your First Container (Jellyfin)

1. Pull the image

I have chosen to install Jellyfin for the demonstration. Jellyfin is a free media system that allows you to manage and stream your media on your local network. You can follow the same method to spin up any container image.

podman pull docker.io/jellyfin/jellyfin:latest

Confirm that the image is pulled:

podman images

2. Create directories

mkdir -p ~/.config/containers/jellyfin/config
mkdir -p ~/.config/containers/jellyfin/cache
mkdir -p ~/data/media
chmod -R 755 ~/.config/containers/jellyfin ~/data/media

3. Create persistent volumes

A Podman volume is a section of the host file system that is attached to a running container. It allows data to persist and be shared between containers.

podman volume create --opt device=$HOME/.config/containers/jellyfin/config --opt type=none --opt o=bind jellyfin-config
podman volume create --opt device=$HOME/.config/containers/jellyfin/cache --opt type=none --opt o=bind jellyfin-cache
podman volume create --opt device=$HOME/data/media --opt type=none --opt o=bind jellyfin-media

Creating the volume and passing it is always recommended as it helps to identify the volume when we list using podman volume ls and remove using podman volume rm <imagename>. If we don’t create explicitly, podman creates automatically and the names would not be easily identifiable.

Use podman volume rm <volume name> to delete a volume if required.

4. Run the container

podman run -d \
  --name jellyfin \
  --restart=always \
  -p 8096:8096 \
  -p 8920:8920 \
  -v jellyfin-config:/config \
  -v jellyfin-cache:/cache \
  -v jellyfin-media:/media \
  jellyfin/jellyfin:latest

5. Allow traffic

sudo iptables -A INPUT -p tcp --dport 8096 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8920 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4

This will create a Podman container with the name jellyfin which runs on your new server. You can upload all the media to ~/data/media folder and organise them in Jellyfin.

Access Jellyfin:

http://<your-server-ip>:8096

If the Jellyfin wizard does not come up, try accessing http://<server-ip>:8096/web/index.html#!/wizardstart.html.


🔁 Step 4: Auto-start Containers on Boot

Podman is daemonless, so containers won’t auto-start after reboot by default. Let’s fix that with a simple systemd service.

1. Create a startup script

mkdir -p ~/.config/containers
nano ~/.config/containers/start.sh

Example content:

#!/bin/bash
podman start jellyfin

Make it executable:

chmod +x ~/.config/containers/start.sh

2. Create a systemd service

sudo nano /etc/systemd/system/start-containers.service

Paste:

[Unit]
Description=Start Podman Containers
After=network.target

[Service]
Environment="XDG_RUNTIME_DIR=/run/user/1000"
ExecStartPre=/bin/sleep 10
ExecStart=/bin/bash /home/<your-username>/.config/containers/start.sh
User=<your-username>
Restart=always

[Install]
WantedBy=default.target

Replace <your-username> accordingly.

Enable and start the service:

sudo systemctl enable start-containers.service
sudo systemctl start start-containers.service

In the next part, we’ll go further with multi-container pods using Podman. We’ll set up PostgreSQL + pgAdmin, Node-RED, and Homarr for managing your homelab.

Stay tuned for Part 5: Advanced Containers – pgAdmin, Node-RED, and Homarr!

0
Subscribe to my newsletter

Read articles from Febin Joy directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Febin Joy
Febin Joy

Technical leader and architect with 20+ years of experience designing secure, scalable enterprise platforms across cloud, hybrid, and on-prem environments. Currently leading technical architecture and cross-functional teams delivering mobility and compliance systems used by 300+ organisations across Australia and New Zealand. Proven track record of translating complex compliance frameworks (HIPAA, ISO 27001) into production-grade systems. Skilled in Azure cloud migration, secure software development, and risk-driven design. Focused on architecting resilient platforms that enhance public safety, operational efficiency, and long-term engineering excellence. Based in Melbourne, Australian citizen, and a clear communicator with a strategic mindset.