# 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)

<div id="bkmrk-resource-minimum-rec"><div><div><div dir="auto"><table dir="auto"><thead><tr><th data-col-size="sm">Resource</th><th data-col-size="lg">Minimum</th><th data-col-size="xl">Recommended (Production)</th><th>Our Systems</th></tr></thead><tbody><tr><td data-col-size="sm">CPU</td><td data-col-size="lg">2 cores</td><td data-col-size="xl">4+ cores</td><td>8 cores</td></tr><tr><td data-col-size="sm">RAM</td><td data-col-size="lg">4 GB</td><td data-col-size="xl">8–16 GB+</td><td>32 GB</td></tr><tr><td data-col-size="sm">Disk</td><td data-col-size="lg">40 GB free</td><td data-col-size="xl">100 GB+ (SSD preferred)</td><td>350 GB</td></tr><tr><td data-col-size="sm">cgroup</td><td data-col-size="lg">cgroup v2</td><td data-col-size="xl">cgroup v2 (required)</td><td>  
</td></tr><tr><td data-col-size="sm">SELinux</td><td data-col-size="lg">Enforcing</td><td data-col-size="xl">Enforcing</td><td>  
</td></tr></tbody></table>

</div></div><div></div></div><div></div></div>**Check cgroup version:**

```
podman info --format '{{.Host.CgroupVersion}}'
```

<div dir="auto" id="bkmrk-install-needed-tools"><div data-testid="code-block"><div>**Install Needed Tools:**</div><div>  
</div></div></div>Epel Release

```bash
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

```bash
dnf upgrade -y
```

<div dir="auto" id="bkmrk--1"><div data-testid="code-block"><div></div><div>Toolset</div><div></div></div></div><div id="bkmrk--2"></div>```bash
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
```

<div id="bkmrk--3"></div><div id="bkmrk--4"></div>---

### 2. Prepare the System

#### 2.1 Register and Update RHEL 10

```bash
sudo dnf update -y
sudo reboot
```

<div dir="auto" id="bkmrk--6"><div data-testid="code-block"><div></div></div></div>#### 2.2 Install Container Tools

```
sudo dnf install -y container-tools
```

<div dir="auto" id="bkmrk--7"><div data-testid="code-block"><div></div></div></div>Optional (Docker CLI compatibility):

```
sudo dnf install -y podman-docker
```

<div dir="auto" id="bkmrk--8"><div data-testid="code-block"><div></div></div></div>Verify:

```bash
podman --version
podman info
```

<div dir="auto" id="bkmrk--9"><div data-testid="code-block"><div></div><div></div></div></div>---

### 3. Create a Dedicated Service User (Best Practice)

For production, avoid running services under a regular interactive user.

```bash
# 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
```

<div dir="auto" id="bkmrk--11"><div data-testid="code-block"><div></div></div></div>Grant subordinate UIDs/GIDs (required for rootless):

```bash
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 podman
```

<div dir="auto" id="bkmrk--12"><div data-testid="code-block"><div></div><div></div></div></div>---

### 4. Enable Lingering (Critical for Production)

This allows the user services to run even when the user is not logged in.

```bash
sudo loginctl enable-linger podman
```

<div dir="auto" id="bkmrk--14"><div data-testid="code-block"><div></div></div></div>Verify:

```bash
loginctl show-user podman | grep Linger
# Linger=yes
```

<div dir="auto" id="bkmrk--15"><div data-testid="code-block"><div></div><div></div></div></div>---

### 5. Configure Rootless Environment

Switch to the service user:

```bash
sudo -u podman -i
```

<div dir="auto" id="bkmrk--17"><div data-testid="code-block"><div></div></div></div>Create required directories:

```bash
mkdir -p ~/.config/containers/systemd
mkdir -p ~/.config/containers
mkdir -p ~/.local/share/containers
```

<div dir="auto" id="bkmrk--18"><div data-testid="code-block"><div></div></div></div>#### Optional but Recommended: Storage Configuration

```bash
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
```

<div dir="auto" id="bkmrk--19"><div data-testid="code-block"><div></div></div></div>#### Optional: Registries Configuration

```bash
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
```

<div dir="auto" id="bkmrk--20"><div data-testid="code-block"><div></div><div></div></div></div>---

### 6. Create Your First Production Quadlet

A) Example: Nginx reverse proxy / web service

```bash
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
```

<div dir="auto" id="bkmrk--22"><div data-testid="code-block"><div></div></div></div>A) Create supporting volumes:

```bash
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
```

<div dir="auto" id="bkmrk-b%29-another-example"><div data-testid="code-block"><div>B) Another Example</div><div>  
</div></div></div>```bash
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:

