How to Deploy Nextcloud – Private Cloud Storage

Updated on 18 December, 2025
Deploy Nextcloud Collaboration Platform with Docker Compose, Traefik TLS, and Secure Cloud Storage.
How to Deploy Nextcloud – Private Cloud Storage header image

Nextcloud is an open-source productivity platform that combines file storage with a suite of collaboration tools, including calendars, contacts, and video conferencing. It is designed for privacy and security, giving you full control over your data while offering features similar to those found in Microsoft 365 or Google Workspace.

This article demonstrates how to deploy Nextcloud on Ubuntu 24.04 using Docker Compose.

Prerequisites

Before you begin:

Set Up the Directory Structure and Environment Variables

Nextcloud requires persistent storage for user data and the database, as well as environment variables to configure the installation. This section sets up the necessary directories and configuration file.

  1. Create the project folders.

    console
    $ mkdir -p ~/nextcloud/{html,mysql,redis,letsencrypt}
    
    • html - Stores the main Nextcloud application code and user data.
    • mysql - Persistent storage for the MariaDB database.
    • redis - Stores Redis cache snapshots for persistence between restarts.
    • letsencrypt - Stores Traefik ACME certificates.
  2. Navigate to the root Nextcloud directory.

    console
    $ cd ~/nextcloud
    
  3. Create an .env file to store your configuration.

    console
    $ nano .env
    
  4. Add the following values:

    ini
    NEXTCLOUD_DOMAIN=nextcloud.example.com
    NEXTCLOUD_ADMIN_USER=admin
    NEXTCLOUD_ADMIN_PASSWORD=STRONG_ADMIN_PASSWORD
    
    MYSQL_DATABASE=nextcloud
    MYSQL_USER=nextcloud
    MYSQL_PASSWORD=STRONG_DB_PASSWORD
    MYSQL_ROOT_PASSWORD=STRONG_ROOT_PASSWORD
    
    LETSENCRYPT_EMAIL=admin@example.com
    

    Replace the placeholders with your own values:

    • nextcloud.example.com – Your actual domain name.
    • STRONG_ADMIN_PASSWORD – The password you will use to log in to the Nextcloud web interface.
    • STRONG_DB_PASSWORD – Secure password for the Nextcloud database user.
    • admin@example.com – Your email for TLS certificate notifications.

    Save and close the file.

Deploy with Docker Compose

