Setting Up a Linux Dev Server on Ubuntu with Docker
Tech Setup
Reviewed July 26, 2026

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.