- Setting up self-hosted Logseq sync and publish server along with the web-app. Based on the yshalsager Logseq self-host wrapper but customized to work with NGINX Proxy Manager
- Key changes:
- Combines all three separate
docker-compose.yamlfiles from the wrapper into a single deployable stack - Use a bind mount for sync data (for persistent storage)
- Does not expose ports directly to the host → Attaches services to the NGINX Proxy Manager Docker network and uses container names as internal proxy targets
docker-compose.yamlfilename: logseq-selfhost services: logseq-sync: image: ghcr.io/yshalsager/logseq-selfhost-sync:latest container_name: logseq-selfhost-sync restart: unless-stopped environment: DB_SYNC_PORT: "8787" DB_SYNC_BASE_URL: "${DB_SYNC_BASE_URL}" DB_SYNC_DATA_DIR: "/app/data" DB_SYNC_STORAGE_DRIVER: "sqlite" DB_SYNC_ASSETS_DRIVER: "filesystem" DB_SYNC_LOG_LEVEL: "info" COGNITO_ISSUER: "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_dtagLnju8" COGNITO_CLIENT_ID: "69cs1lgme7p8kbgld8n5kseii6" COGNITO_JWKS_URL: "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_dtagLnju8/.well-known/jwks.json" DB_SYNC_ADMIN_TOKEN: "${DB_SYNC_ADMIN_TOKEN}" volumes: - ./data:/app/data read_only: true tmpfs: - /tmp cap_drop: - ALL security_opt: - no-new-privileges:true networks: - default - nginx-proxy-manager_default logseq-web: image: ghcr.io/yshalsager/logseq-selfhost-web:latest container_name: logseq-selfhost-web restart: unless-stopped pull_policy: always read_only: true tmpfs: - /tmp - /var/cache/nginx cap_drop: - ALL security_opt: - no-new-privileges:true networks: - default - nginx-proxy-manager_default logseq-publish: image: ghcr.io/yshalsager/logseq-selfhost-publish:latest container_name: logseq-selfhost-publish restart: unless-stopped pull_policy: always environment: COGNITO_ISSUER: "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_dtagLnju8" COGNITO_CLIENT_ID: "69cs1lgme7p8kbgld8n5kseii6" COGNITO_JWKS_URL: "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_dtagLnju8/.well-known/jwks.json" read_only: true tmpfs: - /tmp - /data/home:uid=1000,gid=1000,mode=0755 - /app/worker/.wrangler:uid=1000,gid=1000,mode=0755 - /app/worker/node_modules/.mf:uid=1000,gid=1000,mode=0755 volumes: - logseq_publish_wrangler:/data/wrangler cap_drop: - ALL security_opt: - no-new-privileges:true networks: - default - nginx-proxy-manager_default networks: nginx-proxy-manager_default: external: true volumes: logseq_publish_wrangler:
Setup
Directory setup
- The
docker-compose.yamland the.envfiles should reside in the same directory from wheredocker composecommands will be run (e.g.~/home-server/logseq-sync) - The
docker-compose.yamlalso sets up persistent storage in this directory. Change the./dataundervolumesto change this location
DNS setup
- Create
CNAMErecords in the DNS provider (e.g. Cloudflare) for the hostnameslogseq-sync.example.com→ Sync serverlogseq-publish.example.com→ Publish serverlogseq-web.example.com→ Web-app
Environment file
- Create the
.envfile in the compose directory (e.g.~/home-server/logseq-sync) DB_SYNC_BASE_URL=https://logseq-sync.example.com DB_SYNC_ADMIN_TOKEN=replace-with-random-token- Generate the random admin token and replace in the
.envfile openssl rand -hex 32
Container startup
- Pull the images and start the containers
docker compose pull docker compose up -d
Set up hosts in NGINX Proxy Manager
- For each service, add a separate proxy host, replacing the "Domain name" and "Forward Hostname" appropriately
Domain Names: logseq-sync.example.com Scheme: http Forward Hostname/IP: logseq-selfhost-sync Forward Port: 8787 Cache Assets: OFF Block Common Exploits: ON Websockets Support: ON- Set the SSL settings
SSL Certificate: Select existing or request a new one Force SSL: ON HTTP/2 Support: ON- Advanced NGINX configs
- For
logseq-sync.example.com: client_max_body_size 1024m; proxy_read_timeout 3600s; proxy_send_timeout 3600s;- For
logseq-web.example.com: client_max_body_size 1024m; proxy_read_timeout 3600s; proxy_send_timeout 3600s; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header X-Frame-Options "SAMEORIGIN" always;
Health checks
- Check if the docker containers are running
docker compose ps- Test through the public proxy
curl -i https://logseq-sync.example.com/health curl -I https://logseq-web.example.com/ curl -I https://logseq-publish.example.com/ curl -I https://logseq-publish.example.com/static/publish.css- Expected results
logseq-sync/healthreturns:{"ok":true}logseq-web/returns200logseq-publish/returns publish HTMLlogseq-publish/static/publish.cssreturns200
Setup sync settings in Logseq
- Under "Settings" → "Advanced"
- Add
https://logseq-sync.example.comto "Sync Server URL" - Add
https://logseq-publish.example.comto "Publish Server URL"