Files
bouncer/docs/DEPLOY.md
user 9954a890c3 docs: add podman deployment guide
New docs/DEPLOY.md covering container image, compose config, volume
mounts, host networking, operations, and troubleshooting. Updated
README, INSTALL, CHEATSHEET, and DEBUG to reference it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:51:29 +01:00

4.4 KiB

Podman Deployment

Overview

The bouncer runs in a rootless podman container with host networking. Source code and configuration are mounted as volumes -- the container image only contains Python and pip dependencies.

Container (bouncer)
  |- python:3.12-slim + deps
  |- /app/src  <- ./src (read-only volume)
  |- /data     <- ./config (read-write volume)

Prerequisites

  • podman and podman-compose
  • SOCKS5 proxy reachable at 127.0.0.1:1080 (host network)

Verify:

podman --version
podman-compose --version
ss -tlnp | grep 1080

Quick Start

cd ~/git/bouncer

# create config from template
cp config/bouncer.example.toml config/bouncer.toml
$EDITOR config/bouncer.toml

# build and start
make build
make up

# check logs
make logs

Container Image

The image installs only runtime dependencies. Source code is not baked in.

# build
podman build -t bouncer -f Containerfile .

# rebuild after dependency changes
podman build --no-cache -t bouncer -f Containerfile .

Containerfile

FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir \
    "python-socks[asyncio]>=2.4" \
    "aiosqlite>=0.19"
ENV PYTHONUNBUFFERED=1
ENV PYTHONPATH=/app/src
VOLUME /app/src
VOLUME /data
ENTRYPOINT ["python", "-m", "bouncer"]
CMD ["-c", "/data/bouncer.toml"]

Compose

services:
  bouncer:
    build:
      context: .
      dockerfile: Containerfile
    container_name: bouncer
    restart: unless-stopped
    network_mode: host
    logging:
      driver: k8s-file
    volumes:
      - ./src:/app/src:Z,ro
      - ./config:/data:Z
    command: ["-c", "/data/bouncer.toml", "-v"]

Volume Mounts

Host Path Container Path Mode Purpose
./src /app/src read-only Python source code
./config /data read-write Config + SQLite backlog

The :Z suffix applies the correct SELinux context for rootless podman.

Host Networking

network_mode: host is required because the bouncer needs access to:

  • 127.0.0.1:1080 -- SOCKS5 proxy (outbound IRC connections)
  • 127.0.0.1:6667 -- client listen port (inbound IRC clients)

Log Driver

k8s-file is used instead of the default journald driver to ensure podman logs works reliably in rootless mode.

Operations

Start / Stop / Restart

podman-compose up -d          # start (detached)
podman-compose down           # stop and remove
podman-compose restart        # restart

Or with make targets:

make up                       # podman-compose up -d
make down                     # podman-compose down

Logs

podman logs -f bouncer                          # follow all logs
podman logs --tail 50 bouncer                   # last 50 lines
podman logs bouncer 2>&1 | grep -v aiosqlite    # filter sqlite noise
podman logs bouncer 2>&1 | grep -E 'INFO|WARN'  # important events only

Or:

make logs                     # podman logs -f bouncer

Status

podman ps --filter name=bouncer
podman inspect bouncer --format '{{.State.Status}}'

Shell Access

podman exec -it bouncer bash
podman exec bouncer python -c "import bouncer; print(bouncer.__version__)"

Inspect Backlog

The SQLite database is stored in the config volume:

sqlite3 config/bouncer.db "SELECT network, COUNT(*) FROM messages GROUP BY network;"

Updating

After pulling new code:

git pull
podman-compose down
podman-compose up -d

The image only needs rebuilding if dependencies change:

podman-compose down
make build
podman-compose up -d

Troubleshooting

Container exits immediately

Check logs for config or proxy errors:

podman logs bouncer

Common causes:

  • Missing config/bouncer.toml (not mounted)
  • SOCKS5 proxy not running on host
  • Invalid TOML syntax

No log output

Verify PYTHONUNBUFFERED=1 is set in the Containerfile and the log driver is k8s-file:

podman inspect bouncer --format '{{.HostConfig.LogConfig.Type}}'

Container can't reach SOCKS5 proxy

network_mode: host must be set. Verify the proxy is listening:

ss -tlnp | grep 1080

Permission denied on volumes

The :Z suffix handles SELinux relabeling. If issues persist:

podman unshare ls -la config/

Rebuild from scratch

podman-compose down
podman rmi bouncer
podman build --no-cache -t bouncer -f Containerfile .
podman-compose up -d