This section deploys the full Nextcloud stack behind Traefik. The configuration includes services for the application, database, and cache.

  1. Add your user account to the docker user group.

    console
    $ sudo usermod -aG docker $USER
    
  2. Apply the new group membership.

    console
    $ newgrp docker
    
  3. Create the Docker Compose manifest file.

    console
    $ nano docker-compose.yml
    
  4. Add the following contents:

    yaml
    services:
      traefik:
        image: traefik:latest
        container_name: traefik
        restart: unless-stopped
        environment:
          DOCKER_API_VERSION: "1.44"
        command:
          - "--providers.docker=true"
          - "--providers.docker.exposedbydefault=false"
          - "--entrypoints.web.address=:80"
          - "--entrypoints.websecure.address=:443"
          - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
          - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
          - "--certificatesresolvers.le.acme.httpchallenge=true"
          - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
          - "--certificatesresolvers.le.acme.email=${LETSENCRYPT_EMAIL}"
          - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - ./letsencrypt:/letsencrypt
    
      mariadb:
        image: mariadb:10.11
        container_name: nextcloud_db
        restart: unless-stopped
        command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
        environment:
          MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
          MYSQL_PASSWORD: ${MYSQL_PASSWORD}
          MYSQL_DATABASE: ${MYSQL_DATABASE}
          MYSQL_USER: ${MYSQL_USER}
        volumes:
          - ./mysql:/var/lib/mysql
        healthcheck:
          test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
          interval: 10s
          timeout: 5s
          retries: 3
    
      redis:
        image: redis:latest
        container_name: nextcloud_redis
        restart: unless-stopped
        volumes:
          - ./redis:/data
        healthcheck:
          test: ["CMD", "redis-cli", "ping"]
          interval: 10s
          timeout: 5s
          retries: 3
    
      nextcloud:
        image: nextcloud:latest
        container_name: nextcloud_app
        restart: unless-stopped
        depends_on:
          mariadb:
            condition: service_healthy
          redis:
            condition: service_healthy
        environment:
          NEXTCLOUD_ADMIN_USER: ${NEXTCLOUD_ADMIN_USER}
          NEXTCLOUD_ADMIN_PASSWORD: ${NEXTCLOUD_ADMIN_PASSWORD}
          NEXTCLOUD_TRUSTED_DOMAINS: ${NEXTCLOUD_DOMAIN}
          MYSQL_HOST: mariadb
          MYSQL_DATABASE: ${MYSQL_DATABASE}
          MYSQL_USER: ${MYSQL_USER}
          MYSQL_PASSWORD: ${MYSQL_PASSWORD}
          REDIS_HOST: redis
        volumes:
          - ./html:/var/www/html
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.nextcloud.rule=Host(`${NEXTCLOUD_DOMAIN}`)"
          - "traefik.http.routers.nextcloud.entrypoints=websecure"
          - "traefik.http.routers.nextcloud.tls=true"
          - "traefik.http.routers.nextcloud.tls.certresolver=le"
          - "traefik.http.services.nextcloud.loadbalancer.server.port=80"
          - "traefik.http.middlewares.nextcloud-dav.redirectregex.regex=^/.well-known/(card|cal)dav"
          - "traefik.http.middlewares.nextcloud-dav.redirectregex.replacement=/remote.php/dav/"
          - "traefik.http.routers.nextcloud.middlewares=nextcloud-dav"
    

    Save and close the file.

    This Docker Compose file deploys Nextcloud behind Traefik, using MariaDB for structured data and Redis for caching. Each service has a specific purpose:

    nextcloud service

    • Runs the official nextcloud image.
    • Connects to the mariadb service for the database and redis for transactional file locking and caching.
    • Automatically runs the installation wizard using the NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD variables provided.
    • Stores all application data and uploaded files in the ./html directory (mounted to /var/www/html).
    • Exposes port 80 internally, which Traefik routes to via labels.
    • Includes middleware labels (nextcloud-dav) to handle CalDAV and CardDAV redirects, ensuring calendar and contact syncing works correctly.

    mariadb service

    • Runs MariaDB 10.11, configured specifically for Nextcloud requirements (using READ-COMMITTED transaction isolation).
    • Initializes the database with the credentials from your .env file.
    • Stores database files in the ./mysql directory.
    • Includes a health check to ensure it is fully ready before the Nextcloud container attempts to connect.

    redis service

    • Runs a Redis server for in-memory caching and distributed file locking. Redis significantly improves Nextcloud's performance and prevents data corruption when multiple users edit files simultaneously.
    • Stores cache persistence data in the ./redis directory.

    traefik service

    • Listens on ports 80 and 443 to handle all incoming traffic.
    • Automatically requests and renews TLS certificates from Let’s Encrypt for your domain name.
    • Redirects all insecure HTTP traffic to HTTPS.
  5. Start all services in detached mode.

    console
    $ docker compose up -d
    
  6. Check the container status.

    console
    $ docker compose ps
    
    Note
    For more information on managing a Docker Compose stack, see the How To Use Docker Compose article.

Access and Configure Nextcloud

By default, Nextcloud restricts access to localhost to prevent header poisoning attacks. To access the site via your domain name, you must add it to the trusted list.

  1. Configure your domain as a trusted domain using the command below. Replace nextcloud.example.com with your actual domain name.

    console
    $ docker compose exec --user www-data nextcloud php occ config:system:set trusted_domains 1 --value=nextcloud.example.com
    
    • --user www-data: Runs the command as the web server user.
    • nextcloud: Target service name defined in the docker-compose file.
    • occ: Nextcloud's command-line administration tool.
  2. Run the following command to enable HTTPS for all generated links using Nextcloud, which prevents the Service from getting stuck in a login loop.

    console
    $ docker compose exec --user www-data nextcloud php occ config:system:set overwriteprotocol --value=https
    
  3. Open your browser and visit https://nextcloud.example.com. Enter the NEXTCLOUD_ADMIN_USER and NEXTCLOUD_ADMIN_PASSWORD you configured in your .env file.

  4. Upon successful login, the Nextcloud dashboard loads.

    Dashboard

Conclusion

You have successfully deployed Nextcloud on Ubuntu 24.04 using Docker Compose. Your deployment is now secure and accessible over HTTPS. For more details on managing your instance, visit the Nextcloud Administration Manual.

Comments