ARTICLE

DMIT Docker Deployment: Install to Multi-Service

Install Docker and Compose on DMIT, build images, orchestrate services, persist data and secure.

Why Docker

Docker containerisation packages apps with their dependencies for consistent environments and easy migration. DMIT cloud servers support Docker. This article covers the complete flow of deploying services with Docker on DMIT.

Install Docker

# Debian/Ubuntu
apt update
apt install ca-certificates curl gnupg -y
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
apt update
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

# Verify
docker --version
docker compose version
docker run hello-world

Docker Compose

Compose is installed via the docker-compose-plugin package. Verify:

docker compose version

Use docker compose (space) not the old docker-compose (hyphen).

Basic usage

Run a single container

# Run Nginx
docker run -d --name web -p 80:80 nginx:alpine

# List running containers
docker ps

# View logs
docker logs web

# Enter container
docker exec -it web sh

# Stop and remove
docker stop web
docker rm web

Build with Dockerfile

# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# Build and run
docker build -t myapp:latest .
docker run -d --name myapp -p 3000:3000 myapp:latest

Compose multi-service orchestration

Typical web app: Nginx + Node.js + PostgreSQL.

# docker-compose.yml
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./certs:/etc/nginx/certs
    depends_on:
      - app

  app:
    build: ./app
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:
# Start all services
docker compose up -d

# View status
docker compose ps

# View logs
docker compose logs -f

# Stop
docker compose down

# Rebuild and start
docker compose up -d --build

Data persistence

Containers are stateless — persist data via volumes:

# Named volume (Docker-managed)
volumes:
  - db_data:/var/lib/postgresql/data

# Bind mount (host directory)
volumes:
  - ./uploads:/app/uploads
  - ./config:/app/config

Networking

# Custom network
docker network create mynet

# Containers communicate by service name
services:
  app:
    networks:
      - mynet
  db:
    networks:
      - mynet

networks:
  mynet:
    driver: bridge

Containers on the same network can reach each other by service name (e.g. db:5432) without exposing ports to the host.

IPv6 with Docker

DMIT provides IPv6 by default. Enable Docker IPv6 in /etc/docker/daemon.json:

{
  "ipv6": true,
  "fixed-cidr-v6": "fd00:dead:beef::/64",
  "experimental": true,
  "ip6tables": true
}
systemctl restart docker

More IPv6 config in IPv6 Setup Guide.

Resource limits

Limit container resources to prevent a single container from exhausting the host:

services:
  app:
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
        reservations:
          memory: 256M

More resource management in Performance Tuning.

Log management

Docker logs grow unbounded by default — configure rotation:

# /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Security

  • Don't run as root in containers — use the USER instruction
  • Restrict container privileges: security_opt: [no-new-privileges:true]
  • Never expose the Docker Socket (ports 2375/2376) to the public internet
  • Update images regularly: docker compose pull && docker compose up -d
  • Use .dockerignore to exclude sensitive files

SSH hardening in SSH Hardening.

Backing up Docker data

# Backup named volume
docker run --rm -v db_data:/data -v $(pwd):/backup alpine tar czf /backup/db_data.tar.gz /data

# Restore
docker run --rm -v db_data:/data -v $(pwd):/backup alpine tar xzf /backup/db_data.tar.gz /data

More backup strategies in Monitoring and Backup.

Common issues

Container can't access the internet?

docker run --rm alpine nslookup google.com
docker network inspect bridge

Port already in use?

ss -tlnp | grep :80
# Stop the process or change the mapped port

Out of disk space?

docker system prune -a --volumes
docker system df

More troubleshooting in Troubleshooting Guide.

Checklist

ItemStatus
Docker installed✓ docker --version
Compose installed✓ docker compose version
Container runs as non-root✓ USER instruction
Log rotation configured✓ daemon.json
Data persisted✓ volumes configured
Resource limits set✓ deploy.resources
Docker Socket not exposed✓ 2375 not open

Related: First Deploy Checklist, Migration Guide, Cost Optimisation.

Checked 2026-08-18. Docker installation commands follow the official documentation.

NEXT STEP

Ready to pick your DMIT plan?

Filter the official snapshot by budget and network, or check live stock at DMIT.

Disclosure: purchases through this link may earn the referrer a commission at no extra cost to you.