PODMAN - Install Podman on Linux Redhat Production-Ready Step-by-Step Guide Rootless Podman + Quadlet on Red Hat Enterprise Linux 10 This guide is designed for a production environment as assums a fresh install of Redhat. It uses the modern Quadlet method (recommended) and follows Red Hat best practices for RHEL 10. 1. System Requirements (Production) Resource Minimum Recommended (Production) Our Systems CPU 2 cores 4+ cores 8 cores RAM 4 GB 8–16 GB+ 32 GB Disk 40 GB free 100 GB+ (SSD preferred) 350 GB cgroup cgroup v2 cgroup v2 (required) SELinux Enforcing Enforcing Check cgroup version: podman info --format '{{.Host.CgroupVersion}}' Install Needed Tools: Epel Release subscription-manager repos --enable codeready-builder-for-rhel-10-$(arch)-rpms dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm -y After Epel installation rerun the upgrade to update if any are needed dnf upgrade -y Toolset dnf install bind-utils bzip2 cups cifs-utils enscript ftp gdb ghostscript krb5-workstation ksh lftp lrzsz lsof libnsl lzop plocate mutt ncompress net-tools net-snmp net-snmp-utils net-tools nfs-utils nmap nvme-cli openldap-clients openssh-clients psmisc realmd rsync samba-client strace sysstat tcpdump telnet telnet-server tmux unix2dos vim vim-enhanced vsftpd wget xfsdump vsftpd htop mc rsyslog rsyslog-doc postfix dbus-daemon s-nail dovecot cyrus-sasl cyrus-sasl-lib cyrus-sasl-plain tree figlet toilet coreutils -y 2. Prepare the System 2.1 Register and Update RHEL 10 sudo dnf update -y sudo reboot 2.2 Install Container Tools sudo dnf install -y container-tools Optional (Docker CLI compatibility): sudo dnf install -y podman-docker Verify: podman --version podman info 3. Create a Dedicated Service User (Best Practice) For production, avoid running services under a regular interactive user. # Create a system user for containers sudo useradd -r -m -d /home/podman -s /bin/bash podman # Set a strong password or disable password login sudo passwd podman # or lock the account later Grant subordinate UIDs/GIDs (required for rootless): sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 podman 4. Enable Lingering (Critical for Production) This allows the user services to run even when the user is not logged in. sudo loginctl enable-linger podman Verify: loginctl show-user podman | grep Linger # Linger=yes 5. Configure Rootless Environment Switch to the service user: sudo -u podman -i Create required directories: mkdir -p ~/.config/containers/systemd mkdir -p ~/.config/containers mkdir -p ~/.local/share/containers Optional but Recommended: Storage Configuration cat > ~/.config/containers/storage.conf << 'EOF' [storage] driver = "overlay" runroot = "/run/user/$(id -u)/containers" graphroot = "$HOME/.local/share/containers/storage" [storage.options.overlay] mount_program = "/usr/bin/fuse-overlayfs" mountopt = "nodev,fsync=0" EOF Optional: Registries Configuration cat > ~/.config/containers/registries.conf << 'EOF' unqualified-search-registries = ["registry.access.redhat.com", "registry.redhat.io", "docker.io", "quay.io"] [[registry]] location = "docker.io" insecure = false EOF 6. Create Your First Production Quadlet A) Example: Nginx reverse proxy / web service cat > ~/.config/containers/systemd/nginx.container << 'EOF' [Unit] Description=Nginx Web Server (Production) After=network-online.target Wants=network-online.target [Container] Image=docker.io/library/nginx:alpine ContainerName=nginx PublishPort=8080:80 Volume=nginx-data.volume:/usr/share/nginx/html:Z Volume=nginx-conf.volume:/etc/nginx/conf.d:Z AutoUpdate=registry Environment=TZ=America/New_York PodmanArgs=--memory=512m --cpus=1.0 --memory-swap=512m [Service] Restart=always TimeoutStartSec=300 [Install] WantedBy=default.target EOF A) Create supporting volumes: cat > ~/.config/containers/systemd/nginx-data.volume << 'EOF' [Volume] VolumeName=nginx-data EOF cat > ~/.config/containers/systemd/nginx-conf.volume << 'EOF' [Volume] VolumeName=nginx-conf EOF B) Another Example cat > ~/.config/containers/systemd/myapp.container << 'EOF' [Unit] Description=My Application (Production) After=network-online.target Wants=network-online.target [Container] Image=your-registry/your-app:latest ContainerName=myapp PublishPort=8080:8080 Volume=myapp-data.volume:/data:Z AutoUpdate=registry Environment=TZ=America/New_York PodmanArgs=--memory=1g --cpus=1.5 --memory-swap=1g [Service] Restart=always TimeoutStartSec=300 [Install] WantedBy=default.target EOF B) Create supporting volume: cat > ~/.config/containers/systemd/myapp-data.volume << 'EOF' [Volume] VolumeName=myapp-data EOF   7. Activate the Service A) Example for Nginx # Reload systemd user units systemctl --user daemon-reload # Start and enable systemctl --user enable --now nginx.service # Check status systemctl --user status nginx.service podman ps View logs: journalctl --user -u nginx.service -f B) Second Example systemctl --user daemon-reload systemctl --user enable --now myapp.service # Verify systemctl --user status myapp.service podman ps View logs: journalctl --user -u myapp.service -f   8. Configure pfSense HAProxy In pfSense HAProxy: Backend Mode: http Server: IP of your RHEL 10 host Port: 8080 (or whatever you published) Health check: recommended Frontend Bind to WAN / desired interface TLS offloading (recommended) ACL based on Host header (e.g. hdr(host) -i app.yourdomain.com) Use backend created above Firewall Rules Allow traffic from HAProxy (or LAN) to the RHEL host on the published port(s) only. Firewall example: sudo firewall-cmd --permanent --add-port=8080/tcp sudo firewall-cmd --reload   9. Production Hardening Checklist Item Command / Action Status SELinux Keep enforcing ☐ Linger enabled loginctl show-user podman ☐ Resource limits Set in Quadlet (--memory, --cpus) ☐ Auto-update AutoUpdate=registry in Quadlet ☐ Firewall Open only required ports ☐ Log rotation Configure journald or ship logs ☐ Image scanning Use podman image scan or external scanner ☐ Backup volumes Backup ~/.local/share/containers ☐ Non-interactive user Disable password / use key-based access only ☐ Log management journalctl --user or forward logs Enable auto-update timer (as podman user): systemctl --user enable --now podman-auto-update.timer 9. Useful Management Commands A) Example for Nginx # List all user services systemctl --user list-units --type=service # Restart a service systemctl --user restart nginx.service # Stop a service systemctl --user stop nginx.service # View resource usage podman stats # Update all containers with AutoUpdate podman auto-update B) Another Example # Service management systemctl --user status myapp.service systemctl --user restart myapp.service systemctl --user stop myapp.service # Container status & resources podman ps podman stats # Logs journalctl --user -u myapp.service -f # Manual update podman auto-update   10. Optional: Auto-Update Timer Enable Podman’s auto-update timer (as the podman user): Bash systemctl --user enable --now podman-auto-update.timer Summary of Key Directories (Rootless) Purpose Path Quadlet files ~/.config/containers/systemd/ Container storage ~/.local/share/containers/storage/ User systemd units ~/.config/systemd/user/ Configuration ~/.config/containers/ Summary HAProxy on pfSense = edge reverse proxy / TLS / routing RHEL 10 + rootless Podman + Quadlet = application runtime No Nginx needed unless the application itself requires it