Introduction
Properly configuring Docker is essential for both security and functionality, especially in enterprise and production environments. This comprehensive guide covers critical configuration scenarios, security hardening techniques, and best practices for running Docker safely in production.
We’ll explore proxy configuration, registry trust management, security scanning, resource limits, and the principle of least privilege—all essential for production-ready Docker deployments.
Part 1: Configuring Docker for Corporate Networks
Understanding the Proxy Challenge
In corporate environments, direct internet access is often restricted. All traffic must go through an HTTP/HTTPS proxy server. Docker needs to be configured to use this proxy for:
- Pulling images from Docker Hub
- Building images that download packages
- Containers that need internet access
Configuring the Docker Daemon for Proxy
The Docker daemon needs proxy configuration to pull images and communicate with registries.
On Linux (systemd):
- Create a systemd drop-in directory:
sudo mkdir -p /etc/systemd/system/docker.service.d
- Create the proxy configuration file:
sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf
- Add the proxy settings:
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080"
Environment="HTTPS_PROXY=https://proxy.example.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp.example.com,10.0.0.0/8"
Understanding NO_PROXY:
localhost, 127.0.0.1
: Local addressesdocker-registry.example.com
: Your private registry.corp.example.com
: All subdomains of corp.example.com10.0.0.0/8
: Internal network CIDR
- Reload and restart Docker:
sudo systemctl daemon-reload
sudo systemctl restart docker
- Verify the configuration:
sudo systemctl show --property=Environment docker
On Docker Desktop (Windows/Mac):
- Open Docker Desktop
- Go to Settings → Resources → Proxies
- Enable Manual proxy configuration
- Enter your proxy details:
- Web Server (HTTP):
http://proxy.example.com:8080
- Secure Web Server (HTTPS):
https://proxy.example.com:8080
- Bypass:
localhost,127.0.0.1,*.example.com
- Web Server (HTTP):
- Click Apply & Restart
Configuring Proxy for Container Runtime
Containers themselves may also need proxy configuration to access the internet.
Method 1: Environment Variables in docker run
docker run -d \
-e HTTP_PROXY="http://proxy.example.com:8080" \
-e HTTPS_PROXY="https://proxy.example.com:8080" \
-e NO_PROXY="localhost,127.0.0.1" \
my-app
Method 2: In Dockerfile
FROM ubuntu:20.04
# Set proxy for build time
ENV HTTP_PROXY="http://proxy.example.com:8080"
ENV HTTPS_PROXY="https://proxy.example.com:8080"
ENV NO_PROXY="localhost,127.0.0.1"
# Install packages (will use proxy)
RUN apt-get update && apt-get install -y curl
# Unset proxy for runtime (optional)
ENV HTTP_PROXY=""
ENV HTTPS_PROXY=""
Method 3: Docker Compose
version: '3.8'
services:
web:
image: my-app
environment:
- HTTP_PROXY=http://proxy.example.com:8080
- HTTPS_PROXY=https://proxy.example.com:8080
- NO_PROXY=localhost,127.0.0.1
Method 4: Global Container Proxy (daemon.json)
sudo nano /etc/docker/daemon.json
{
"proxies": {
"default": {
"httpProxy": "http://proxy.example.com:8080",
"httpsProxy": "https://proxy.example.com:8080",
"noProxy": "localhost,127.0.0.1,docker-registry.example.com"
}
}
}
sudo systemctl restart docker
Part 2: Configuring Access to Private/Insecure Registries
Understanding the Security Model
By default, Docker requires all registries to use TLS (HTTPS). This is a critical security feature. However, for local development or air-gapped networks, you may need to configure Docker to trust an insecure (HTTP) registry.
⚠️ Warning: Only use insecure registries in isolated, trusted networks. Never in production!
Configuring Insecure Registries
On Linux:
- Edit daemon.json:
sudo nano /etc/docker/daemon.json
- Add the insecure registry:
{
"insecure-registries": [
"myregistry.local:5000",
"192.168.1.100:5000"
]
}
- Restart Docker:
sudo systemctl restart docker
- Verify:
docker info | grep -A 5 "Insecure Registries"
On Docker Desktop:
- Go to Settings → Docker Engine
- Edit the JSON configuration:
{
"insecure-registries": [
"myregistry.local:5000"
]
}
- Click Apply & Restart
Testing the Insecure Registry
# Pull an image
docker pull alpine
# Tag for your registry
docker tag alpine myregistry.local:5000/alpine:latest
# Push (will work now)
docker push myregistry.local:5000/alpine:latest
# Pull back
docker pull myregistry.local:5000/alpine:latest
Part 3: Docker Security Best Practices
1. Run Containers as Non-Root User
Why: If a container is compromised, the attacker has root access to the container and potentially the host.
Bad:
FROM node:16
WORKDIR /app
COPY . .
CMD ["node", "server.js"]
# Runs as root!
Good:
FROM node:16
# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
COPY --chown=appuser:appuser . .
# Switch to non-root user
USER appuser
CMD ["node", "server.js"]
Verify:
docker run my-app whoami
# Should output: appuser (not root)
2. Use Read-Only Filesystems
Prevent containers from modifying their filesystem:
docker run --read-only \
--tmpfs /tmp \
--tmpfs /var/run \
my-app
In Docker Compose:
services:
web:
image: my-app
read_only: true
tmpfs:
- /tmp
- /var/run
3. Limit Container Resources
Prevent containers from consuming all host resources:
docker run -d \
--memory="512m" \
--memory-swap="512m" \
--cpus="1.0" \
--pids-limit=100 \
my-app
In Docker Compose:
services:
web:
image: my-app
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
4. Drop Unnecessary Capabilities
Linux capabilities allow fine-grained control over privileges:
docker run -d \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
my-web-server
Common capabilities:
NET_BIND_SERVICE
: Bind to ports < 1024CHOWN
: Change file ownershipDAC_OVERRIDE
: Bypass file permission checksSETUID/SETGID
: Change user/group IDs
5. Use Security Scanning
Scan images for vulnerabilities:
# Using Docker Scout (built-in)
docker scout cves my-app:latest
# Using Trivy
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image my-app:latest
# Using Clair
docker run -d --name clair-db postgres
docker run -d --name clair --link clair-db:postgres \
quay.io/coreos/clair:latest
6. Enable Docker Content Trust
Verify image signatures before pulling:
# Enable content trust
export DOCKER_CONTENT_TRUST=1
# Now only signed images can be pulled
docker pull alpine:latest
# Will fail if not signed
# Sign and push your own images
docker trust sign myregistry.com/my-app:v1.0
docker push myregistry.com/my-app:v1.0
7. Use Secrets Management
Never hardcode secrets in images!
Bad:
ENV DATABASE_PASSWORD=supersecret123
Good - Docker Secrets (Swarm):
# Create secret
echo "supersecret123" | docker secret create db_password -
# Use in service
docker service create \
--name my-app \
--secret db_password \
my-app:latest
Good - Environment Files:
# .env file (add to .gitignore!)
DATABASE_PASSWORD=supersecret123
# Use with docker run
docker run --env-file .env my-app
# Use with docker-compose
docker-compose --env-file .env up
8. Network Segmentation
Isolate containers with custom networks:
# Create isolated networks
docker network create frontend
docker network create backend
# Frontend can't access backend directly
docker run -d --name web --network frontend nginx
docker run -d --name api --network backend my-api
docker run -d --name db --network backend postgres
# API connects both (acts as gateway)
docker network connect frontend api
9. Enable AppArmor/SELinux
AppArmor (Ubuntu/Debian):
# Check if enabled
sudo aa-status
# Run container with profile
docker run --security-opt apparmor=docker-default my-app
SELinux (RHEL/CentOS):
# Check if enabled
getenforce
# Run container with SELinux
docker run --security-opt label=type:container_runtime_t my-app
10. Regular Updates
# Update base images regularly
docker pull ubuntu:20.04
docker build --no-cache -t my-app .
# Remove old images
docker image prune -a
# Update Docker itself
sudo apt-get update && sudo apt-get upgrade docker-ce
Part 4: Docker Daemon Security Configuration
Secure daemon.json Configuration
{
"icc": false,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"seccomp-profile": "/etc/docker/seccomp-profile.json",
"userns-remap": "default"
}
Key settings:
icc: false
: Disable inter-container communication by defaultlog-opts
: Prevent log files from filling disklive-restore
: Keep containers running during daemon downtimeno-new-privileges
: Prevent privilege escalationuserns-remap
: Use user namespaces for isolation
Enable TLS for Docker Daemon
Secure the Docker daemon socket:
# Generate certificates
openssl genrsa -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# Configure daemon
sudo nano /etc/docker/daemon.json
{
"tls": true,
"tlscacert": "/etc/docker/ca.pem",
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem",
"tlsverify": true
}
Part 5: Monitoring and Auditing
Enable Audit Logging
# Install auditd
sudo apt-get install auditd
# Add Docker rules
sudo nano /etc/audit/rules.d/docker.rules
-w /usr/bin/docker -k docker
-w /var/lib/docker -k docker
-w /etc/docker -k docker
-w /usr/lib/systemd/system/docker.service -k docker
-w /etc/systemd/system/docker.service -k docker
sudo systemctl restart auditd
Monitor Container Activity
# Real-time stats
docker stats
# Inspect container processes
docker top my-container
# View container events
docker events --filter 'type=container'
# Export logs
docker logs my-container > container.log
Conclusion
Proper Docker configuration and security are critical for production deployments. This guide covered:
- Proxy configuration for corporate networks
- Insecure registry setup (with warnings)
- Comprehensive security best practices
- Resource limits and capability management
- Secrets management
- Network segmentation
- Daemon security configuration
- Monitoring and auditing
Key Security Takeaways:
- Always run containers as non-root users
- Use read-only filesystems where possible
- Limit resources to prevent DoS
- Drop unnecessary capabilities
- Scan images for vulnerabilities
- Never hardcode secrets
- Segment networks appropriately
- Keep Docker and images updated
- Enable audit logging
- Use TLS for daemon communication
By following these practices, you’ll create a secure, production-ready Docker environment that protects your applications and infrastructure.