Overleaf has become a popular choice for collaborative LaTeX editing, making it easy for academics, researchers, and engineers to work together directly in a web browser.

However, using Overleaf’s public cloud service involves more than just a financial cost. As projects become larger and more complex, the disadvantages of depending on a third-party Software-as-a-Service (SaaS) provider become increasingly difficult to overlook:

  • Compile Timeouts: On Overleaf’s free plan, you are restricted to a short 10-second compilation window. The moment you add complex diagrams, heavy plots, or large high-resolution figures, your builds hit a wall and crash with timeout errors. Even paid subscription tiers cap your compile times.
  • Data Privacy and IP Concerns: Uploading proprietary research, sensitive company documents, or unpublished papers to a cloud server means trusting an external platform with your intellectual property. For many institutions and privacy-conscious authors, storing raw LaTeX code online raises significant security and compliance concerns.
  • Subscription Paywalls & Team Limits: Essential features such as real-time collaboration with more than one co-author, full project history, and Git integration are locked behind recurring monthly subscriptions.
  • Vendor Lock-In & Internet Dependency: If your internet connection drops or Overleaf experiences downtime, access to your work instantly stops.

Fortunately, you don’t have to trade Overleaf's brilliant web-based interface for local command-line tools. By self-hosting Overleaf Community Edition via Docker and Docker Compose, you get the best of both worlds. Unlimited compilation power, zero data tracking, full offline availability, and complete control over your TeX environment. All running on your own server or local machine.

In this guide, we’ll walk through setting up your private Overleaf instance step by step using Docker and Docker Compose.

Screenshot of Overleaf running in a homelab

Docker Compose Setup

The docker compose stack for Overleaf consists of three components:

  • MongoDB database
  • Redis caching database
  • Overleaf app
💡
Optionally, you may want to add a reverse proxy like Traefik.

Setting Up MongoDB

Before spawning up the Overleaf stack, one has to define a MongoDB configuration file.

Luckily, the file can easily be downloaded and put aside next to your future docker-compose.yml file. Just run the following command on your Linux host:

curl -o mongodb-init-replica-set.js https://raw.githubusercontent.com/overleaf/overleaf/main/bin/shared/mongodb-init-replica-set.js

Downloading mongodb-init-replica-set.js

Alternatively, if you want to manually create it, please put the following content in a file named mongodb-init-replica-set.js:

/* eslint-disable no-undef */

rs.initiate({ _id: 'overleaf', members: [{ _id: 0, host: 'mongo:27017' }] })

Content of mongodb-init-replica-set.js

Setting Up Overleaf

Next, we can create the docker-compose.yml, which defines all three containers.

🚨
Please adjust the environment variables and docker bind mount volumes to your liking. Especially secret keys like OVERLEAF_INVITE_TOKEN_SECRET.
services:

    sharelatex:
        image: sharelatex/sharelatex:6.3.0
        container_name: sharelatex
        restart: always
        depends_on:
            mongo:
                condition: service_healthy
            redis:
                condition: service_started
        ports:
            - 8888:80
        expose:
            - 80
        links:
            - mongo
            - redis
        stop_grace_period: 60s
        volumes:
            - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/sharelatex/data:/var/lib/overleaf
        environment: # see https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/environment-variables
            OVERLEAF_APP_NAME: Overleaf Community Edition
            OVERLEAF_MONGO_URL: mongodb://mongo/sharelatex?replicaSet=overleaf
            OVERLEAF_INVITE_TOKEN_SECRET: Distance-Rework-Iphone-Viewing # generate a secure value with openssl rand -base64 32
            OVERLEAF_REDIS_HOST: redis
            REDIS_HOST: redis
            ENABLED_LINKED_FILE_TYPES: 'project_file,project_output_file'
            ENABLE_CONVERSIONS: 'true'
            EMAIL_CONFIRMATION_DISABLED: 'true'
            # TEXMFVAR: /var/lib/sharelatex/tmp/texmf-var
            # OVERLEAF_SITE_URL: http://overleaf.example.com
            # OVERLEAF_NAV_TITLE: Overleaf Community Edition
            # OVERLEAF_HEADER_IMAGE_URL: http://example.com/mylogo.png
            # OVERLEAF_ADMIN_EMAIL: [email protected]
            # OVERLEAF_LEFT_FOOTER: '[{"text": "Another page I want to link to can be found <a href=\"here\">here</a>"} ]'
            # OVERLEAF_RIGHT_FOOTER: '[{"text": "Hello I am on the Right"} ]'
            # OVERLEAF_EMAIL_FROM_ADDRESS: "[email protected]"
            # OVERLEAF_EMAIL_AWS_SES_ACCESS_KEY_ID:
            # OVERLEAF_EMAIL_AWS_SES_SECRET_KEY:
            # OVERLEAF_EMAIL_SMTP_HOST: smtp.example.com
            # OVERLEAF_EMAIL_SMTP_PORT: 587
            # OVERLEAF_EMAIL_SMTP_SECURE: false
            # OVERLEAF_EMAIL_SMTP_USER:
            # OVERLEAF_EMAIL_SMTP_PASS:
            # OVERLEAF_EMAIL_SMTP_TLS_REJECT_UNAUTH: true
            # OVERLEAF_EMAIL_SMTP_IGNORE_TLS: false
            # OVERLEAF_EMAIL_SMTP_NAME: '127.0.0.1'
            # OVERLEAF_EMAIL_SMTP_LOGGER: true
            # OVERLEAF_CUSTOM_EMAIL_FOOTER: "This system is run by department x"
            # ENABLE_CRON_RESOURCE_DELETION: true
            # OVERLEAF_LDAP_URL: 'ldap://ldap:389'
            # OVERLEAF_LDAP_SEARCH_BASE: 'ou=people,dc=planetexpress,dc=com'
            # OVERLEAF_LDAP_SEARCH_FILTER: '(uid={{username}})'
            # OVERLEAF_LDAP_BIND_DN: 'cn=admin,dc=planetexpress,dc=com'
            # OVERLEAF_LDAP_BIND_CREDENTIALS: 'GoodNewsEveryone'
            # OVERLEAF_LDAP_EMAIL_ATT: 'mail'
            # OVERLEAF_LDAP_NAME_ATT: 'cn'
            # OVERLEAF_LDAP_LAST_NAME_ATT: 'sn'
            # OVERLEAF_LDAP_UPDATE_USER_DETAILS_ON_LOGIN: 'true'
            # OVERLEAF_TEMPLATES_USER_ID: "578773160210479700917ee5"
            # OVERLEAF_NEW_PROJECT_TEMPLATE_LINKS: '[ {"name":"All Templates","url":"/templates/all"}]'
            # OVERLEAF_PROXY_LEARN: "true"
            # OVERLEAF_TRUSTED_PROXY_IPS: 127.0.0.1/32
        #networks:
        #  - proxy
        #  - internal-db
        #labels:
        #  - traefik.enable=true
        #  - traefik.docker.network=proxy
        #  - traefik.http.routers.overleaf.rule=Host(`overleaf.example.com`)
        #  - traefik.http.services.overleaf.loadbalancer.server.port=80
        #  # Optional part for traefik middlewares
        #  - traefik.http.routers.overleaf.middlewares=local-ipwhitelist@file,crowdsec@file

    mongo:
        restart: always
        image: mongo:8.2
        container_name: sharelatex-mongo
        command: "--replSet overleaf"
        expose:
            - 27017
        volumes:
            - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/sharelatex/mongo:/data/db
            - ./mongodb-init-replica-set.js:/docker-entrypoint-initdb.d/mongodb-init-replica-set.js:ro
        environment:
            MONGO_INITDB_DATABASE: sharelatex
        extra_hosts:
            - mongo:127.0.0.1
        healthcheck:
            test: echo 'db.stats().ok' | mongosh localhost:27017/test --quiet
            interval: 10s
            timeout: 10s
            retries: 5
        #networks:
        #  - internal-db            

    redis:
        restart: always
        image: redis:8-alpine
        container_name: sharelatex-redis
        expose:
            - 6379
        volumes:
            - ${DOCKER_VOLUME_STORAGE:-/mnt/docker-volumes}/sharelatex/redis:/data
        #networks:
        #  - internal-db

