SQLite is embedded in the application process, so there is no dedicated SQLite server container to run. Updated for current Docker best practices with SQLite 3.51.2+.
Most common pattern: install SQLite in your application container and mount a volume for persistence.
FROM python:3.12-alpine
# Install SQLite
RUN apk add --no-cache sqlite sqlite-dev
# Copy application code
COPY . /app
WORKDIR /app
# Install Python dependencies
RUN pip install -r requirements.txt
# Create database directory
RUN mkdir -p /data
RUN chown -R appuser:appuser /data /app
USER appuser
CMD ["python", "app.py"]
# Mount a named volume
docker run -v sqlite-data:/data myapp:latest
# Mount a host directory
docker run -v /host/path/to/data:/data myapp:latest
# Mount with specific permissions
docker run -v /host/path/to/data:/data:Z myapp:latest # SELinux context
version: '3.8'
services:
myapp:
build: .
image: myapp:latest
volumes:
- sqlite-data:/data
# Or use bind mount:
# - ./data:/data:rw
environment:
- DATABASE_URL=/data/app.db
ports:
- "8000:8000"
depends_on:
- redis # if using Redis for caching/sessions
restart: unless-stopped
volumes:
sqlite-data:
driver: local
version: '3.8'
services:
myapp:
build:
context: .
dockerfile: Dockerfile.prod
image: myapp:3.51.2
volumes:
- sqlite-data:/data:rw
- ./logs:/app/logs:rw
environment:
- DATABASE_URL=/data/app.db
- LOG_LEVEL=INFO
- SQLITE_JOURNAL_MODE=WAL
- SQLITE_SYNCHRONOUS=NORMAL
ports:
- "80:8000"
healthcheck:
test: ["CMD", "sqlite3", "/data/app.db", "SELECT 1;"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /run
volumes:
sqlite-data:
driver: local
driver_opts:
type: none
o: bind
device: /opt/volumes/myapp-sqlite
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Production stage
FROM node:20-alpine
# Install SQLite and other system dependencies
RUN apk add --no-cache \
sqlite \
su-exec \
dumb-init
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
WORKDIR /app
# Copy application files from builder
COPY --from=builder /app/node_modules ./node_modules
COPY . .
# Create data directory
RUN mkdir -p /data && \
chown -R nextjs:nodejs /app /data
USER nextjs
# Use dumb-init to handle signals properly
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "server.js"]
# Run as non-root user
docker run --user 1001:1001 -v sqlite-data:/data myapp:latest
# Use read-only root filesystem where possible
docker run --read-only --tmpfs /tmp -v sqlite-data:/data myapp:latest
# Set security options
docker run --security-opt=no-new-privileges:true myapp:latest
# Backup from running container
docker exec myapp-container sqlite3 /data/app.db ".backup '/backups/app-$(date +%F).db'"
# Or copy file out of volume
docker run --rm -v sqlite-data:/data -v backup-volume:/backups \
alpine sh -c "cp /data/app.db /backups/app-\$(date +%F).db"
services:
backup:
image: alpine:latest
volumes:
- sqlite-data:/data:ro
- backup-data:/backups
command: >
sh -c "apk add --no-cache sqlite curl &&
while :; do
sqlite3 /data/app.db '.backup \"/backups/app-$$(date +%Y%m%d_%H%M%S).db\"' &&
sleep 86400; # Every 24 hours
done"
restart: unless-stopped
docker run --rm alpine:latest sh -c "apk add --no-cache sqlite && sqlite3 --version"
docker exec myapp-container sqlite3 /data/app.db "PRAGMA journal_mode;"
docker exec myapp-container ls -la /data/