• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Setting up Isolated Developer Workspaces on RHEL 9 using Podman Containers and Nginx Stream Router Routing

Setting up Isolated Developer Workspaces on RHEL 9 using Podman Containers and Nginx Stream Router Routing

Prerequisites and Initial Setup

This guide assumes a RHEL 9 system with root or sudo privileges. We’ll be leveraging Podman for containerization and Nginx as a stream router to direct traffic to isolated developer environments. Ensure Podman is installed and running. If not, execute:

  • sudo dnf install -y podman
  • sudo systemctl enable --now podman.socket

Similarly, Nginx must be installed. For this setup, we’ll use Nginx as a TCP stream proxy, not for HTTP. Install it with:

  • sudo dnf install -y nginx
  • sudo systemctl enable --now nginx

Defining Developer Environment Images

We’ll create a simple Dockerfile to build a base image for our developer workspaces. This image will include common tools and a basic application server (e.g., a Python Flask app). For demonstration, let’s assume each developer needs a Python 3.10 environment with Flask and a simple web service.

Create a file named Dockerfile.dev:

  • mkdir ~/dev-env-image && cd ~/dev-env-image

Dockerfile.dev content:

# Use a minimal RHEL 9 base image
FROM registry.access.redhat.com/ubi9/ubi:latest

# Install Python 3.10 and pip
RUN dnf update -y && \
    dnf install -y python310 python310-pip && \
    dnf clean all

# Set Python 3.10 as the default
RUN alternatives --set python /usr/bin/python3.10

# Install Flask
RUN pip3 install Flask

# Copy a sample application (optional, for testing)
# Create a simple app.py in the same directory as Dockerfile.dev
COPY app.py /app/app.py

# Expose the application port
EXPOSE 5000

# Set the working directory
WORKDIR /app

# Command to run the application
CMD ["python3", "app.py"]

Create a sample app.py in the same directory:

from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def hello():
    hostname = os.uname().nodename
    return f"Hello from container {hostname}!\n"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Build the container image:

sudo podman build -t dev-workspace-base:latest -f Dockerfile.dev .

Creating Isolated Developer Workspaces

For each developer, we’ll launch a container from our base image. We’ll assign a unique port for each developer’s application and map it to a host port. This allows multiple developers to run their environments on the same host without port conflicts.

Let’s define a script to launch a developer’s workspace. This script will take a developer ID and a desired host port as arguments.

Create a script named launch_dev_workspace.sh:

#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "Usage: $0 <developer_id> <host_port>"
    exit 1
fi

DEV_ID="$1"
HOST_PORT="$2"
CONTAINER_NAME="dev-workspace-${DEV_ID}"
APP_PORT="5000" # The port the application listens on inside the container

echo "Launching workspace for developer: ${DEV_ID}"
echo "Mapping host port ${HOST_PORT} to container port ${APP_PORT}"

# Check if container is already running
if sudo podman ps -q --filter "name=${CONTAINER_NAME}" --format '{{.Names}}' | grep -q "${CONTAINER_NAME}"; then
    echo "Container ${CONTAINER_NAME} is already running. Skipping launch."
    exit 0
fi

# Run the container
sudo podman run -d \
    --name "${CONTAINER_NAME}" \
    -p "${HOST_PORT}:${APP_PORT}" \
    --restart always \
    dev-workspace-base:latest

if [ $? -eq 0 ]; then
    echo "Workspace ${CONTAINER_NAME} launched successfully."
    echo "Access it via http://<your_server_ip>:${HOST_PORT}"
else
    echo "Failed to launch workspace ${CONTAINER_NAME}."
    exit 1
fi

Make the script executable:

chmod +x launch_dev_workspace.sh

Now, you can launch workspaces for different developers. For example, for ‘alice’ on port 8081 and ‘bob’ on port 8082:

sudo ./launch_dev_workspace.sh alice 8081
sudo ./launch_dev_workspace.sh bob 8082

Configuring Nginx as a Stream Router

Instead of directly exposing developer ports, we can use Nginx’s stream module to route traffic based on a subdomain or a specific port. This provides a more centralized and manageable access point. For this example, we’ll configure Nginx to route traffic based on the destination port.

First, ensure the stream module is enabled in Nginx. It’s usually compiled in by default on RHEL packages. We need to add a stream block to the Nginx configuration.

Edit the main Nginx configuration file, typically /etc/nginx/nginx.conf. Add the following stream block outside of the http block:

# /etc/nginx/nginx.conf

# ... other global directives ...

