This repository provides ready Docker image for Quartz v4, an open-source tool for publishing digital gardens and Obsidian vaults.
Credits: All credit for Quartz goes to jackyzha0. This repository only handles the containerization process.
This image is designed for local network use or VPN-only environments (like Tailscale/Headscale). It utilizes the npx quartz build --serve command, meaning it actively watches your mounted Markdown files and provides real-time Hot-Reloading via WebSockets.
I DO NOT recommend exposing this image directly to the public internet "as is".
Because this image runs a continuous Node.js runtime to facilitate live-syncing and WebSocket connections (port 3001), it naturally has a larger attack surface than a static web server. It contains several npm dependencies that are strictly meant for the build process but remain present in the runtime to allow on-the-fly rebuilding.
For Public Production Environments:
If you plan to expose your digital garden to the internet via Cloudflare, Caddy, or Nginx, you should use a 3-stage static build approach. In a production setup, Quartz should only be used to generate the /public static HTML/CSS files during a CI/CD pipeline, and those files should be served by a pure, stripped-down web server (like Caddy file_server or Nginx) without any Node.js runtime attached.
-
Copy the
compose.yml.examplefile todocker-compose.yml. -
Edit the volume paths to point to your local Obsidian vault.
-
Run the stack:
docker compose up -d
8080: Main HTTP Web Server.3001: WebSocket Server (Required for Live Hot-Reloading).
/usr/src/app/content: Mount your Markdown files here. Always use:ro(Read-Only) as shown in the compose file. This ensures the container can never accidentally corrupt or overwrite your personal vault data.
Currently, no explicit environment variables are required for basic functionality. If you need to customize Quartz behavior, you should bind-mount your customized quartz.config.ts and quartz.layout.ts over the default ones inside /usr/src/app/.
This image implements several sysadmin-grade security practices:
- Non-Root Execution: The process runs as the standard, unprivileged
nodeuser (UID 1000). - Capability Drop: The
compose.yml.exampleexplicitly drops all Linux Kernel capabilities (cap_drop: - ALL). - No New Privileges: Prevents privilege escalation vectors.
- Automated Scanning: Built monthly via GitHub Actions and scanned by Trivy. If CRITICAL or HIGH vulnerabilities are detected, the build fails and prevents publishing.
- Built-in Healthcheck: Docker automatically monitors the container via
curlto ensure the HTTP server is responsive.
If you want to build the image yourself instead of pulling from GHCR:
docker compose up -d --buildYou can specify a target Quartz version/tag by passing a build argument:
docker build --build-arg QUARTZ_VERSION=v4.2.3 -t quartz-custom .This project is provided "as is" without warranty of any kind. You are solely responsible for ensuring the security of your network and infrastructure.