```bash
cat > ~/.config/containers/systemd/myapp-data.volume << 'EOF'
[Volume]
VolumeName=myapp-data
EOF
```

---

### 7. Activate the Service

A) Example for Nginx

```bash
# 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
```

<div dir="auto" id="bkmrk--25"><div data-testid="code-block"><div></div></div></div>View logs:

```
journalctl --user -u nginx.service -f
```

<div dir="auto" id="bkmrk-b%29-second-example"><div data-testid="code-block"><div>  
</div><div>B) Second Example</div><div>  
</div><div>  
</div></div></div>```bash
systemctl --user daemon-reload
systemctl --user enable --now myapp.service

# Verify
systemctl --user status myapp.service
podman ps
```

View logs:

```bash
journalctl --user -u myapp.service -f
```

---

### 8. Configure pfSense HAProxy

In pfSense HAProxy:

1. **Backend**
    - Mode: http
    - Server: IP of your RHEL 10 host
    - Port: 8080 (or whatever you published)
    - Health check: recommended
2. **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
3. **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

<div id="bkmrk-item-command-%2F-actio"><div><div><div dir="auto"><table dir="auto" style="width: 59.5238%; height: 297.969px;"><thead><tr style="height: 29.7969px;"><th data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Item</th><th data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Command / Action</th><th data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">Status</th></tr></thead><tbody><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">SELinux</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Keep enforcing</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Linger enabled</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">loginctl show-user podman</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Resource limits</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Set in Quadlet (--memory, --cpus)</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Auto-update</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">AutoUpdate=registry in Quadlet</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Firewall</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Open only required ports</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Log rotation</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Configure journald or ship logs</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Image scanning</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Use podman image scan or external scanner</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Backup volumes</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Backup ~/.local/share/containers</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr style="height: 29.7969px;"><td data-col-size="lg" style="width: 28.6188%; height: 29.7969px;">Non-interactive user</td><td data-col-size="xl" style="width: 59.9188%; height: 29.7969px;">Disable password / use key-based access only</td><td data-col-size="xs" style="width: 11.1719%; height: 29.7969px;">☐</td></tr><tr><td style="width: 28.6188%;">Log management

</td><td style="width: 59.9188%;">journalctl --user or forward logs

</td><td style="width: 11.1719%;">  
</td></tr></tbody></table>

</div></div><div></div></div></div>Enable auto-update timer (as podman user):

```bash
systemctl --user enable --now podman-auto-update.timer
```

<div dir="auto" id="bkmrk--28"><div data-testid="code-block"><div></div><div></div></div></div>---

### 9. Useful Management Commands

<div dir="auto" id="bkmrk-bash-18"><div data-testid="code-block"><div><div>A) Example for Nginx <div></div></div><div></div></div></div></div>```bash
# 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
```

<div dir="auto" id="bkmrk-b%29-another-example-1"><div data-testid="code-block"><div>B) Another Example</div><div></div><div></div></div></div>```bash
# 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):

<div dir="auto" id="bkmrk-bash-19"><div data-testid="code-block"><div><div>Bash <div></div></div><div></div></div></div></div>```bash
systemctl --user enable --now podman-auto-update.timer
```

<div dir="auto" id="bkmrk--32"><div data-testid="code-block"><div></div><div></div></div></div>---

### Summary of Key Directories (Rootless)

<div id="bkmrk-purpose-path-quadlet"><div><div><div dir="auto"><table dir="auto"><thead><tr><th data-col-size="sm">Purpose</th><th data-col-size="lg">Path</th></tr></thead><tbody><tr><td data-col-size="sm">Quadlet files</td><td data-col-size="lg">~/.config/containers/systemd/</td></tr><tr><td data-col-size="sm">Container storage</td><td data-col-size="lg">~/.local/share/containers/storage/</td></tr><tr><td data-col-size="sm">User systemd units</td><td data-col-size="lg">~/.config/systemd/user/</td></tr><tr><td data-col-size="sm">Configuration</td><td data-col-size="lg">~/.config/containers/</td></tr></tbody></table>

</div></div></div></div>**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