This setup is based on git and post receive hooks for publishing.
Requirements
Quartz 4.5+ requires Node.js >= 22 and npm >= 10.9.2. Your Docker image handles this, but you’ll need a compatible environment if testing locally.
First, create a bare git repo for the notes called content.git
:
git init --bare content.git
cd content.git
touch test
git add test
git commit -m "Initial commit"
cd ..
Then, clone the original quartz repo into a bare state. Call it quartz.git
:
git clone --bare https://github.com/jackyzha0/quartz.git quartz.git
Now, we need a local clone of that repo which we can later mount in a docker container. Let’s call it quartz-site
:
git clone quartz.git quartz-site
The content.git
repo should new be added as a submodule to the quartz-site
.
cd quartz-site
git rm -r --cached content
rm -rf content
git commit -m "Remove original content directory"
# Add content.git as submodule
git config protocol.file.allow always
GIT_ALLOW_PROTOCOL=file git submodule add -f ../content.git content
git commit -m "Add content.git as a sub"
git push
Things that could go wrong
- Adding submodules using the file protocol is considered unsafe, so be sure you know what you are doing.
Next, create post receive hooks for our content.git
repo.
#!/bin/bash
export PATH=/usr/bin:/bin:/usr/local/bin
set -e
echo "[Content hook] Updating Quartz repo submodule and rebuilding"
QUARTZ_DIR="/strg/src/secret/quartz-site"
GIT_DIR="$QUARTZ_DIR/.git"
BRANCH="v4"
export GIT_WORK_TREE="${QUARTZ_DIR}"
export GIT_DIR="${GIT_DIR}"
export GIT_ALLOW_PROTOCOL=file
cd "${QUARTZ_DIR}" || exit 1
echo "PWD: $(pwd)"
echo "GIT_DIR: $GIT_DIR"
echo "GIT_WORK_TREE: $GIT_WORK_TREE"
/usr/bin/git status
# Make sure you're acting *inside* a working repo
if [ ! -d "$GIT_DIR" ]; then
echo "[$GIT_DIR] is not a valid /usr/bin/git repo"
exit 1
fi
# Update submodule from content.git
/usr/bin/git --git-dir="$GIT_DIR" --work-tree="$QUARTZ_DIR" submodule update --remote --init
# Stage submodule change
/usr/bin/git --git-dir="$GIT_DIR" --work-tree="$QUARTZ_DIR" add content
# Only commit if needed
if ! /usr/bin/git --git-dir="$GIT_DIR" --work-tree="$QUARTZ_DIR" diff --cached --quiet; then
/usr/bin/git --git-dir="$GIT_DIR" --work-tree="$QUARTZ_DIR" commit -m "Auto-update content submodule"
/usr/bin/git --git-dir="$GIT_DIR" --work-tree="$QUARTZ_DIR" push origin "$BRANCH"
docker exec quartz-site npx quartz build
else
echo "[Content hook] No submodule changes detected"
fi
Don’t forget to make the hook executable:
chmod +x content.git/hooks/post-receive
Now, at the end of the hook is a call to a docker container that does not yet exist. Next we are going to create that!
We’ll use a quite simple docker container. The following are the files used for creating our container:
Consider the following file structure:
quartz-site
|-- compose.yml
|-- Dockerfile
|-- entrypoint.sh
\-- nginx.conf
services:
quartz-site:
build:
context: .
dockerfile: Dockerfile
container_name: quartz-site
ports:
- "8098:80"
volumes:
- /strg/src/secret/quartz-site:/site
restart: unless-stopped
FROM node:22-slim
# Install nginx
RUN apt-get update && apt-get install -y nginx && apt-get clean
# Copy nginx config
COPY nginx.conf /etc/nginx/nginx.conf
# Copy entrypoint
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
WORKDIR /site
CMD ["/entrypoint.sh"]
#!/bin/bash
set -e
echo "[Entrypoint] Building Quartz site..."
cd /site
# Ensure Node version is correct
echo "[Entrypoint] Node version: $(node -v)"
echo "[Entrypoint] NPM version: $(npm -v)"
# Install dependencies and initialize quartz
if [ ! -d "node_modules" ]; then
echo "[Entrypoint] Installing npm dependencies..."
npm install
npx quartz create
fi
# Run Quartz build
echo "[Entrypoint] Running Quartz build..."
npx quartz build
# Start Nginx
echo "[Entrypoint] Starting Nginx..."
exec nginx -g "daemon off;"
events {}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
root /site/public;
index index.html;
error_page 404 /404.html;
location / {
try_files $uri $uri.html $uri/ =404;
}
}
}
Now, let’s build and start our container:
docker compose up --build -d
On your local machine you can now clone the content.git
repo and start creating notes :)
Every time you push to the origin
content.git quartz should rebuild your notes.