Secure your site: Docker and Traefik for SSL domain deployment

traefik-banner

Welcome. This time we’ll be learning how to set up a secure any app, in this case Nextcloud, using Docker Compose and Traefik. Nextcloud is a powerful self-hosted solution for file sync and a collaborative tool, while Traefik serves as a reverse proxy that ensures secure access to your services.

This will be a process of deploying Nextcloud with the help of Docker Compose and configuring Traefik to handle SSL termination and secure connections. By the end of this guide, you’ll have your Nextcloud instance accessible securely over HTTPS with a free domain.

1. Docker install

First we need to install docker, then, follow my post of DuckDNS.

https://blog.matiasmercado.ar/archives/14

Below is the docker-compose.yaml file that defines the Nextcloud, Redis, and MariaDB services:

version: "3.7"

services:

   nextcloud:
     # ... (Nextcloud service configuration)

   redis:
     # ... (Redis service configuration)

   db:
     # ... (MariaDB service configuration)

volumes:
  redis:
    name: nextcloud-redis

networks:
  proxy:
    external: true
  default:
    driver: bridge

2. Nextcloud Configuration

In the nextcloud service section of the docker-compose.yaml file, various environment variables are set to configure Nextcloud’s connection to the database, Redis, and other settings.

nextcloud:
  image: nextcloud:latest
  container_name: nextcloud
  # ... (other configurations)
  environment:
    - REDIS_HOST=redis
    - MYSQL_PASSWORD=password123
    - MYSQL_DATABASE=nextcloud
    - MYSQL_USER=nextcloud
    - MYSQL_HOST=db
    - TRUSTED_PROXIES=traefik
  networks:
    - proxy
    - default
  labels:
    # ... (Traefik labels for Nextcloud)

3. Traefik Configuration

The magic of this setup lies in the Traefik configuration. Traefik acts as a reverse proxy and automatically handles SSL termination, making sure your Nextcloud instance is accessible securely over HTTPS.

nextcloud:
# … (Nextcloud configuration)
labels:
- "traefik.backend=nextcloud"
- "traefik.frontend.rule=Host:nextcloud.example.com" # Replace with your domain
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.nextcloud-secure.entrypoints=websecure"
- "traefik.http.routers.nextcloud-secure.rule=Host(nextcloud.example.com)" # Replace with your domain
- "traefik.http.routers.nextcloud-secure.service=nextcloud-service"
- "traefik.http.services.nextcloud-service.loadbalancer.server.port=80"

4. Launching the Services

Your code should look similar to this:

version: "3.7"

services:

   nextcloud:
     image: nextcloud:latest
     container_name: nextcloud
     restart: always
     depends_on:
      - db
      - redis
     volumes:
      - /home/docker/nextcloud:/var/www/html
     environment:
      - REDIS_HOST=redis
      - MYSQL_PASSWORD=matiasmercado
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_HOST=db
      - TRUSTED_PROXIES=traefik
     networks:
      - proxy
      - default
     labels:
      - "traefik.backend=nextcloud"
      - "traefik.frontend.rule=Host:test.duckdns.org"
      - "traefik.enable=true"
      - "traefik.docker.network=proxy"
      - "traefik.http.routers.nextcloud-secure.entrypoints=websecure"
      - "traefik.http.routers.nextcloud-secure.rule=Host(`test.duckdns.org`)"
      - "traefik.http.routers.nextcloud-secure.service=nextcloud-service"
      - "traefik.http.services.nextcloud-service.loadbalancer.server.port=80"

   redis:
     image: redis:latest
     restart: always
     networks:
      - default
     volumes:
      - /home/docker/redis:/var/lib/redis

   db:
     image: mariadb:latest
     restart: always
     #I had to add this line because it's throws me 
     #an error with the db --skip-innodb-read-only-compressed
     command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --skip-innodb-read-only-compressed
     volumes:
       - /home/docker/db:/var/lib/mysql
     environment:
       - MYSQL_ROOT_PASSWORD=matiasmercado.ar
       - MYSQL_PASSWORD=matiasmercado
       - MYSQL_DATABASE=nextcloud
       - MYSQL_USER=nextcloud

