Linux

Setting Up a Linux Dev Server on Ubuntu with Docker

Tech Setup2 min read
TS

Tech Setup

Reviewed July 26, 2026

Setting Up a Linux Dev Server on Ubuntu with Docker

Introduction

Every development team needs a shared environment. Whether it is a staging server for QA, a shared database for the backend team, or a CI runner that builds and tests every pull request, having a reliable Linux server running Docker is one of the most versatile investments you can make.

In this guide, you will take a fresh Ubuntu 24.04 installation and turn it into a fully configured development server with Docker, Docker Compose, and essential services. By the end, you will have a machine ready to run any containerized application your team throws at it.

Prerequisites

  • A fresh Ubuntu 24.04 LTS server (bare metal or VPS)
  • SSH access with a non-root user with sudo privileges
  • A domain name pointing to the server (optional but recommended)

Step 1: System Update and Basic Security

Start with a fresh system update and configure basic security:

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git ufw fail2ban

Configure the firewall:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Configure fail2ban for SSH protection:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Step 2: Install Docker

Docker's official repository is the most reliable way to install on Ubuntu:

# Add Docker's official GPG key
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Add your user to the docker group so you do not need sudo for every command:

sudo usermod -aG docker $USER
newgrp docker

Verify:

docker --version
docker compose version

Step 3: Configure Docker for Development

Create a Docker daemon configuration for development-friendly defaults:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<'EOF'
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "dns": ["8.8.8.8", "8.8.4.4"]
}
EOF

sudo systemctl restart docker

Step 4: Set Up Docker Compose Services

Create a project directory for your shared services:

mkdir -p ~/dev-server && cd ~/dev-server

Create a docker-compose.yml with essential development services:

services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: devuser
      POSTGRES_PASSWORD: changeme_dev_2026
      POSTGRES_DB: devdb
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
      - redisdata:/data

  mailhog:
    image: mailhog/mailhog
    restart: unless-stopped
    ports:
      - "1025:1025"
      - "8025:8025"

  adminer:
    image: adminer
    restart: unless-stopped
    ports:
      - "8080:8080"

volumes:
  pgdata:
  redisdata:

Start everything:

docker compose up -d

You now have:

  • PostgreSQL on port 5432 with a dev database
  • Redis on port 6379 for caching
  • MailHog on port 8025 for testing emails
  • Adminer on port 8080 for database management

Step 5: Set Up Automatic Updates

Keep your Docker images updated automatically:

sudo apt install -y unattended-upgrades

Create a script that pulls and restarts updated images daily:

sudo tee /usr/local/bin/docker-update.sh <<'EOF'
#!/bin/bash
cd /home/$USER/dev-server
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
EOF

sudo chmod +x /usr/local/bin/docker-update.sh

Add a cron job:

sudo crontab -e
# Add this line to run daily at 3 AM:
0 3 * * * /usr/local/bin/docker-update.sh >> /var/log/docker-update.log 2>&1

Step 6: Set Up Log Monitoring

Install Dozzle for real-time container log monitoring:

docker run -d \
  --name dozzle \
  --restart unless-stopped \
  -p 8081:8000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  amir20/dozzle:latest

Access it at http://your-server:8081 to see live logs from all containers.

Step 7: Backup Strategy

Back up your PostgreSQL data daily:

sudo tee /usr/local/bin/pg-backup.sh <<'EOF'
#!/bin/bash
BACKUP_DIR="/backups/postgres"
mkdir -p $BACKUP_DIR
DATE=$(date +%Y%m%d_%H%M%S)
docker exec dev-server-postgres-1 pg_dump -U devuser devdb | gzip > $BACKUP_DIR/devdb_$DATE.sql.gz
# Keep only last 7 days
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
EOF

sudo chmod +x /usr/local/bin/pg-backup.sh

Add to crontab:

# Back up at 2 AM daily
0 2 * * * /usr/local/bin/pg-backup.sh >> /var/log/pg-backup.log 2>&1

Conclusion

You now have a Linux development server running Docker with PostgreSQL, Redis, email testing, database management, log monitoring, automatic updates, and daily backups. This setup scales from a solo developer to a small team of 5-10 engineers. The entire stack is containerized, reproducible, and can be migrated to a new machine by copying the docker-compose.yml and the backup volume data.