A beautiful, lightweight Docker container management service built with Rust, featuring real-time metrics visualization and an intuitive web interface.
- View Running Containers: See all your running containers at a glance
- Start/Stop/Restart: Easy one-click container controls
- Launch New Containers: Start new containers from available images
- Real-time Status: Live updates of container states
- Container Details: Expandable details view showing environment variables and container information
- Container Logs: View real-time container logs with WebSocket streaming
- Live Log Streaming: Real-time log updates via WebSocket connection
- Configurable History: Adjustable number of log lines to display
- Log Export: Download logs as text files with timestamps
- Auto-scroll: Automatic scrolling to follow new log entries
- Real-time Monitoring: Live container resource usage tracking
- Beautiful Charts: Interactive charts powered by Chart.js
- System Overview: Docker version, container counts, and image statistics
- Resource Tracking:
- CPU usage percentage per container
- Memory usage and limits
- Network I/O (RX/TX bytes)
- Disk I/O (read/write bytes)
- Process counts (PIDs)
- Responsive Design: Works on desktop and mobile
- Glass Morphism: Beautiful gradient backgrounds with frosted glass effects
- Smooth Animations: Hover effects and transitions
- Clean Architecture: HTML templates separated from Rust code with shared CSS
- Secure Authentication: Built-in login system with session management
- 12-Factor App: Environment-based configuration
- Graceful Shutdown: Proper signal handling for containers
- Health Checks: Built-in health and readiness endpoints
- Structured Logging: Configurable log levels and output
- Zero Downtime: Hot configuration reloads via environment
- Backend: Rust with Axum web framework
- Docker Integration: Bollard (Docker API client)
- Frontend: Vanilla JavaScript with Chart.js
- Styling: Modern CSS with gradients and animations
- File Serving: Static assets served efficiently
- Configuration: Environment variables with .env support
- π Mandatory Authentication: Secure login with Argon2 password hashing
- π‘οΈ Non-root Container: Runs as unprivileged user (UID 10001)
- π¦ Minimal Attack Surface: Built on
scratchbase image with no shell - π Read-only Docker Socket: Docker socket mounted read-only by default
- π« Static Binary: No runtime dependencies or package managers
- Automated Vulnerability Scanning: Trivy, Cargo Audit, and Semgrep
- License Compliance: Cargo Deny for dependency license checking
- Secret Detection: GitLeaks for credential scanning
- Dockerfile Security: Hadolint for container best practices
- Always use HTTPS in production (reverse proxy recommended)
- Use strong passwords and short session timeouts
- Deploy in isolated networks with proper firewall rules
- Regularly update dependencies and container images
- Monitor access logs and authentication failures
π See SECURITY.md for complete security documentation and vulnerability reporting.
We provide a justfile for running security checks locally before committing:
# Install just command runner (if not already installed)
# macOS: brew install just
# Linux: cargo install just
# Windows: cargo install just
# Run all security checks (matches CI)
just
# Quick security check (Rust only)
just security-quick
# Individual checks
just rust-security # Cargo audit + deny
just container-security # Docker security tests
just secret-scan # GitLeaks (if installed)
just policy-check # Security policy validation
# Install required security tools
just install-tools
# Show available commands
just --listAvailable Commands:
justorjust security-all- Run all security checksjust security-quick- Essential checks only (Rust + policy)just container-basic- Basic container security (no external tools)just rust-security- Dependency vulnerabilities and license checksjust versions- Show installed security tool versionsjust clean- Clean up test artifactsjust report- Generate security report
Prerequisites:
- Just command runner
- Docker (for container security checks)
- Optional: GitLeaks, Semgrep for additional scans
The easiest way to get started is using our pre-built Docker images from GitHub Container Registry:
# Pull the latest image
docker pull ghcr.io/oscillatelabsllc/simple-docker-manager:latest
# Run the container
docker run -d \
--name simple-docker-manager \
-p 3000:3000 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e SDM_PASSWORD=your-secure-password \
--restart unless-stopped \
ghcr.io/oscillatelabsllc/simple-docker-manager:latest
# Access the application
open http://localhost:3000Using Docker Compose:
version: "3.8"
services:
simple-docker-manager:
image: ghcr.io/oscillatelabsllc/simple-docker-manager:latest
ports:
- "3000:3000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- sdm-data:/data # Persistent password storage
environment:
- SDM_PASSWORD=your-secure-password
restart: unless-stopped
volumes:
sdm-data:For development or customization:
- Rust (latest stable version)
- Docker installed and running
- Access to Docker daemon (usually requires being in the
dockergroup on Linux)
-
Clone the repository
git clone <repository-url> cd simple-docker-manager
-
Configure the application (optional)
# Copy the example configuration cp env.example .env # Edit configuration as needed vim .env
-
Build the project
cargo build --release
-
Run the service
# With default configuration cargo run # Or with custom environment SDM_PORT=8080 SDM_LOG_LEVEL=debug cargo run
-
Open your browser Navigate to
http://localhost:3000(or your configured port)
Simple Docker Manager is available as pre-built Docker images from GitHub Container Registry, making deployment quick and easy. The images are built with a minimal, statically-compiled container based on scratch for maximum security and efficiency.
Available Images:
ghcr.io/oscillatelabsllc/simple-docker-manager:latest- Latest stable releaseghcr.io/oscillatelabsllc/simple-docker-manager:v1.x.x- Specific version tags
Supported Architectures:
linux/amd64(x86_64)linux/arm64(ARM64/Apple Silicon)
# Pull and run the latest image
docker run -d \
--name simple-docker-manager \
-p 3000:3000 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e SDM_PASSWORD=your-secure-password \
--restart unless-stopped \
ghcr.io/oscillatelabsllc/simple-docker-manager:latestThe easiest way to deploy is using Docker Compose with the pre-built image:
# Start the service
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the service
docker-compose downIf you need to customize the image or build from source:
# Build with default settings
./docker-build.sh
# Build and run immediately
./docker-build.sh --run
# Build with custom tag
./docker-build.sh --tag v1.0.0
# Build and push to registry
./docker-build.sh --registry ghcr.io/yourusername --push
# Build without cache
./docker-build.sh --no-cache
# See all options
./docker-build.sh --help# Build the image
docker build -t simple-docker-manager:latest .
# Run the container
docker run -d \
--name simple-docker-manager \
-p 3000:3000 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--restart unless-stopped \
simple-docker-manager:latest- Minimal Size: Built on
scratchbase image for maximum security and minimal attack surface - Static Binary: Fully statically linked Rust binary with no runtime dependencies
- OCI Labels: Comprehensive metadata for better container registry UX
- Health Endpoints: Built-in
/healthand/readyendpoints for monitoring - Proper Shutdown: Graceful handling of termination signals
Configure the container using environment variables:
docker run -d \
--name simple-docker-manager \
-p 3000:3000 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e SDM_LOG_LEVEL=debug \
-e SDM_METRICS_INTERVAL_SECONDS=10 \
-e SDM_PORT=3000 \
--restart unless-stopped \
simple-docker-manager:latestFor production environments, use the pre-built images:
The container exposes health endpoints for monitoring:
# Health check (includes Docker connectivity)
curl http://localhost:3000/health
# Readiness check (service is ready to handle requests)
curl http://localhost:3000/ready
# View container logs
docker logs -f simple-docker-manager- Read-only Docker socket: The container mounts Docker socket as read-only by default
- Non-root execution: The application runs as a non-root user within the container
- Minimal attack surface: Scratch base image contains no shell, package manager, or unnecessary utilities
- Network isolation: Use Docker networks to isolate the container if needed
- Base Image:
scratch(minimal, security-focused) - Binary: Statically compiled Rust binary (~10-20MB)
- Total Size: Typically under 30MB
- Architecture: Currently supports
x86_64Linux - OCI Compliant: Full OCI label support for registry metadata
simple-docker-manager/
βββ src/
β βββ main.rs # Application entry point with 12-Factor setup
β βββ config.rs # Environment-based configuration
β βββ web.rs # Web routes and handlers
β βββ docker.rs # Docker API integration
β βββ models.rs # Data structures
βββ templates/
β βββ dashboard.html # Metrics dashboard template
β βββ management.html # Container management template
βββ static/
β βββ styles.css # Shared CSS styles
β βββ dashboard.js # Frontend JavaScript
βββ Dockerfile # Multi-stage Docker build
βββ docker-compose.yml # Compose configuration
βββ docker-build.sh # Build script with options
βββ .dockerignore # Docker build context exclusions
βββ env.example # Configuration template
βββ Cargo.toml # Rust dependencies
βββ README.md # This file
GET /- Main container management interfaceGET /metrics- Real-time metrics dashboard
GET /health- Health check endpoint (returns 200/503 with Docker status)GET /ready- Readiness probe endpoint (always returns 200 when server is up)
POST /start-image- Start a new container from an imagePOST /start/:id- Start a stopped containerPOST /stop/:id- Stop a running containerPOST /restart/:id- Restart a container
GET /logs/:id- View container logs with optional?tail=NparameterGET /logs/:id/ws- WebSocket endpoint for real-time log streaming
GET /api/metrics- JSON metrics data for all containersGET /api/config- Current configuration settings
GET /login- Login page (when authentication is enabled)POST /login- Submit login credentialsPOST /logout- Logout and clear session
/static/*- CSS, JavaScript, and other static files
The application follows the 12-Factor App methodology and is configured entirely through environment variables.
All configuration is done via environment variables prefixed with SDM_:
| Variable | Default | Description |
|---|---|---|
SDM_HOST |
0.0.0.0 |
Server bind address |
SDM_PORT |
3000 |
Server port |
SDM_LOG_LEVEL |
info |
Log level (error, warn, info, debug, trace) |
SDM_DOCKER_SOCKET |
auto-detected | Docker socket path |
SDM_METRICS_INTERVAL_SECONDS |
5 |
Metrics update interval |
SDM_METRICS_HISTORY_LIMIT |
20 |
Max metrics history points |
SDM_MAX_CHART_CONTAINERS |
5 |
Max containers shown in charts (for performance) |
SDM_SHUTDOWN_TIMEOUT_SECONDS |
30 |
Graceful shutdown timeout |
SDM_AUTH_ENABLED |
true |
Enable/disable authentication |
SDM_AUTH_USERNAME |
admin |
Username for authentication |
SDM_AUTH_PASSWORD |
auto-generated | Password for authentication (see below) |
SDM_SESSION_TIMEOUT_SECONDS |
3600 |
Session timeout (1 hour) |
SDM_PASSWORD_FILE |
auto-detected | Custom password file location |
The Simple Docker Manager uses secure authentication by default to protect your Docker environment.
-
Custom Password: Set
SDM_AUTH_PASSWORDenvironment variableSDM_AUTH_PASSWORD=your_secure_password cargo run
-
Auto-Generated Password: If no password is provided, the system will:
- Generate a secure 24-character random password
- Save it to a persistent file with secure permissions (600)
- Display the password in logs on first run
- Reuse the saved password on subsequent runs
-
Password File Locations: The system automatically chooses the best location:
For Containers (auto-detected):
/data/sdm_password(preferred - mount a volume here)/config/sdm_password(alternative config location)/app/data/sdm_password(app-specific data directory)/var/lib/sdm/password(system-style location)
For Development:
.sdm_password(current directory)
Custom Location:
SDM_PASSWORD_FILE=/my/custom/path/password cargo run
-
Accessing Your Password:
# View the current password (path shown in startup logs) cat /data/sdm_password # Or check the logs when starting the application cargo run
Docker Run:
# Create a volume for persistent password storage
docker volume create sdm-data
# Run with volume mounted
docker run -d \
--name simple-docker-manager \
-p 3000:3000 \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v sdm-data:/data \
--restart unless-stopped \
ghcr.io/oscillatelabsllc/simple-docker-manager:latest
# View the generated password
docker exec simple-docker-manager cat /data/sdm_passwordDocker Compose:
services:
simple-docker-manager:
image: ghcr.io/oscillatelabsllc/simple-docker-manager:latest
ports:
- "3000:3000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- sdm-data:/data # Persistent password storage
restart: unless-stopped
volumes:
sdm-data:- Argon2 Hashing: Passwords are hashed using industry-standard Argon2
- Secure File Permissions: Password file is created with 600 permissions (owner read/write only)
- Session Management: Configurable session timeouts with secure cookies
- Container Detection: Automatically uses container-friendly paths when deployed
- HTTPS Ready: Use behind a reverse proxy with TLS for production
# Only for development/testing - NOT for production
SDM_AUTH_ENABLED=false cargo runexport SDM_PORT=8080
export SDM_LOG_LEVEL=warn
cargo run --release# Copy the example
cp env.example .env
# Edit your configuration
echo "SDM_PORT=8080" >> .env
echo "SDM_LOG_LEVEL=debug" >> .env
# Run (automatically loads .env)
cargo run# Override specific values at runtime
SDM_PORT=9000 SDM_LOG_LEVEL=trace cargo runFor Docker deployment, pass environment variables:
docker run -e SDM_PORT=8080 -e SDM_LOG_LEVEL=warn ghcr.io/oscillatelabsllc/simple-docker-manager:latestThe /api/metrics endpoint returns comprehensive container metrics:
{
"system": {
"timestamp": "2024-01-01T12:00:00Z",
"total_containers": 5,
"running_containers": 3,
"total_images": 10,
"docker_version": "24.0.0"
},
"containers": [
{
"container_id": "abc123...",
"container_name": "my-app",
"timestamp": "2024-01-01T12:00:00Z",
"cpu_usage_percent": 15.5,
"memory_usage_mb": 256.0,
"memory_limit_mb": 512.0,
"memory_usage_percent": 50.0,
"network_rx_bytes": 1024000,
"network_tx_bytes": 512000,
"block_read_bytes": 204800,
"block_write_bytes": 102400,
"pids": 25
}
]
}The service continuously polls Docker for container statistics, calculating:
- CPU Usage: Percentage based on system CPU time
- Memory Usage: Current usage vs. container limits
- Network Traffic: Bytes received and transmitted
- Disk I/O: Read and write operations
- Process Count: Number of running processes
- Live Updates: Charts update every 5 seconds (configurable)
- History Tracking: Maintains configurable data points for trend visualization
- Multiple Metrics: Separate charts for CPU, memory, network, and disk
- Color Coding: Unique colors per container for easy identification
- Separation of Concerns: HTML templates separate from Rust code
- Shared Styling: Single CSS file for consistent design across views
- Static Asset Serving: Efficient file serving for CSS/JS
- Type Safety: Strong typing with Rust's type system
- Error Handling: Graceful error handling and user feedback
- Expandable Details: Click the "Details" button to view comprehensive container information
- Environment Variables: Sorted alphabetically for easy browsing
- Port Mappings: Consistently ordered by container port number for predictable display
- Container Information: Full container ID, image details, and metadata
- One-Click Actions: Start, stop, restart, and view logs directly from the interface
The application provides standard health check endpoints:
- Health Check (
/health): Returns 200 if Docker is accessible, 503 otherwise - Readiness Check (
/ready): Returns 200 if the server can handle requests
The application handles shutdown signals gracefully:
- SIGTERM: Container termination
- SIGINT: Ctrl+C for development
- Configurable timeout: Prevents hanging shutdowns
Structured logging with configurable levels:
# Development
SDM_LOG_LEVEL=debug cargo run
# Production
SDM_LOG_LEVEL=warn cargo run
# Environment-based (respects RUST_LOG if SDM_LOG_LEVEL not set)
RUST_LOG=simple_docker_manager=debug cargo run-
Port in use: Change the port via environment variable
SDM_PORT=8080 cargo run
-
Permission denied: Ensure Docker access
# Add user to docker group (Linux) sudo usermod -aG docker $USER # Log out and back in
-
Docker not accessible: Check Docker daemon
docker ps # Should work without sudo
- Check current configuration: The app logs its configuration on startup
- Validate environment variables: Ensure proper naming (
SDM_prefix) - Check .env file: Ensure it's in the working directory
-
Adjust metrics interval:
SDM_METRICS_INTERVAL_SECONDS=10 cargo run
-
Reduce history retention:
SDM_METRICS_HISTORY_LIMIT=10 cargo run
- Docker socket: The app auto-detects Docker socket location
- Custom socket: Set
SDM_DOCKER_SOCKET=/path/to/docker.sock - Remote Docker: Currently not supported (local socket only)
If you see errors like Error in the hyper legacy client: client error (Connect), this indicates Docker socket permission problems:
Symptoms:
- Authentication works fine, but API endpoints fail
- Error message: "hyper legacy client: client error (Connect)"
- Health endpoint returns unhealthy status
Root Cause: The container runs as a non-root user (UID 10001) by default, but Docker socket access typically requires root privileges or docker group membership.
Solutions:
-
Run as root (Docker Compose - Recommended for simplicity):
services: simple-docker-manager: # ... other config ... user: "0:0" # Run as root
-
Use host user (Linux only):
services: simple-docker-manager: # ... other config ... user: "${DOCKER_USER_ID:-1000}:${DOCKER_GROUP_ID:-1000}"
export DOCKER_USER_ID=$(id -u) export DOCKER_GROUP_ID=$(getent group docker | cut -d: -f3) docker-compose up -d
-
Docker run with root:
docker run -d \ --name simple-docker-manager \ --user 0:0 \ -p 3000:3000 \ -v /var/run/docker.sock:/var/run/docker.sock:ro \ ghcr.io/oscillatelabsllc/simple-docker-manager:latest
Note: On macOS with Docker Desktop, running as root is typically required since there's no docker group. On Linux, you can alternatively add the container user to the docker group.