volumes:
  redis:
    name: nextcloud-redis

networks:
  proxy:
    external: true
  default:
    driver: bridge

With your docker-compose.yaml file configured, navigate to the directory containing the file and execute the following command to deploy the app:

$ docker-compose up -d

This command will launch the Nextcloud, Redis, and MariaDB services defined in the docker-compose.yaml file.

5. Accessing Nextcloud Securely

Once the services are up and running, you can access your Nextcloud instance securely by navigating to your domain (e.g., https://nextcloud.duckdns.org). Traefik will automatically handle the SSL certificate, ensuring your connection is encrypted and secure:

After a few tunes, you should be able to get in with your free domain using DuckDNS, or using your public IP/name if you have one.

nextcloud dashboard

Traefik will give you a domain to set configuration in there. Once you’re logged in, you’ll be presented with the Traefik dashboard. This dashboard provides an overview of your routers, services, middlewares, and more. It’s an intuitive interface that helps you manage your reverse proxy setup.

traefik dashboard

In the Traefik dashboard, you’ll find sections related to routers and services. Routers define how incoming requests are matched and directed to the appropriate services. Services define where those requests are sent. For instance, if you have a service that represents your Nextcloud application, a router can be set up to route requests to that service based on certain conditions (like domain names).
You can use the dashboard to create, modify, and delete routers and services. This is where you’ll configure things like domain routing, load balancing, SSL certificates, and more.

traefik routers
traefik http routers

6. Securing the code

Docker Compose supports using environment variables from external files, which is a good practice for keeping sensitive data secure. Below, an example of how you can secure your Docker Compose file by using environment variables stored in an external .env file. This will help you avoid exposing sensitive information directly in the docker-compose.yaml file.

Create an .env file

Create a file named .env in the same directory as your docker-compose.yaml file. In this file, you can define your sensitive environment variables without exposing them directly in the Docker Compose file. For example:

# .env

# Nextcloud
MYSQL_PASSWORD=password123
MYSQL_ROOT_PASSWORD=nextcloudpass123

# Redis
REDIS_PASSWORD=redispassword

# Nextcloud Admin User
NEXTCLOUD_ADMIN_USER=admin
NEXTCLOUD_ADMIN_PASSWORD=adminpassword

Update Docker Compose

Modify your docker-compose.yaml file to use the environment variables defined in the .env file. Here’s how your docker-compose.yaml might look:

version: "3.7"

services:

   nextcloud:
     image: nextcloud:latest
     container_name: nextcloud
     restart: always
     depends_on:
      - db
      - redis
     volumes:
      - /home/docker/nextcloud:/var/www/html
     environment:
      - REDIS_HOST=redis
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_HOST=db
      - TRUSTED_PROXIES=traefik
     networks:
      - proxy
      - default
     labels:
      # ... (Traefik labels for Nextcloud)
      
   redis:
     image: redis:latest
     restart: always
     networks:
      - default
     volumes:
      - /home/docker/redis:/var/lib/redis
     environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD}

   db:
     image: mariadb:latest
     restart: always
     command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --skip-innodb-read-only-compressed
     volumes:
       - /home/docker/db:/var/lib/mysql
     environment:
       - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
       - MYSQL_PASSWORD=${MYSQL_PASSWORD}
       - MYSQL_DATABASE=nextcloud
       - MYSQL_USER=nextcloud

volumes:
  redis:
    name: nextcloud-redis

networks:
  proxy:
    external: true
  default:
    driver: bridge

By using ${VARIABLE_NAME} syntax, Docker Compose will read the values of the environment variables from the .env file and substitute them into the configuration.

Launching the Services

After making these changes, you can launch the services as before using:

$ docker-compose up -d

Now the sensitive information is stored securely in the .env file, and you’ve reduced the risk of accidentally exposing sensitive information in your Docker Compose file. Make sure to keep the .env file protected and not share it publicly.


Leave a Comment

Your email address will not be published. Required fields are marked *