Modern Server Management Made Simple: An All-in-One Docker Infrastructure

Modern Server Management Made Simple: An All-in-One Docker Infrastructure

ยท

8 min read

Managing servers effectively doesn't have to be complex or time-consuming. By combining Docker with three carefully selected tools - Portainer, Traefik, and Watchtower - we can create a server infrastructure that practically manages itself. This article will guide you through setting up this efficient stack and explain how these tools work together to streamline your server management.

Understanding Our Infrastructure Tools

Before diving into configuration, let's understand what makes each component special and how they work together to create a seamless system.

Docker: Your Application's Home

Docker serves as the foundation of our infrastructure, providing containerization that lets us run applications in isolated environments. Think of Docker as a specialized apartment building for your applications. Each application gets its own fully-furnished apartment (container) with everything it needs to run - from basic utilities (runtime) to furniture (libraries). These apartments are completely isolated from each other, ensuring that what happens in one doesn't affect the others.

Portainer: Your Building Manager

Portainer provides a user-friendly web interface for managing Docker environments. It serves as your building's management office. Instead of running around the building with a clipboard and tools, you get a sleek dashboard where you can monitor all your apartments, handle maintenance, and even add new tenants - all from one central location. No more memorizing complex maintenance procedures or juggling multiple tools.

Traefik: Your Smart Doorman

Traefik acts as a modern reverse proxy and load balancer. It's like an intelligent doorman who knows exactly where to direct visitors. When someone arrives at your building (incoming web traffic), Traefik automatically knows which apartment (container) they're trying to reach. It also handles security by managing SSL certificates, ensuring all visits are secure and private.

Watchtower: Your Maintenance Crew

Think of Watchtower as a diligent maintenance team that works while you sleep. It constantly monitors your running Docker containers and automatically updates them when new versions become available. Just like a maintenance crew checking for building improvements, Watchtower ensures your applications always have the latest features and security patches without requiring manual intervention.

Setting Up Your Infrastructure

๐Ÿ’ก
This setup can be achieved more easily using the docker-setup tool. View it here: https://github.com/jackkweyunga/docker-setup

Let's organize our setup with a clear structure:

โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ configure.sh
โ”œโ”€โ”€ docker-compose.yml
โ””โ”€โ”€ traefik
    โ””โ”€โ”€ traefik.yml

Now, let's create our infrastructure definition in docker-compose.yml:

services:

  # Traefik
  traefik:
    container_name: "traefik"
    image: "traefik:v3.2"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - traefik-ssl-certs:/ssl-certs
      - ./traefik:/etc/traefik
    networks:
      - traefik_network
    restart: always
    labels:
      com.centurylinklabs.watchtower.enable: "false"
    environment:
      - TZ=Africa/Dar_es_Salaam

  # Portainer
  portainer:
    container_name: portainer
    image: "docker.io/portainer/portainer-ce:2.21.4"
    expose:
      - 9000
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer-data:/data
    networks:
      - traefik_network
    restart: always
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
      - "traefik.enable=true"
      - "traefik.http.routers.portainer.rule=Host(`${PORTAINER_DOMAIN}`)"
      - "traefik.http.routers.portainer.entrypoints=websecure"
      - "traefik.http.services.portainer.loadbalancer.server.port=9000"
      - "traefik.http.routers.portainer.tls.certresolver=production"

  # Watchtower
  watchtower:
    container_name: "watchtower"
    image: "docker.io/containrrr/watchtower"
    volumes:
       - /var/run/docker.sock:/var/run/docker.sock
       - /root/.docker/config.json:/config.json:ro
    restart: always
    environment:
      TZ: Africa/Dar_es_Salaam
      WATCHTOWER_LIFECYCLE_HOOKS: "1"
    command: --debug --cleanup --interval 30

networks:
  traefik_network:
    external: true

volumes:
  portainer-data:
  traefik-ssl-certs:

The configuration above sets up our three core services with careful attention to security and reliability. Each service is configured to work together seamlessly while maintaining proper isolation and security practices.

Creating a Secure Gateway with Traefik

Let's set up Traefik to manage incoming traffic securely. Create traefik/traefik.yml:

global:
  checkNewVersion: true
  sendAnonymousUsage: false

api:
  dashboard: true
  insecure: false

entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https

  websecure:
    address: :443

certificatesResolvers:
  staging:
    acme:
      email: your-email@domain.com
      storage: /etc/traefik/certs/acme.json
      caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
      tlsChallenge: {}
      httpChallenge:
        entryPoint: web

  production:
    acme:
      email: your-email@domain.com
      storage: /etc/traefik/certs/acme.json
      caServer: "https://acme-v02.api.letsencrypt.org/directory"
      tlsChallenge: {}
      httpChallenge:
        entryPoint: web

providers:
  docker:
    exposedByDefault: false
  file:
    directory: /etc/traefik
    watch: true

This configuration sets up secure HTTPS access, automatic SSL certificate management through Let's Encrypt, and proper traffic routing for your applications.

Making Setup Easy with configure.sh

Create a script to automate the setup process:

#!/bin/bash

# This script automates the setup of our Docker infrastructure
# It handles Docker installation, network creation, and initial configuration

#---------------------------------------
# Utility Functions
#---------------------------------------

# Checks if a command exists on the system
# Usage: if command_exists docker; then ...
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Validates email format using regex
# Returns 0 for valid email, 1 for invalid
# Usage: if validate_email "test@example.com"; then ...
validate_email() {
    local email=$1
    if [[ $email =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
        return 0
    else
        return 1
    fi
}

# Validates domain name format
# Returns 0 for valid domain, 1 for invalid
# Usage: if validate_domain "example.com"; then ...
validate_domain() {
    local domain=$1
    if [[ $domain =~ ^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$ ]]; then
        return 0
    else
        return 1
    fi
}

#---------------------------------------
# Docker Installation
#---------------------------------------

install_docker() {
    echo "๐Ÿณ Installing Docker..."

    # Download and run the official Docker installation script
    curl -fsSL https://get.docker.com -o get-docker.sh
    sudo sh get-docker.sh

    # Add current user to docker group to avoid needing sudo
    sudo usermod -aG docker $USER

    echo "โœ… Docker installation completed successfully"

    # Inform user about group changes
    echo "Note: You may need to log out and back in for group changes to take effect"
    read -p "Would you like to restart the shell now? (y/n) " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        exec su -l $USER
    fi
}

#---------------------------------------
# Environment Setup
#---------------------------------------

setup_environment() {
    echo "๐Ÿ”ง Setting up environment..."

    # Create required directories
    mkdir -p traefik/certs
    touch traefik/certs/acme.json
    chmod 600 traefik/certs/acme.json

    # Create .env file if it doesn't exist
    if [ ! -f .env ]; then
        touch .env
        echo "Created .env file"
    fi

    # Create Docker network if it doesn't exist
    if ! docker network ls | grep -q "traefik_network"; then
        docker network create traefik_network
        echo "Created traefik_network"
    fi
}

#---------------------------------------
# Configuration Collection
#---------------------------------------

collect_configuration() {
    echo "โš™๏ธ Collecting configuration details..."

    # Get Portainer domain
    while true; do
        read -p "Enter domain for Portainer (e.g., portainer.yourdomain.com): " portainer_domain
        if validate_domain "$portainer_domain"; then
            echo "PORTAINER_DOMAIN=$portainer_domain" > .env
            break
        else
            echo "โŒ Invalid domain format. Please try again."
        fi
    done

    # Get email for SSL certificates
    while true; do
        read -p "Enter email address for SSL certificates: " email_address
        if validate_email "$email_address"; then
            # Update Traefik configuration with the email
            sed -i "s/your-email@domain.com/$email_address/" traefik/traefik.yml
            break
        else
            echo "โŒ Invalid email format. Please try again."
        fi
    done

    # Optional: Configure timezone
    read -p "Enter timezone (default: UTC): " timezone
    timezone=${timezone:-UTC}
    echo "TZ=$timezone" >> .env
}

#---------------------------------------
# Main Setup Process
#---------------------------------------

main() {
    echo "๐Ÿš€ Starting Docker infrastructure setup..."

    # Check for Docker installation
    if ! command_exists docker; then
        echo "Docker is not installed"
        read -p "Would you like to install Docker now? (y/n) " -n 1 -r
        echo
        if [[ $REPLY =~ ^[Yy]$ ]]; then
            install_docker
        else
            echo "โŒ Docker is required to continue. Exiting..."
            exit 1
        fi
    fi

    # Setup environment
    setup_environment

    # Collect configuration
    collect_configuration

    # Start the services
    echo "๐Ÿš€ Starting services..."
    docker compose pull
    docker compose up -d

    # Check if services started successfully
    if [ $? -eq 0 ]; then
        echo "
โœ… Setup completed successfully!

You can access your services at:
๐Ÿ”— Portainer: https://$portainer_domain

Please note:
- Allow a few minutes for SSL certificates to be generated
- Portainer will ask you to set an admin password on first login
- Check docker logs if you encounter any issues

For more information, visit:
- Portainer: https://portainer.io/
- Traefik: https://traefik.io/
- Watchtower: https://containrrr.dev/watchtower/
"
    else
        echo "โŒ An error occurred while starting the services. Please check the logs:"
        echo "docker logs traefik"
        echo "docker logs portainer"
        echo "docker logs watchtower"
    fi
}

# Start the setup process
main "$@"

This installation assistant handles everything from Docker installation to final configuration, making the setup process smooth and error-free.

Getting Started

To launch your new infrastructure:

chmod +x configure.sh
./configure.sh

The script will guide you through providing necessary information:

  • A domain name for accessing Portainer

  • Your email address for SSL certificate management

Deploying Applications

Once your infrastructure is running, deploying new applications becomes straightforward. Here's an example deploying a WordPress site:

version: '3'

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress
    restart: always
    networks:
      - traefik_network
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=wordpress
      - WORDPRESS_DB_PASSWORD=secure_password
      - WORDPRESS_DB_NAME=wordpress
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.wordpress.rule=Host(`blog.yourdomain.com`)"
      - "traefik.http.services.wordpress.loadbalancer.server.port=80"

networks:
  traefik_network:
    external: true

This configuration automatically connects WordPress to your infrastructure, sets up secure HTTPS access, and enables automatic updates through Watchtower.

Maintenance and Monitoring

Your infrastructure largely maintains itself, but here are key areas to monitor:

Automatic Updates

Watchtower handles updates automatically. Monitor its activities with:

docker logs watchtower

Infrastructure Management

Access Portainer at https://portainer.yourdomain.com to:

  • Monitor container health and resource usage

  • View container logs

  • Manage container lifecycle

  • Deploy new containers

Best Practices

To ensure long-term success with your infrastructure:

  1. Data Protection

    • Maintain regular backups of configuration files

    • Back up application data volumes

    • Store credentials securely

    • Document your backup procedures

  2. Security Management

    • Run containers as non-root users

    • Keep your host system updated

    • Perform regular security audits

    • Monitor container logs for suspicious activity

    • Implement proper network segmentation

  3. Performance Monitoring

    • Watch container resource usage

    • Set up alerts for critical events

    • Monitor update success rates

    • Check SSL certificate status

    • Track system resource utilization

Conclusion

This infrastructure setup provides a robust, self-maintaining environment that lets you focus on developing and deploying applications rather than managing servers. The combination of Docker, Portainer, Traefik, and Watchtower creates a powerful yet simple server configuration that handles most administrative tasks automatically.

The beauty of this setup lies in its simplicity and automation. Once configured, it requires minimal maintenance while providing enterprise-grade features like automatic SSL certificate management, container updates, and a user-friendly management interface.

Remember to regularly check your logs and monitor system resources, but with this setup, you'll spend far less time on server management and more time on what matters - building and improving your applications.

By following this guide and implementing these best practices, you'll have a modern, efficient, and largely self-managing server infrastructure that can grow with your needs while maintaining security and reliability.

ย