Learn how to self-host AFFiNE on a Synology NAS using Docker and a secure Cloudflare Tunnel. Master your setup and avoid this one network mistake!
Are you tired of handing over your sensitive project data, whiteboards, and notes to third-party cloud servers? If you are heavily invested in productivity apps but demand total data sovereignty, it is time to take control.
AFFiNE is an open-source, all-in-one workspace that brilliantly combines the document features of Notion, the whiteboarding of Miro, and the project management capabilities of Monday.com into a single platform. By choosing to self-host AFFiNE on your Synology NAS, you gain complete, direct control over your data. ย
Table of Contents
Why Self-Host AFFiNE on a Synology NAS?
The biggest hurdle for home lab enthusiasts is securely accessing internal services from the outside world. Traditional setups require opening ports on your router, which exposes your network to brute-force attacks and malicious bots.
The Solution: You can bypass port forwarding entirely by deploying a Cloudflare Tunnel alongside your AFFiNE Docker container. This method creates a secure, encrypted outbound connection from your NAS directly to Cloudflare’s edge network. When you access your workspace remotely, you connect via a secure HTTPS domain routed through Cloudflare’s free servers, keeping your true IP address hidden and your NAS completely locked down.
Prerequisites for the Ultimate Setup
Before diving into the terminal, ensure your Synology environment meets the strict requirements for this deployment.
- Synology NAS Hardware: You must have a model that officially supports Docker. ย
- Operating System: We highly recommend running DSM version 7.2 or higher. ย
- Software Package: Install the “Container Manager” directly from the Synology Package Center. ย
- Terminal Access: SSH access must be enabled via the Control Panel. ย
Domain Warning: You cannot easily link a default Synology DDNS address (e.g., xxx.synology.me) directly to a Cloudflare Tunnel. You must use a custom domain managed by Cloudflare. You can purchase one directly from Cloudflare or transfer the nameservers from a registrar like Namecheap or Gabia.
Step 1: Directory Structure & Environment Variables
Proper folder mapping is critical. If you rely on internal Docker volumes instead of mapping them to your NAS storage array, all your workspace data will vanish the moment you update the container.
Create the Persistent Storage Folders
Open File Station and navigate to your main docker shared folder. Create a new folder named affine, and inside it, build the following exact structure:
- /postgres/ โ Dedicated to saving your database files. ย
- /redis/ โ Used for caching server data. ย
- /storage/ โ Your main repository for uploaded files and images. ย
- /config/ โ Holds essential configuration files.
Configure the .env File
Connect to your NAS via SSH and use the vi editor to create an environment file at /volume1/docker/affine/.env.
You will need to define a 64-character random string for your session secret. Do not guess this. Generate it securely in your SSH terminal by running the command openssl rand -hex 32.
Populate your .env file with the following, replacing the placeholders with your actual data:
POSTGRES_PASSWORD=Enter_A_Strong_PasswordSESSION_SECRET=Your_Generated_64_Character_StringAFFINE_SERVER_HOST=affine.yourdomain.comAFFINE_SERVER_PORT=443CLOUDFLARE_TUNNEL_TOKEN=Your_Cloudflare_Token_Here
Note: Make sure your AFFINE_SERVER_HOST perfectly matches the domain you intend to use in Cloudflare.
Step 2: The Docker Compose Configuration
Instead of deploying scattered containers, we will use a unified compose.yaml file to bring up the core app, database, cache, and tunnel simultaneously.
Navigate to Container Manager, go to Projects, click Create, set the path to docker/affine, and create a docker-compose.yml file.
Our setup will utilize four specific components:
- AFFiNE App: The main workspace running on port 3010. ย
- PostgreSQL (pgvector): The primary database backbone. ย
- Redis: A lightweight cache server. ย
- Cloudflare Tunnel: The zero-trust external access bridge.
Advanced Configuration Settings for Max Performance
When pasting in the official Docker Compose code, note a few crucial performance and stability tweaks we have applied:
- Disabled Healthchecks: We must set healthcheck: disable: true for the main AFFiNE container. The base image lacks wget and curl, which causes standard health checks to fail and report an “Unhealthy” status. ย
- Optimized Redis: By appending –save “” and –appendonly no, we disable Redis disk saving, as it is strictly serving as a temporary cache. This prevents “Redis MISCONF” permission errors. ย
- Network Isolation: We define a custom bridge network (affine_net) to ensure secure container isolation, which is highly recommended for Synology environments. ย
- Telemetry Disabled: We explicitly disable data collection by setting TELEMETRY_ENABLE=false.
Step 3: Secure Remote Access with Cloudflare Tunnel
Now, let’s connect your local NAS to the global internet safely.
- Log into the Cloudflare Dashboard and navigate to Zero Trust โ Networks โ Tunnels โ Create a Tunnel. ย
- Select Cloudflared as your connector type. ย
- Name your tunnel (for example, affine-tunnel). ย
- Choose Docker as your environment, copy the provided TOKEN value, and paste it into your .env file under CLOUDFLARE_TUNNEL_TOKEN.
Setting the Public Hostname
Next, map your domain to the internal Docker port. Go to your tunnel settings, click Configure, and add a Public Hostname.
- Subdomain: affine (or your preferred name). ย
- Domain: Select your purchased domain. ย
- Type: HTTP. ย
- URL: affine:3010.
Launching the Stack
Return to your SSH terminal, navigate to /volume1/docker/affine, and start the stack:sudo docker compose up -d ย
Verify the tunnel connection by checking the logs:sudo docker logs affine_cloudflared -f If you see “Connected to Cloudflare,” your deployment is successful!
Pro Tip: Troubleshooting Common Homelab Errors
Even with a perfect setup, network routing can cause headaches. Here are the most critical fixes for common AFFiNE self-hosting issues.
- The Hairpin NAT Problem
If you are connected to your home WiFi (the same network as the NAS), accessing https://affine.yourdomain.com might fail. This is a common router limitation known as Hairpin NAT. ย- When at home: Use your internal IP http://NAS_IP:3010. ย
- When on LTE/5G: Use your official https://affine.yourdomain.com address. ย
- Broken Copy and Paste
If you notice that your clipboard does not work when trying to paste images or text, check your URL. Modern browsers block clipboard access over unencrypted HTTP connections; you must access the workspace via HTTPS. ย - Fragmented Workspaces Across Devices
If your desktop and mobile app seem to have completely different data, you are likely using a “Local Workspace.” To sync data, you must create an admin account, log in (Sign Up), and strictly use a Server Workspace. Using the local workspace prevents synchronization.
Conclusion & Maintenance Strategy
You have successfully built a private, high-performance productivity suite. To maintain your instance, never use the stable tag in your Docker compose file, as automatic pulls can break your database. Instead, manually update the image tag to specific release versions (e.g., ghcr.io/toeverything/affine:0.27.0) when checking their GitHub releases.
Always run routine backups of your /postgres, /storage, and /config folders!
Leave a Reply