The Rock Garden Grows: Hardening Old Docker Images

A hard transformation has arrived for several classic Ubuntu images on ECR and Docker Hub. The remaining old Docker images –Apache2, Nginx, Bind9, Memcached, and Squid– have been hardened to rocks, signaling a complete evolution of the Ubuntu namespace.

Built on top of Resolute and equipped with Pebble as the service manager, these new rocks are now maintained by the Rockcrafters team and follow the same principles that have guided the broader Rocks initiative: user-focused experience, uniform and opinionated design, and a distroless-like architecture.

By meticulously chiseling each rock down to its bare essentials, we have achieved a significant reduction in image sizes:

A Resolute docker image has been built using traditional techniques to establish a baseline for security analysis. This allowed for a direct comparison against the new rocks using Snyk vulnerability scan to assess the security impact of these updates. The chart below shows the number of CVEs found by Snyk for each image:

Since Pebble now handles service management, it provides several new commands for monitoring services. These allow you to inspect logs for a specific Pebble-managed service, assess container health, or validate configured health checks.

To inspect the logs, run the pebble logs command, as follows:

$ docker exec squid-container pebble logs
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| With 1024 file descriptors available
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| Initializing IP Cache...
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| DNS IPv6 socket created at [::], FD 8
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| DNS IPv4 socket created at 0.0.0.0, FD 9
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| Adding nameserver 10.255.255.254 from /etc/resolv.conf
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| Adding domain home from /etc/resolv.conf
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| Logfile: opening log daemon:/var/log/squid/access.log
2026-06-22T16:27:21.448Z [squid] 2026/06/22 16:27:19| Logfile Daemon: opening log /var/log/squid/access.log
...

To assess the health status, run pebble health:

$ docker exec nginx-container pebble health
healthy

To validate configured checks, run pebble checks:

$ docker exec bind9-container pebble checks
Check  Level Startup  Status  Successes  Failures Change
config   -   enabled    up        1         0/3      1

Now let’s take a deeper look at what has changed for each one of the new rocks!


Apache2

Repository: canonical/apache2-rock

Pull from: Dockerhub, Amazon ECR.

Contents

Apache2 has undergone one of the most dramatic reductions in size among this batch of rocks. It includes the following Chisel slices:

Slice Description
base-files_base Creates an Ubuntu-like file system.
base-files_chisel Adds the Chisel manifest.
base-files_release-info Adds the release information files, like /etc/os-release.
base-passwd_data Adds /etc/passwd and /etc/group.
apache2_core Core functionality of the apache2 package.
apache2_index Adds /var/www/html/index.html.
tzdata_zoneinfo Adds timezone data.

By installing the apache2_core slice, this rock includes the primary binary at /usr/sbin/apache2 alongside critical modules, configurations, and dependencies.

While the standard slice typically bundles extra data like icons and the apachectl script, these have been excluded to eliminate unnecessary bloat. Instead, a bespoke control script is provided for streamlined server management.

Additionally, to maintain parity with previous image behavior, the apache2_index slice is also included, providing /var/www/html/index.html.

Usage

The result is a significantly smaller rock that still provides the same Apache2 experience without carrying around over 120 MB of unnecessary baggage. It can be run with docker as follows:

$ docker run -d --rm --name apache2-rock -p 8080:80 ubuntu/apache2:2.4-26.04_edge
$ curl -sSI http://127.0.0.1:8080

HTTP/1.1 200 OK
...

Nginx

Repository: canonical/nginx-rock

Pull from: Dockerhub, Amazon ECR.

Contents

Nginx followed a similar path and emerged even leaner. It includes the following slices:

Slice Description
base-files_base Creates an Ubuntu-like file system.
base-files_chisel Adds the Chisel manifest.
base-files_release-info Adds the release information files, like /etc/os-release.
base-passwd_data Adds /etc/passwd and /etc/group.
nginx_bins Includes the main nginx binary and its dependencies.
nginx-common_index Adds /var/www/html/index.nginx-debian.html
ca-certificates_data-with-certs Adds ca-certificates data required for SSL.
ca-certificates_scripts Adds script to update ca-certificates data.

The core of the Nginx rock is built around the nginx_bins slice, which provides the main executable and every necessary shared library required for operation. To ensure consistency and stability across the ecosystem, these slices were carefully forward-ported from the 25.10 base.

Recognizing the critical importance of secure communications, the rock incorporates dedicated ca-certificate slices to fully support SSL/TLS requirements. This inclusion ensures that the new rock not only maintains strict functional parity with previous Nginx images but also remains lightweight and highly secure.

Usage

The resulting rock contains little more than what is needed to start and run Nginx, delivering a substantial reduction in size while preserving expected functionality. It can be used as follows:

$ docker run -d --rm --name nginx-rock -p 8080:80 ubuntu/nginx:1.28-26.04_edge

Similarly to Apache2, a request can be made to Nginx with curl:

$ curl -sSI http://127.0.0.1:8080

HTTP/1.1 200 OK
...

Bind9

Repository: canonical/bind9-rock

Pull from: Dockerhub, Amazon ECR.

Contents

Bind9 presents an interesting case because it is more than just a daemon. It includes these slices:

Slice Description
base-files_base Creates an Ubuntu-like file system.
base-files_chisel Adds the Chisel manifest.
base-files_release-info Adds the release information files, like /etc/os-release.
base-passwd_data Adds /etc/passwd and /etc/group.
bind9_core Core functionality of the bind9 package.
tzdata_zoneinfo Adds timezone data.

While the primary purpose of the image is to run the named DNS server, many users also rely on the accompanying administrative tools. The challenge was therefore not only to reduce the image size but also to preserve the operational workflows people expect.

The new rock includes the named binary together with its essential runtime dependencies, added by the bind9_core slice. This slice also contains several utilities from bind9-utils that were already available in the previous images, including:

  • named-checkzone

  • named-compilezone

  • named-checkconf

The latter is now used as a Pebble health check, helping verify that the server configuration remains valid, as shown by the pebble plan command:

$ docker exec bind9-rock pebble plan

services:
    dns-server:
        startup: enabled
        override: replace
        command: /usr/sbin/named [ -g ]
checks:
    config:
        override: replace
        threshold: 3
        exec:
            command: /usr/bin/named-checkconf
            service-context: dns-server

Besides, in order to support day-to-day DNS administration, the rndc utility is also included in the rock. It is installed by the bind9-utils_rndc slice, which is a dependency of the core slice. As such, rndc commands can be executed through docker exec, providing a familiar management experience for existing users.

Usage

The Bind9 rock now runs rootless, and even after keeping the operational tools, the image size dropped from 131 MB to 37.3 MB uncompressed. It can be used as follows:

$ docker run --rm -d --name bind9-rock ubuntu/bind9:9.20-26.04_edge

The DNS server can be managed using the rndc tool, though it requires initializing the rndc-confgen script beforehand:

$ docker exec bind9-rock rndc-confgen -a
$ docker restart bind9-rock
$ docker exec bind9-rock rndc status

version: BIND 9.20.18-1ubuntu2.1-Ubuntu (Stable Release) <id:>
running on localhost: ...
boot time: Sun, 21 Jun 2026 23:10:23 GMT
last configured: Sun, 21 Jun 2026 23:10:23 GMT
configuration file: /etc/bind/named.conf
CPUs found: 12
worker threads: 12
number of zones: 101 (100 automatic)
debug level: 0
xfers running: 0
xfers deferred: 0
xfers first refresh: 0
soa queries in progress: 0

Memcached

Repository: canonical/memcached-rock

Pull from: Dockerhub, Amazon ECR.

Contents

Memcached received the same treatment as several of the newer rocks in the ecosystem: fewer layers, fewer dependencies, and fewer privileges. It contains the following slices:

Slice Description
base-files_base Creates an Ubuntu-like file system.
base-files_chisel Adds the Chisel manifest.
base-files_release-info Adds the release information files, like /etc/os-release.
base-passwd_data Adds /etc/passwd and /etc/group.
libsasl2-modules_libs Modules required by memcached.
memcached_bins Core functionality of the Memcached package.
tzdata_zoneinfo Adds timezone data.

The memcached_bins slice provides the core memcached binary, necessary libraries, and configuration files. To support specific use cases, the libsasl2-modules_libs slice is also included; it contains a set of modules that extend the libsasl2-2 library. Although these modules are not explicitly defined as dependencies for Memcached, they are required for various advanced functional scenarios.

Usage

For a service that exists to help everything else run faster, it seems only fair that the image itself got a little lighter too. It can be used as follows:

$ docker run --rm -d --name memcached-rock -p 11211:11211 ubuntu/memcached:1.6-26.04_edge 

Then once the Memcached server is up, it can store and retrieve data:

$ printf "set my_key 0 60 11\r\nhello world\r\n" | nc -q 1 127.0.0.1 11211
$ printf "get my_key\r\n" | nc -q 1 127.0.0.1 11211 | grep "hello world"

hello world

Squid

Repository: canonical/squid-rock

Pull from: Dockerhub, Amazon ECR.

Contents

As one of the most widely used images under the Ubuntu namespace, compatibility and functionality were key concerns throughout the process. Unlike some services that can be reduced almost entirely to a single daemon and a handful of dependencies, Squid often relies on a broader collection of modules and supporting components.

For that reason, most of Squid’s tentacles were preserved:

Slice Description
base-files_base Creates an Ubuntu-like file system.
base-files_chisel Adds the Chisel manifest.
base-files_release-info Adds the release information files, like /etc/os-release.
base-passwd_data Adds /etc/passwd and /etc/group.
squid_standard Standard installation of squid: core functionality plus authentication, cache, external acls and certs capabilities.
tzdata_zoneinfo Adds timezone data.
libc-bin_nsswitch Name service switch. Adds /etc/nsswitch.conf.
libpam-modules_libs Provides PAM authentication capabilities.

The objective was to remain close to a standard Squid deployment while still applying the principles of chiseling and minimization wherever possible. Each included component was evaluated against a simple rule: if a capability is present, the dependencies required to make it functional should be present too–but nothing more.

Usage

Despite retaining a substantial set of features, the rock is still both baseless and rootless, and its uncompressed size has been reduced from 205 MB to 127 MB. It can be used as follows:

$ docker run --rm -d --name squid-rock -p 3128:3128 ubuntu/squid:7.2-26.04_edge

Using curl, an HTTP request can then be routed through the proxy:

$ curl -4 -sI -x http://127.0.0.1:3128 https://ubuntu.com | grep "HTTP/1.1 200"

HTTP/1.1 200 Connection established

Then you can check that the request was actually routed by the Squid proxy:

$ docker exec squid cat /var/log/squid/access.log | grep -qF "CONNECT ubuntu.com:443"

1782085805.059  15133 172.17.0.1 TCP_TUNNEL/200 7771 CONNECT ubuntu.com:443 - HIER_DIRECT/185.125.190.29 -

Closing Thoughts

These five rocks represent another step toward a broader collection of minimal, secure, and maintainable Ubuntu service images.

Apache2, Nginx, Bind9, Memcached and Squid all emerged from the petrification process smaller than before, with cleaner dependency trees and a reduced runtime footprint. Several now run rootless, with their services being now managed by Pebble, and each has been carefully chiseled to include only the pieces required for its intended purpose.

The rock garden keeps growing! :deciduous_tree: :rock:

7 Likes