Skip to content

Instantly share code, notes, and snippets.

@Clivern
Created October 30, 2025 20:00
Show Gist options
  • Save Clivern/2bf768561663d7d3ef1b64ec87458133 to your computer and use it in GitHub Desktop.
Save Clivern/2bf768561663d7d3ef1b64ec87458133 to your computer and use it in GitHub Desktop.
Podman

Overview

Rootless mode allows you to run containers without root privileges, providing better security and user isolation.

Prerequisites

  • Root or sudo access (for initial setup)
  • Linux system with systemd

Setup Instructions

1. User Creation & Configuration

Create a dedicated non-root user for running containers:

# Check current user (should be root or have sudo access)
whoami

# Create new user (using 'staging' as example)
sudo adduser staging
sudo usermod -aG sudo staging

# Configure subordinate UIDs and GIDs for user namespace mapping
sudo usermod --add-subuids 100000-165535 staging
sudo usermod --add-subgids 100000-165535 staging

2. Install Podman & Dependencies

sudo apt-get update
sudo apt-get install -y podman uidmap slirp4netns fuse-overlayfs golang

3. Configure Rootless Environment

Switch to the non-root user and configure container registries:

# Switch to new user
su - staging

# Verify you're non-root
whoami
id

# Configure container registries
mkdir -p ~/.config/containers
cat > ~/.config/containers/registries.conf << 'EOF'
unqualified-search-registries = ["docker.io"]
EOF

4. Test & Verify

# Test rootless Podman
podman run hello-world

# Verify rootless mode is enabled
podman info | grep rootless
# Should output: rootless: true

Optional Configuration

Enable Systemd Lingering

Lingering allows the user to run systemd services even when not logged in, preventing containers from stopping on logout:

# Exit to root/sudo user
exit

# Enable lingering (use username or UID)
sudo loginctl enable-linger staging

# Verify lingering is enabled
loginctl show-user staging | grep Linger
# Should output: Linger=yes

# Switch back to user
su - staging

Running Containers with UID/GID Mapping

Build Container Image

# Build from Dockerfile in current directory
podman build -t app:1.0.0 .

# Run with port mapping
podman run \
  --rm \
  --uidmap "+100000:0:1" \
  --gidmap "+100000:0:1" \
  -p 8080:8080 \
  --name myapp \
  -d \
  app:1.0.0

Resources

# Multi-stage build for a minimal image
FROM golang:1.25-alpine AS builder
WORKDIR /build
# Copy source
COPY main.go .
# Build static binary
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o server main.go
# Final minimal image
FROM alpine:latest
# Install ca-certificates for HTTPS and create user
RUN apk --no-cache add ca-certificates && \
addgroup -g 10000 myapp && \
adduser -u 10000 -G myapp -D -h /var/lib/myapp myapp
# Create necessary directories
RUN mkdir -p /var/lib/myapp/data && \
chown -R myapp:myapp /var/lib/myapp
# Copy binary from builder
COPY --from=builder /build/server /usr/local/bin/server
# Switch to non-root user
USER myapp
# Set working directory
WORKDIR /var/lib/myapp
# Expose port
EXPOSE 8080
# Run the server
CMD ["/usr/local/bin/server"]
package main
import (
"fmt"
"log"
"net/http"
"os"
"os/user"
"time"
)
func main() {
// Get current user information
currentUser, err := user.Current()
if err != nil {
log.Printf("Warning: Could not get current user: %v", err)
} else {
log.Printf("Running as: UID=%s GID=%s Username=%s",
currentUser.Uid, currentUser.Gid, currentUser.Username)
}
// Get hostname
hostname, _ := os.Hostname()
log.Printf("Hostname: %s", hostname)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from Go Server!\n")
fmt.Fprintf(w, "Time: %s\n", time.Now().Format(time.RFC3339))
fmt.Fprintf(w, "Hostname: %s\n", hostname)
if currentUser != nil {
fmt.Fprintf(w, "Running as: UID=%s GID=%s Username=%s\n",
currentUser.Uid, currentUser.Gid, currentUser.Username)
}
fmt.Fprintf(w, "Request from: %s\n", r.RemoteAddr)
})
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "OK\n")
})
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("Starting server on port %s...", port)
if err := http.ListenAndServe(":"+port, nil); err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment