Use Traefik 2 with Nginx, Apache, or CaddyServer to Serve Static Files
Tags: code, nginx, traefik, caddyserver
Published: 2020-03-12 12:42:57

---
title: Use Traefik 2 with Nginx, Apache, or CaddyServer to Serve Static Files
published: true
date: 2020-02-24 06:09:00 UTC
tags: Code,nginx,traefik,caddyserver
canonical_url: https://www.simplecto.com/use-traefik-with-nginx-apache-caddyserver-serve-static-files/
---

Setup a simple HTTP static file server behind Traefik. My specific use case is to serve static files (eg - PDF, excel, etc) from my blog that runs [Ghost](https://ghost.org). However, the software itself does not support that. There are a number of HTTP servers, but we will choose three of the most popular ones.

- [Nginx](https://www.nginx.com/)
- [CaddyServer](https://www.caddyserver.com)
- [Apache HTTPD](https://httpd.apache.org/)

These work well because they provide a nice drop-in to solve static file serving because it is small, fast, and will work well in a default configuration.

Now we will explore two ways to serve up files.

1. Hosting on a subdomain (eg - `files.example.com`)
2. Hosting on the blog's domain but in a subfolder (eg - `example.com/static`)

Use `docker-compose` and docker labels to configure Traefik's routing and middlewares.

In both scenarios:

- Use the images from Docker Hub.
- Bind-mount a local folder to host the files for the web server. See `volumes:` in the docker-compose.

## On its own domain

You must have the DNS entry, `files.example.com` in this case, to point at the server. An example file download URL would be:

- https://files.example.com/sales-pitch.pdf

### All-in-one config (docker-compose)

This is a `docker-compose.yml` with configurations for all three servers. Simply comment out the ones you don't want and un-comment the ones you do. Bobs- your uncle.

<!--kg-card-begin: markdown-->
```
    static:

        # nginx config
        image: nginx
        volumes:
            - ./files:/usr/share/nginx/html:ro

# uncomment to use Aapche HTTPD Server
# image: httpd:2.4-alpine
# volumes:
# - ./files:/usr/local/apache2/htdocs:ro

# Uncomment to use Caddeserver
# image: caddy/caddy:scratch
# command: file-server --root /files --listen 0.0.0.0:80
# volumes:
# - ./files:/files:ro

        container_name: static-files
        restart: unless-stopped
        networks:
            - traefik
        labels:
            # Match on the hostname and the path
            - traefik.http.routers.nginx.rule=Host(`files.example.com`)
            - traefik.http.routers.nginx.tls=true
            - traefik.http.routers.nginx.tls.certresolver=le
            - traefik.http.services.nginx.loadbalancer.server.port=80

            # tell Traefik which middlewares we want to use on this container
            - traefik.http.routers.nginx.middlewares=gzip

```
<!--kg-card-end: markdown-->
## On a specific URI path (/static) in an existing domain

It is only a matter of three lines that will enable this to live under `/static` Path. An example file download URL would be:

- https://blog.example.com/static/sales-pitch.pdf
<!--kg-card-begin: markdown-->

**Just the parts you need**

```
# Match on the hostname and the path
- traefik.http.routers.nginx.rule=(Host(`blog.example.com`) && Path(`/static`))

# Define a new middleware to strip the URL prefix before sending it to nginx
- traefik.http.middlewares.nginx-stripprefix.stripprefix.prefixes=/static

# tell Traefik which middlewares we want to use on this container
- traefik.http.routers.nginx.middlewares=gzip@docker,nginx-stripprefix@docker

```
<!--kg-card-end: markdown--><!--kg-card-begin: markdown-->

**Full docker-compose.yml**

```
    static:

        # nginx config
        image: nginx
        volumes:
            - ./files:/usr/share/nginx/html:ro

# uncomment to use Aapche HTTPD Server
# image: httpd:2.4-alpine
# volumes:
# - ./files:/usr/local/apache2/htdocs:ro

# Uncomment to use Caddeserver
# image: caddy/caddy:scratch
# command: file-server --root /files --listen 0.0.0.0:80
# volumes:
# - ./files:/files:ro

        container_name: static-files
        restart: unless-stopped
        networks:
            - traefik
        labels:
            # Match on the hostname and the path
            - traefik.http.routers.static-files.rule=(Host(`blog.example.com`) && Path(`/static`))
            - traefik.http.routers.static-files.tls=true
            - traefik.http.routers.static-files.tls.certresolver=le
            - traefik.http.services.static-files.loadbalancer.server.port=80

            # Define a new middleware to strip the URL prefix before sending it to static-files
            - traefik.http.middlewares.static-files-stripprefix.stripprefix.prefixes=/static

            # tell Traefik which middlewares we want to use on this container
            - traefik.http.routers.static-files.middlewares=gzip@docker,static-files-stripprefix@docker

```
<!--kg-card-end: markdown-->
### Things to note

- The CaddyServer config needed a `command:` attribute added to tell it to activate its fileserver feature.
- The mountpoints for `volumes:` is different per server
- Only official images are used. Your milage may vary if you stray from these...

### Other guides

- I previously made a guide on hosting your files using a nice Golang service called filebrowser. [Read more about Ghost and Filebrowse here](https://dev.to/simplecto/ghost-file-downloads-with-traefik-docker-and-filebrowser-11pm).

### Conclusion

Using the above snippets you should be able to add Nginx, Apache HTTPD, or CaddyServer to your docker / Traefik deployments and have simple, no fuss static file serving.

I should also mention that is snipped is part of my production stack template that use for most Simple CTO projects. More on that later