Back to articles
Technology Insight

Maximizing Low-Spec VPS Performance: How to Drastically Reduce Docker Image Sizes Below 10MB Using Multi-Stage Builds

May 30, 2026

Introduction: The Low-Spec VPS Dilemma

Operating on a low-specification Virtual Private Server (VPS)—such as an entry-level instance with 1 vCPU and 1GB (or even 512MB) of RAM—presents a unique set of constraints for modern DevOps and software engineering. While containerization via Docker offers unparalleled portability, it also introduces a hidden tax: disk space and memory overhead. Standard Docker images frequently balloon to hundreds of megabytes, quickly exhausting the limited solid-state drive (SSD) storage and caching capabilities of budget infrastructure.

When a single application image demands 800MB of storage, deploying multiple microservices or maintaining a local container registry on a low-spec VPS becomes mathematically unfeasible. Furthermore, larger images result in slower deployment times, higher network bandwidth usage during pull operations, and a broader attack surface for potential security vulnerabilities. To extract maximum performance from constrained hardware, engineers must adopt a minimalist approach to containerization. The definitive solution to this challenge lies in mastering Docker Multi-Stage Builds, a powerful technique capable of compressing production-grade deployment images to under 10MB.

The Anatomy of Container Bloat

To effectively shrink Docker images, we must first diagnose why they become bloated in the first place. A typical standard Dockerfile utilizes a heavy base image, such as full distributions of Ubuntu, Debian, or official language runtimes (e.g., node:latest or golang:latest). These base images include components that are absolutely vital during the development phase but completely redundant during runtime execution:

  • Compilers and Build Tools: GCC, G++, Make, and language-specific SDKs.
  • Package Managers: APT, YUM, or APK along with their localized metadata caches.
  • Debugging Utilities: curl, wget, vim, and comprehensive manual pages.
  • Source Code Files: Raw uncompiled code, build configurations, and local testing frameworks.

In a traditional single-stage Docker build, every command executed via a RUN instruction adds a permanent new layer to the image. Even if you attempt to delete build dependencies or clean up package caches in a subsequent instruction, the underlying data remains embedded within the historical layers of the container, contributing directly to the final image size.

Enter Multi-Stage Builds: Philosophy and Mechanics

Introduced in Docker 17.05, Multi-Stage Builds radically transform the containerization workflow by allowing developers to use multiple FROM statements within a single Dockerfile. Each FROM instruction initiates a brand-new, isolated stage of the build process using a completely different base image.

The foundational philosophy of Multi-Stage Builds is simple: Separate your build environment from your runtime environment.

By leveraging this architectural pattern, you can utilize a heavy, feature-rich base image loaded with compilers, linters, and dependencies to compile your application code in the first stage (the Build Stage). Once the compilation yields a static binary or optimized asset bundle, you spin up a secondary, ultra-lightweight base image in the second stage (the Runtime Stage). You then explicitly copy only the compiled artifact from the first stage into the second. All compilers, source files, caches, and intermediate layers from the build stage are discarded entirely, leaving behind a pristine, minimal production image.

Step-by-Step Guide: Compressing an Application Image Under 10MB

Let us look at a practical demonstration using a high-performance compiled language, such as Go or Rust, which is ideal for low-spec VPS environments due to its efficiency. We will write a highly optimized Dockerfile designed to break the sub-10MB barrier seamlessly.

1. The Sub-Optimal Single-Stage Approach (The Anti-Pattern)

Consider a standard, single-stage Dockerfile used by many developers:

FROM golang:1.21
WORKDIR /app
COPY . .
RUN go build -o main .
CMD ["./main"]

Executing this build yields a final image size typically ranging between 800MB and 1GB. This massive footprint is unacceptable for a VPS with limited resources.

2. The Optimized Multi-Stage Solution

By applying multi-stage building techniques combined with an ultra-minimal runtime base image like Alpine Linux or Scratch, we can plummet the final size down to roughly 6MB to 8MB. Here is the highly optimized implementation:

# Stage 1: The Build Environment
FROM golang:1.21-alpine AS builder
WORKDIR /build

# Install essential build dependencies if necessary
RUN apk add --no-cache git

# Copy source code and download dependencies
COPY go.mod go.sum ./
RUN go mod download
COPY . .

# Compile the binary with optimization flags
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o myapp .

# Stage 2: The Ultra-Minimal Runtime
FROM scratch

# Copy essential system files from builder if TLS/HTTPS communication is required
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# Copy the highly optimized statically compiled binary
COPY --from=builder /build/myapp /myapp

# Configure container execution
USER 1000:1000
EXPOSE 8080
ENTRYPOINT ["/myapp"]

Deep Dive into the Optimization Techniques

Achieving a deployment image under 10MB requires understanding the granular configurations utilized in the optimized Dockerfile above:

The Role of the 'Scratch' Base Image

The FROM scratch instruction indicates that the runtime stage starts with an empty filesystem. scratch is an explicit no-op image that contains zero files, zero shell environments, and zero libraries. It adds 0 bytes to your final container footprint. By injecting only our compiled binary into scratch, we eliminate all operating system overhead.

Compiler Flags For Maximum Shrinkage

During the compilation step in the builder stage, the command go build -ldflags="-s -w" plays a crucial role:

  • -s: Omit the symbol table and debug information from the binary.
  • -w: Omit the DWARF generation debugging symbols.

Stripping these debugging symbols drastically minimizes the executable size of the binary itself (often reducing it by 30% to 50%), which directly facilitates keeping the total image size below the 10MB target threshold.

Static Linking via CGO_ENABLED=0

Setting CGO_ENABLED=0 forces the compiler to build a statically linked binary. By default, applications often rely on dynamic libraries provided by the host operating system (such as glibc). Because our final scratch runtime contains no operating system libraries, a dynamically linked binary would fail to execute with a cryptic "file not found" error. Static linking ensures all required library code is baked right into the self-contained binary file.

The Cascade of Benefits for Low-Spec VPS Deployments

Implementing Multi-Stage builds yields substantial technical advantages that extend far beyond simply saving disk space on your server:

Metric / AttributeStandard Image BuildMulti-Stage (Scratch/Alpine)Impact on Low-Spec VPS
Average Image Size850 MB< 10 MBSaves up to 98% disk space; allows high-density hosting.
RAM UtilizationHigher (due to OS background layers)Minimal (only executes application memory)Prevents OOM (Out Of Memory) crashes on 512MB RAM servers.
Network BandwidthHeavy continuous consumption during updatesNegligible throughput neededDrastically accelerates deployment speed over slow server networks.
Security Attack SurfaceHigh (Vulnerable to package exploits)Virtually ZeroNo package manager or shell means hackers cannot run malicious scripts.

Conclusion: Engineering Elegance over Hardware Upgrades

When operating on constrained infrastructure, throwing expensive hardware at optimization problems is an inefficient crutch. By integrating Docker Multi-Stage Builds into your engineering workflow, you transform your deployment strategy. Compressing your images to under 10MB allows a modest, low-spec VPS to run with the agility, speed, and safety of premium enterprise configurations.

Embrace the discipline of minimalist containerization: compile aggressively in your build stages, strip your runtime down to its absolute essentials, and run your applications within highly secure, highly optimized environments that treat hardware resources with the respect they deserve.

Maximizing Low-Spec VPS Performance: How to Drastically Reduce Docker Image Sizes Below 10MB Using Multi-Stage Builds | DPTCloud