
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.
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.

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.

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.


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.