Creating Your First Isolated Linux Container with SSH Access: A Step-by-Step Guide

Creating Your First Isolated Linux Container with SSH Access: A Step-by-Step Guide




Introduction

Have you ever wondered how tools like Docker create isolated environments? In this guide, we’ll build a simple container from scratch using Linux namespaces. You’ll create a fully isolated environment with its own network and filesystem, then access it remotely via SSH or NSENTER. – No prior container experience needed!




What You’ll Learn

  1. How Linux namespaces work
  2. Setting up a minimal container filesystem
  3. Configuring isolated networking
  4. Create a Custom cgroup
  5. Limit CPU Usage
  6. Startup a webserver & host a simple webpage
  7. nsenter or SSH access with Dropbear (a lightweight SSH server) optinal



Prerequisites

  • A Linux system (Ubuntu 22.04 used here)
  • sudo access
  • Basic terminal familiarity
  • Internet connection



Step 1: The Complete Script

Here’s the full script we’ll be using. Don’t worry if it looks complex—we’ll break it down line by line!

Save this as create-container.sh:

#!/usr/bin/env bash
# setup_isolated_container_ssh.sh
# This script sets up a fully isolated container environment with its own network namespace using a veth pair,
# then chroots into a minimal filesystem and starts Dropbear SSH daemon and a BusyBox HTTP server.

set -eo pipefail

# CONFIGURATION VARIABLES
CONTAINER_ROOT="/opt/isolated_container"
HOST_VETH="veth-host"
CONTAINER_VETH="veth-container"
HOST_IP="192.168.200.1/24"
CONTAINER_IP="192.168.200.2/24"
GATEWAY_IP="192.168.200.1"
SSH_PORT=22
HTTP_PORT=80

# Clean up any existing container filesystem
rm -rf "${CONTAINER_ROOT}"
mkdir -p "${CONTAINER_ROOT}"/{bin,etc/dropbear,proc,dev,www}

# Create device nodes (if not already present)
if [ ! -e "${CONTAINER_ROOT}/dev/null" ]; then
    mknod -m 666 "${CONTAINER_ROOT}/dev/null" c 1 3
fi
if [ ! -e "${CONTAINER_ROOT}/dev/urandom" ]; then
    mknod -m 666 "${CONTAINER_ROOT}/dev/urandom" c 1 9
fi

# Set up BusyBox in the container filesystem
cp /bin/busybox "${CONTAINER_ROOT}/bin/"
chmod +x "${CONTAINER_ROOT}/bin/busybox"
cd "${CONTAINER_ROOT}/bin"
ln -sf busybox sh
ln -sf busybox ls
ln -sf busybox mkdir
ln -sf busybox cat
ln -sf busybox echo
ln -sf busybox httpd
cd -

# Set up Dropbear in the container filesystem
cp /usr/sbin/dropbear "${CONTAINER_ROOT}/bin/dropbear"
chmod +x "${CONTAINER_ROOT}/bin/dropbear"
# Copy required libraries for dropbear (using ldd)
ldd /usr/sbin/dropbear | awk '/=>/ {print $3}' | while read -r lib; do
    dest_dir="${CONTAINER_ROOT}$(dirname "$lib")"
    mkdir -p "$dest_dir"
    cp "$lib" "$dest_dir/"
done

# Create minimal passwd and group files
echo "root:x:0:0:root:/:/bin/sh" > "${CONTAINER_ROOT}/etc/passwd"
echo "root:x:0:" > "${CONTAINER_ROOT}/etc/group"

# Generate SSH host key if not present
if [ ! -f "${CONTAINER_ROOT}/etc/dropbear/dropbear_rsa_host_key" ]; then
    dropbearkey -t rsa -f "${CONTAINER_ROOT}/etc/dropbear/dropbear_rsa_host_key"
fi

# Set up web content (for testing; remove if not needed)
echo "Isolated Container Web Server Ready!" > "${CONTAINER_ROOT}/www/index.html"

# Set up veth pair on the host
ip link add "$HOST_VETH" type veth peer name "$CONTAINER_VETH"
ip addr add "$HOST_IP" dev "$HOST_VETH"
ip link set "$HOST_VETH" up

# Launch an isolated container shell with unshare and capture its PID
CONTAINER_PID=$(unshare --fork --pid --mount --uts --ipc --net --user --map-root-user bash -c 'echo $$; exec sleep infinity')
echo "Container PID: $CONTAINER_PID"

# Move the container side of the veth pair into the container's network namespace
ip link set "$CONTAINER_VETH" netns "$CONTAINER_PID"

# Configure networking inside the container using nsenter
nsenter --target "$CONTAINER_PID" --net bash -c "
  ip addr add '$CONTAINER_IP' dev $CONTAINER_VETH &&
  ip link set $CONTAINER_VETH up &&
  ip link set lo up &&
  ip route add default via '$GATEWAY_IP'
"

# Mount proc in the container
mkdir -p "${CONTAINER_ROOT}/proc"
nsenter --target "$CONTAINER_PID" --mount bash -c "mount -t proc proc ${CONTAINER_ROOT}/proc"