# Stream block for TCP/UDP proxying
stream {
    # Define upstream servers for each developer workspace
    # These map a logical name to the actual host:port of the container
    upstream dev_alice {
        server 127.0.0.1:8081; # Assuming Nginx is on the same host as containers
    }
    upstream dev_bob {
        server 127.0.0.1:8082;
    }

    # Define server blocks for routing
    # This server listens on port 80 and routes based on the target port
    # This is a simplified example; a more robust solution might use SNI or specific hostnames
    server {
        listen 80;
        proxy_pass dev_alice; # Default to Alice if no other rule matches
        proxy_timeout 10s;
        proxy_connect_timeout 1s;
    }

    # Example: Route traffic to Bob's workspace if it arrives on port 8082
    # This requires clients to connect to Nginx on different ports for different devs
    # A more common approach is using subdomains with DNS.
    server {
        listen 8082; # Listening on a different port for Bob
        proxy_pass dev_bob;
        proxy_timeout 10s;
        proxy_connect_timeout 1s;
    }

    # If you want to route based on subdomains (e.g., alice.dev.example.com),
    # you would typically use DNS to point subdomains to your Nginx server's IP
    # and then configure Nginx's http block to proxy to the stream block,
    # or use a more advanced stream configuration if available/needed.
    # For simplicity here, we'll stick to port-based routing or direct access.

    # For direct access to Alice's workspace on port 8081
    server {
        listen 8081;
        proxy_pass dev_alice;
        proxy_timeout 10s;
        proxy_connect_timeout 1s;
    }
}

# ... http block ...

Important Note on Stream Routing: The Nginx stream module operates at Layer 4 (TCP/UDP). It doesn’t inspect HTTP headers. Therefore, routing based on hostnames (like subdomains) requires either:

  • DNS configuration pointing subdomains (e.g., alice.dev.example.com) to your Nginx server’s IP, and then using Nginx’s http block to proxy to the stream block, or directly to the container ports if not using stream.
  • A more complex stream configuration that might involve custom logic or specific protocols if not using standard HTTP.

For simplicity in this example, we’ve shown direct port mapping in the stream block. A more practical setup for multiple developers would involve DNS and potentially a single entry point (e.g., port 80/443) that Nginx then routes based on the requested hostname.

After modifying nginx.conf, test the configuration and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

Accessing and Managing Workspaces

With the Nginx stream router configured, developers can access their environments. If using direct port mapping (as in the simplified Nginx config above), they would connect to <your_server_ip>:<their_assigned_port>. For example, Alice would access http://<your_server_ip>:8081.

To stop or remove a developer’s workspace:

# Stop a container
sudo podman stop dev-workspace-alice

# Remove a container
sudo podman rm dev-workspace-alice

# List running containers
sudo podman ps

# List all containers (including stopped)
sudo podman ps -a

Advanced Considerations and Best Practices

Security: Exposing developer environments directly, even through a router, requires careful consideration. Implement network segmentation, firewall rules, and potentially authentication mechanisms if these environments are accessible externally. For internal development, ensure the host system is secured.

Resource Management: Each container consumes CPU, memory, and disk I/O. Monitor resource usage on the host and consider setting resource limits for Podman containers using the --memory, --cpus, and other options in podman run.

Persistent Storage: The current setup loses any data within the container when it’s removed. For development that requires persistent data (e.g., databases, code changes not committed), use Podman volumes:

# Example with a volume for code
sudo podman run -d \
    --name dev-workspace-alice \
    -p 8081:5000 \
    --restart always \
    -v /path/on/host/for/alice/code:/app \
    dev-workspace-base:latest

Dynamic Port Allocation: Instead of manually assigning ports, you could implement a system that dynamically assigns the next available high port to new developers. This would involve scripting to check /proc/net/tcp or using tools like ss.

Configuration Management: For managing multiple developer environments and their configurations, consider using tools like Ansible to automate the deployment of containers and Nginx configurations.

Nginx Subdomain Routing: A more scalable approach for Nginx would involve:

  • Configuring DNS to point dev1.yourdomain.com, dev2.yourdomain.com, etc., to your Nginx server’s IP.
  • Modifying the Nginx http block to proxy requests to the appropriate container’s IP and port, or to the stream block if necessary. This often involves using map directives or server_name in http blocks to determine the target upstream.

This setup provides a robust foundation for isolated developer workspaces on RHEL 9, leveraging Podman for containerization and Nginx for flexible network routing.

Reader Interactions

Leave a Reply Cancel reply

You must be logged in to post a comment.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store
  • How to refactor legacy event ticket registers queries using modern WP_Query and custom Transient caching
  • Step-by-Step Guide: Offloading high-frequency member profile directories metadata writes to a Redis KV store

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (662)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • PHP (5)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (647)
  • SEO & Growth (492)
  • Server (118)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (726)
  • WordPress Theme Development (357)

Recent Posts

  • Debugging Guide: Diagnosing PHP-FPM child process pool exhaustion in multi-site network environments with modern tools
  • Debugging and Resolving complex namespace class loading collisions issues during heavy concurrent database traffic
  • Step-by-Step Guide: Offloading high-frequency customer support tickets metadata writes to a Redis KV store

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (726)
  • Debugging & Troubleshooting (662)
  • Security & Compliance (647)
  • SEO & Growth (492)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala