Published on

Building a Raspberry Pi Nginx Image with Caching on Alpine for Docker Swarm


In this guide, we will be creating a nginx reverse proxy with the ability to cache static content using a alpine image.

We will then push the image to gitlab's private registry, and then run the service on docker swarm.

Create the backend service:

We will upstream to our blog using ghost, which you can deploy using:

$ docker service create --name blog --network docknet rbekker87/armhf-ghost:2.0.3

Current File Structure:

Our file structure for the assets we need to build the reverse proxy:

$ find .
  • Dockerfile
FROM hypriot/rpi-alpine-scratch

RUN apk update && \
    apk add nginx && \
    rm -rf /etc/nginx/nginx.conf && \
    chown -R nginx:nginx /var/lib/nginx && \
    rm -rf /var/cache/apk/*

ADD nginx.conf /etc/nginx/
ADD conf.d/blog.conf /etc/nginx/conf.d/


CMD ["nginx", "-g", "daemon off;"]
  • nginx.conf
user nginx;
worker_processes 1;

events {
    worker_connections 1024;

error_log  /var/log/nginx/nginx_error.log warn;

http {

    sendfile	      on;
    tcp_nodelay	      on;

    gzip              on;
    gzip_http_version 1.0;
    gzip_proxied      any;
    gzip_min_length   500;
    gzip_disable      "MSIE [1-6]\.";
    gzip_types        text/plain text/xml text/css

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    error_log   /var/log/nginx/error.log;

    proxy_cache_path /var/cache/nginx/ levels=1:2 keys_zone=nginx_cache:5m max_size=128m inactive=60m;

    keepalive_timeout  60;
    server_tokens      off;

    include /etc/nginx/conf.d/*.conf;


Hostname resolution to our Ghost Blog Service: In our swarm we have a service called blog which is associated to the docknet network, so the dns resolution will resolve to the vip of the service. As seen in the figure below:

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                                    PORTS
nq42a6jfwx3d        blog                replicated          1/1                 rbekker87/armhf-ghost:2.0.3
  • conf.d/blog.conf
upstream ghost_blog {
    server blog:2368;

server {
    listen 80;

    access_log  /var/log/nginx/blog_access.log  main;
    error_log   /var/log/nginx/blog_error.log;

    location / {

        proxy_cache                 nginx_cache;
        add_header                  X-Proxy-Cache $upstream_cache_status;
        proxy_ignore_headers        Cache-Control;
        proxy_cache_valid any       10m;
        proxy_cache_use_stale       error timeout http_500 http_502 http_503 http_504;

        proxy_pass                  http://ghost_blog;
        proxy_redirect              off;

        proxy_set_header            Host $host;
        proxy_set_header            X-Real-IP $remote_addr;
        proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header            X-Forwarded-Host $server_name;

Building the Image and Pushing to Gitlab

I'm using Gitlab in this demonstration, but you can use the registry of your choice:

$ docker login
$ docker build -t .
$ docker tag
$ docker push


Create the Nginx Reverse Proxy Service on Docker Swarm:

$ docker service create --name nginx_proxy \
--network docknet \
--publish 80:80 \
--replicas 1 \

Listing our Services:

$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                                                    PORTS
je7x21l7egoh        nginx_proxy         replicated          1/1          *:80->80/tcp
nq42a6jfwx3d        blog                replicated          1/1                 rbekker87/armhf-ghost:2.0.3

Once you access your proxy on port 80, you should see your Ghost Blog Homepage like below:

Have a look at the benchmark performance when using Nginx with caching enabled


Thank You

Thanks for reading, if you like my content, feel free to check out my website, and subscrube to my newsletter or follow me at @ruanbekker on Twitter.

Buy Me A Coffee