# Chroot into the container and start SSH and HTTP services
  ip link set lo up &&
  ip route add default via '$GATEWAY_IP'
"

# Mount proc in the container
mkdir -p "${CONTAINER_ROOT}/proc"
nsenter --target "$CONTAINER_PID" --mount bash -c "mount -t proc proc ${CONTAINER_ROOT}/proc"

# Chroot into the container and start SSH and HTTP services

# Mount proc in the container
mkdir -p "${CONTAINER_ROOT}/proc"
nsenter --target "$CONTAINER_PID" --mount bash -c "mount -t proc proc ${CONTAINER_ROOT}/proc"

# Chroot into the container and start SSH and HTTP services
mkdir -p "${CONTAINER_ROOT}/proc"
nsenter --target "$CONTAINER_PID" --mount bash -c "mount -t proc proc ${CONTAINER_ROOT}/proc"

# Chroot into the container and start SSH and HTTP services
nsenter --target "$CONTAINER_PID" --mount bash -c "mount -t proc proc ${CONTAINER_ROOT}/proc"

# Chroot into the container and start SSH and HTTP services

# Chroot into the container and start SSH and HTTP services
# Chroot into the container and start SSH and HTTP services
nsenter --target "$CONTAINER_PID" --mount chroot "${CONTAINER_ROOT}" /bin/sh -c "
nsenter --target "$CONTAINER_PID" --mount chroot "${CONTAINER_ROOT}" /bin/sh -c "
  echo 'Inside container: starting HTTP server and Dropbear SSH daemon...';
  echo 'Inside container: starting HTTP server and Dropbear SSH daemon...';
  /bin/httpd -f -p $HTTP_PORT -h /www &
  exec /bin/dropbear -F -E -p $SSH_PORT
"

# End of script
Enter fullscreen mode

Exit fullscreen mode




Step 2: Understanding Key Components



1. Container Filesystem

  • /bin: Contains BusyBox (provides basic Linux commands)
  • /dev: Device files like null and urandom (required for programs to work)
  • /etc/dropbear: Stores SSH host keys



2. Network Setup

  • Creates a virtual Ethernet pair (host-side and container-side)
  • Container gets IP 192.168.100.2, host uses 192.168.100.1
  • Port 2222 on host forwards to container’s SSH port (22)



Step 3: Running the Script

  1. Make it executable:
   chmod +x create-container.sh
Enter fullscreen mode

Exit fullscreen mode

  1. Execute with sudo:
   sudo ./create-container.sh
Enter fullscreen mode

Exit fullscreen mode

  1. Connect via SSH:
   sudo nsenter --target  --mount --uts --ipc --net --pid bash
Enter fullscreen mode

Exit fullscreen mode

OR

  1. Connect via SSH:
   ssh root@localhost -p 2222
Enter fullscreen mode

Exit fullscreen mode




Step 4: What to Expect



Connection

You’ll see a warning about the SSH key fingerprint (this is normal). Type yes to continue.



Inside the Container

Try these commands:

ls /      # See container filesystem
ip addr   # Show container's network
ps aux    # List running processes (only container's)
Enter fullscreen mode

Exit fullscreen mode




Troubleshooting



1. SSH Connection Fails

  iptables -t nat -L PREROUTING
Enter fullscreen mode

Exit fullscreen mode



2. Permission Denied

  • Ensure you used sudo when running the script
  • Recreate device files if missing:
  mknod -m 666 /opt/my_container/dev/null c 1 3
Enter fullscreen mode

Exit fullscreen mode




How It Works: Beginner’s Glossary

  • Namespace: A isolated workspace for processes (like a private room)
  • Veth Pair: Virtual Ethernet cable connecting host and container
  • BusyBox: Swiss Army knife of Linux commands in a single file
  • Dropbear: Lightweight SSH server (uses less resources than OpenSSH)



Next Steps

  1. Add Persistence:

    Create files in /opt/my_container/www.

  2. Customize SSH:

    Add your public key to /opt/my_container/root/.ssh/authorized_keys.

  3. ** Verify cgroups v2 is Active**

   mount | grep cgroup2
Enter fullscreen mode

Exit fullscreen mode

  1. Create a Custom cgroup
    mkdir /sys/fs/cgroup/mycontainer

  2. Limit CPU Usage

   echo "50000 100000" > /sys/fs/cgroup/mycontainer/cpu.max
Enter fullscreen mode

Exit fullscreen mode

6 Limit Memory Usage

   echo $((512 * 1024 * 1024)) > /sys/fs/cgroup/mycontainer/memory.max
Enter fullscreen mode

Exit fullscreen mode

  1. Explore More:
    Try installing additional software in the container using chroot.



Conclusion

You’ve just created a fully isolated Linux container from scratch! While this isn’t production-ready, it demonstrates core containerization concepts used by Docker and Kubernetes. Experiment with modifying the network setup or adding new services to deepen your understanding.

Happy container hacking! 🐧🔒



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *