Deploy Any SSL Secured Website With Docker And Traefik
Tags: programming, docker, webdev, tutorial
Published: 2022-09-02 21:45:46

[Paul Knulst](https://www.paulsblog.dev)  in  [Docker](https://www.paulsblog.dev/tag/docker/) • 8 min read

* * *

What is Docker?
---------------

Docker is a platform that is used for developing, shipping, and running all kinds of applications. It enables the separation of applications from the infrastructure so that software can be delivered without concerns about the operating system of the host or the end-user.

To install Docker on your machine download the installation package from the official docker page here: [https://docs.docker.com/get-docker/](https://docs.docker.com/get-docker/)

To work with Docker you should get familiar with the following keywords/concepts: **Container, Dockerfiles, Docker-Images, Docker-Compose**

### Container

A container describes a unit of software that merges code and every dependency to run an application. They provide a quick and safe way to run an application on several different devices. Also, it secures the application because of different isolation capabilities.

### Docker Images

A Docker image is a read-only template that is used for creating the container to run the application within the Docker platform. It packages up applications and preconfigured server environments to create the container which will be deployed. On the officially [DockerHub](https://hub.docker.com/) several already configured images are available to use. You can use the search function to find any image and deploy it on your system with:
```bash
    $ docker run -it "NAME_OF_IMAGE_FROM_DOCKERHUB"
```
### Dockerfiles

A Dockerfile is a plain text document that contains every command to set up an image. It contains the base image to use (operating system) and the additional software that should be installed on the resulting image.

Every time custom content is used for a Docker container a Dockerfile has to be created and filled with the missing information.

As an example, the following two snippets will demonstrate the usage of a Dockerfile. The first one will extend an NGINX image to serve a simple HTML file that is shown in the second snippet.
```docker
    FROM nginx
    COPY index.html /usr/share/nginx/html
```

```html
    <html>
    <h1>How To Deploy Docker</h1>
      <p>Learning IT. Level Up.</p>
      <p>This is a simple static website, built and deliver from a docker container</p>
      <p><a href="https://www.paulsblog.dev/">Check out my blog here</a></p>
    </html>
```

If you place both files within the same folder you can run it with:
```bash
    $ docker build -t nginx-sample .
    $ docker run --name test-nginx -d -p 8080:80 nginx-sample
```
Now open your favorite web browser and hit `http://localhost:8080` (or `http://your-ip:8080` if you working on a server)

### Docker Compose

Docker Compose is a tool that was developed to create multi-container applications in an easy way by using a YAML file that could contain several Docker containers.

One big advantage over simple Dockerfiles is that it enables the use of a simple “stack” file for your whole application stack. You can keep one Compose file in your repository and deploy everything with one simple command: `docker-compose up -d`

To install Docker Compose follow the official tutorial: [https://docs.docker.com/compose/install/](https://docs.docker.com/compose/install/)

Afterward, read the [official Docker Compose guide](https://docs.docker.com/get-started/08_using_compose/) to fully understand how a Docker Compose file is created because this will not be part of this article.

What is Traefik?
----------------

> **Traefik Makes Networking Boring**  
> **Cloud-Native Networking Stack That Just Works.**

Traefik is used to forward incoming requests to a service deployed in a Docker environment. Also, it has the ability to create [Let’s Encrypt](https://letsencrypt.org/) SSL certificates automatically for every domain which is managed by __traefik__.

To set up a local Traefik service within your Docker environment you can [download this Docker Compose file](https://gist.github.com/paulknulst/68e5e63badaa6a9ac80b4227ca07baee#file-docker-compose-traefik-yml) and execute the following commands:

1\. Create an external network that is used for Traefik
```bash
    $ docker create network traefik-public
```
2\. Export needed variables
```bash
    $ export PRIMARY_DOMAIN=yourdomain.de
    $ export TRAEFIK_SSLEMAIL=youremai@yourdomain.de
```
3\. Deploy
```bash
    $ docker-compose up -d
```
To access the traefik dashboard you can hit `[https://dashboard.yourdomain.de](https://dashboard.yourdomain.de/)` and login with:
```
    username: devadmin 
    password: devto
```
**To get a deeper understanding of Traefik you can read about [How To Deploy it within this article](https://www.paulsblog.dev/how-to-setup-traefik-with-automatic-letsencrypt-certificate-resolver/)**.

Set Up And Deploy Your Website
------------------------------

### Create A Simple Website

After you learned the basics and set up a Traefik instance you can start creating a Dockerfile and a Compose file to create a Docker Container (service) for your website.

To simplify this procedure I will deploy a [simple dashboard project that I forked from an awesome list on GitHub](https://github.com/paulknulst/personal-dashboard). To get a copy of that dashboard either [download the latest zip file here](https://github.com/paulknulst/personal-dashboard/archive/refs/tags/v1.0.0.zip) or clone the repository:
```bash
    $ git clone git@github.com:paulknulst/personal-dashboard.git
```
__In contrast to the original repository, I have adjusted the index.html and the CSS file to be kind of SEO optimized and have 5 items per row instead of 6.__

* * *

Create a new folder (personal-dashboard) and extract (or move) the project files into a subfolder named `html`. Now, you should open it in your favorite IDE, copy the **config.sample.json** to **config.json** and open it.

Change it to fulfill your needs and provide your own personal links. I will use the following settings:
```json
    {
    	"title" : "Pauls Simple Dashboard",
    	"items" : [
    		{
    			"alt" : "Github",
    			"icon" : "fab fa-github",
    			"link" : "https://github.com/paulknulst"
    		},
    		{
    			"alt" : "Twitter",
    			"icon" : "fab fa-twitter",
    			"link" : "https://twitter.com/paulknulst"
    		},
    		{
    			"alt" : "Portfolio",
    			"icon" : "fab fa-at",
    			"link" : "https://www.paulknulst.de"
    		},
    		{
    			"alt" : "Medium",
    			"icon" : "fab fa-medium",
    			"link" : "https://medium.knulst.de"
    		}
    	]
    }
```

### Create Dockerfile

The Dockerfile will be created in the simple-dashboard folder and only contains the base image and one copy command to add the HTML folder into the container.
```docker
    FROM nginx
    COPY html /usr/share/nginx/html
```

### Create Compose File

The Compose file will be created in the simple-dashboard folder too. It contains every setting to set up your personal dashboard within your Docker environment. Furthermore, it will use Traefik to enable Let’s Encrypt certificate generation.

The complete Docker Compose file which will be explained afterward:
```docker
    version: '3.4'
    
    services:
      web:
        image: personal-dashboard
        build:
          context: ./
          dockerfile: Dockerfile
        networks:
          - traefik-public
        healthcheck:
          test: curl --fail http://localhost || exit 1
          interval: 60s
          retries: 5
          start_period: 20s
          timeout: 10s
        labels:
          - traefik.enable=true
          - traefik.docker.network=traefik-public
          - traefik.constraint-label=traefik-public
          - traefik.http.routers.personal-dashboard-http.rule=Host(`personal-dashboard.${PRIMARY_DOMAIN}`) 
          - traefik.http.routers.personal-dashboard-http.entrypoints=http
          - traefik.http.routers.personal-dashboard-http.middlewares=https-redirect
          - traefik.http.routers.personal-dashboard-https.rule=Host(`personal-dashboard.${PRIMARY_DOMAIN}`) 
          - traefik.http.routers.personal-dashboard-https.entrypoints=https
          - traefik.http.routers.personal-dashboard-https.tls=true
          - traefik.http.routers.personal-dashboard-https.tls.certresolver=le
          - traefik.http.services.personal-dashboard.loadbalancer.server.port=80
          # - traefik.http.routers.personal-dashboard-https.middlewares=security-headers
        restart: unless-stopped
    
    
    networks:
      traefik-public:
        external: true
```

Within this Compose file, you can see that we define an **image** in Line 5 (personal-dashboard:v1). Also, we add a **build** section because the image does not officially exist. Within the build section, we define that the Dockerfile which is located in the same directory should be used for creating the image.

The **networks** part (Line 9–10) contains the external network that was created during Traefik installation. Also, within Line 33–35 we especially define the network as an external network for this Compose service.

Another very important section is **healthcheck** (Line 11–16). For me, this part should be contained in every Docker Compose file because it helps to know if a Docker Container is running correctly without any runtime errors. For further reading have a look at [this article that explains how to implement different types of health checks.](https://www.paulsblog.dev/how-to-successfully-implement-a-healthcheck-in-docker-compose/) that explains how to implement different types of health checks.

The most important part of this Compose file is the **labels** section. This section contains several labels that are important for Traefik. First, we enable Traefik (Line 18) for this service because in our Traefik service there was an option to not be working for every Docker service. Within Line 19 we define which external network is used for traefik.

In Line 20 we set the **constraint-label** of this service. Normally this is an optional setting and only used if we have more than one Traefik instance deployed to our Docker environment.

From Line 21–25 we define the URL of the service for HTTP and for HTTPS. For the HTTP part, we also activate a middleware from the Traefik configuration that will always redirect HTTP requests to HTTPS (Line 23).

The labels in Line 26 and 27 are necessary to create automatic SSL certificates for this Docker service.

Line 28 is needed to “expose” the internal Docker service port to the Traefik instance. All incoming requests to the URL defined in Line 21/24 will be forwarded to the Docker service on the Port mentioned within this label.

Line 29 is commented out because it is an extra middleware that I personally use in my Docker environment. I did not include this middleware within the Traefik installation but if you want to read about it have a look at [my article about hardening any Traefik service](https://www.paulsblog.dev/harden-your-website-with-traefik-and-security-headers/).

* * *

Keep in mind that this file only works correctly if you followed the above steps to set up Traefik. If not you have to adjust `PRIMARY_DOMAIN`, your __Docker external network,__ and the entry points used for Traefik (`http`, `https`).

### Deploy The Website

Now, that you finished creating the needed files you can open your CLI, switch to your project folder and start the deployment process by executing:
```bash
    $ docker-compose up -d --build
```
After the deployment is complete you can open your dashboard in your browser and if you followed this tutorial it should look like this:

![Screenshot of a personal dashboard created within this tutorial](https://www.paulsblog.dev/content/images/2022/09/image.png)

Closing Notes
---------------

I hope you enjoyed reading my tutorial and are now able to deploy your own website within a Docker container and enhance it with Traefik and SSL certificates.

Keep in mind that you can replace the HTML folder with every other static website. Also, you can extend the Compose file with other services like a database for your website. Furthermore, you can exchange the image with another public one from Docker Hub.

To help you, I have written another tutorial on how to deploy a Kimai2 Timetracking website that also includes a Docker Hub image, Traefik settings, a database, and an NGINX.

https://medium.com/geekculture/how-to-setup-kimai2-timetracking-locally-or-on-your-server-with-docker-compose-1287d9bc3722

I would love to hear your feedback about this tutorial. Furthermore, if you already run a traefik installation and use a different approach please comment here and explain what you have done differently. Also, if you have any questions, please jot them down below. I try to answer them if possible.

This blog post was initially published on my own blog: https://www.paulsblog.dev/deploy-any-ssl-secured-website-with-docker-and-traefik/

Feel free to connect with me on [my personal blog](https://www.paulsblog.dev), [Medium](https://medium.knulst.de), [LinkedIn](https://www.linkedin.com/in/paulknulst/), [Twitter](https://twitter.com/paulknulst), and [GitHub](https://github.com/paulknulst).

* * *

Did you find this article valuable? Want to support the author? (... and support development of current and future tutorials!). You can sponsor me on [Buy Me a Coffee](https://buymeacoffee.com/paulknulst) or [Ko-Fi](https://ko-fi.com/paulknulst). Furthermore, you can become a free or paid member by [signing up to this website](https://www.paulsblog.dev/#/portal). See the [contribute page](https://www.paulsblog.dev/contribute/) for all (free or paid) ways to say thank you!

---

Photo by [Arian Darvishi](https://unsplash.com/@arianismmm) / [Unsplash](https://unsplash.com)