#networks:
#  proxy:
#    external: true
#  internal-db:
#    internal: true
🧠
As you can see, Traefik reverse proxy labels as well as Docker bridge networking are already defined but still commented out. Feel free to adjust the network setup and reverse proxy configuration to your liking.

The stack works without TLS and a specific network configuration just fine. So you may just spawn it up for testing purposes and add a reverse proxy or custom networking later on.

Spawning the Stack

After having defined the docker-compose.yml as well as the mongodb-init-replica-set.js configuration file for MongoDB, we can start spawning up the stack via:

docker compose up -d

Afterwards, the Overleaf web interface will be available on:

http://<YOUR-IP>:8888

Creating your Admin User

To create the first admin user account, one can open the web URL path /launchpad. So please go ahead and open the following URL:

http://<YOUR-IP>:8888/launchpad 

Adhere to the account setup instructions and create your admin account.

You may proceed logging in.

Additional Packages

The Overleaf Community Docker image comes as lightweight installation and provides only a minimal install of TeXLive.

With this minimal installation, most real-world LaTex projects won't really compile and you won't be able to generate a PDF document.

Therefore, we have to add more packages using tlmgr.

Install Individual Packages

Depending on your LaTex project, you may want to install individual and selective packages only. Basically, just the things you need.

To install an individual package, you can run:

docker exec sharelatex tlmgr install <package-name>

Command to install individual package

Here is an example:

docker exec -it sharelatex tlmgr install collection-langgerman collection-fontsrecommended collection-latexrecommended collection-latexextra collection-bibtexextra

Install the Full Scheme

In order to run an Overleaf instance with nearly all possible features supported, one have to install the full scheme.

To do so, please run the following command:

docker exec sharelatex tlmgr install scheme-full

Command to install the full scheme with all packages

💡
Please be aware that installing scheme-full may take a few minutes as multiple packages must be downloaded, installed and activated.

Persist Package Data

Once individual packages or the full scheme were installed, your Overleaf instance is ready to go. Just define your project and LaTex files and PDF compilation should work flawlessly.

However, there is one downside.

🚨
Installed packages via the tlmgr binary are not persisted accross container restarts.

Therefore, one will loose all package installs and would have to install the individual packages or full-scheme each time the container is restarted. Quite a PAIN!

In order to persist installed packages, one have to use the docker commit command as follows:

docker commit sharelatex sharelatex/sharelatex:6.3.0-with-texlive-full

Command to snapshot the container image with custom installed packages

Afterwars, one have to define this custom image at the docker-compose.yaml and restart the stack.

services:

    sharelatex:
        image: sharelatex/sharelatex:6.3.0-with-texlive-full
        ...

Excerpt of the adjusted docker-compose.yml with the new image tag

After container restart, your Overleaf instance with individually installed packages is ready to use.

🚨
You will need to repeat these steps each time you upgrade to a new Overleaf version. Please read the official documentation.

Summary

Self-hosting Overleaf Community Edition with Docker and Docker Compose gives you complete control over your LaTeX environment, bypassing SaaS constraints like strict compile timeouts, team size caps, and cloud privacy concerns.

Enjoy!