Hello.
Notesnook is an end-to-end encrypted note taking alternative to Evernote. I wanted to self-host a Notesnook sync server really badly, but I’m a noob. So, I worked hard on it and came up with this noob-proof tutorial on how to set up a Notesnook sync server with local file storage, getting inspiration from the provided docker-compose in the repository.
That’s my way of giving back to the self-hosting community. I hope it can help some people.
This guide will help you set up a self-hosted instance of Notesnook using Docker Compose.
Create the required directories:
# Create data directories
mkdir -p /srv/Files/Notesnook/db
mkdir -p /srv/Files/Notesnook/s3
mkdir -p /srv/Files/Notesnook/setup
Create the .env
file:
cd /srv/Files/Notesnook/setup
nano .env
Add the following content (modify the values accordingly):
# Instance Configuration
INSTANCE_NAME=My Notesnook
DISABLE_SIGNUPS=false
NOTESNOOK_API_SECRET=your_secure_api_secret_here
# SMTP Configuration
SMTP_USERNAME=your_email@domain.com
SMTP_PASSWORD=your_smtp_password
SMTP_HOST=smtp.your-server.com
SMTP_PORT=587
# Public URLs (replace domain.com with your domain)
AUTH_SERVER_PUBLIC_URL=https://auth.domain.com/
NOTESNOOK_APP_PUBLIC_URL=https://notes.domain.com/
MONOGRAPH_PUBLIC_URL=https://mono.domain.com/
ATTACHMENTS_SERVER_PUBLIC_URL=https://files.domain.com/
# MinIO Configuration
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=your_secure_password_here
Create the docker-compose.yml
file:
nano docker-compose.yml
Paste the following content:
x-server-discovery: &server-discovery
NOTESNOOK_SERVER_PORT: 5264
NOTESNOOK_SERVER_HOST: notesnook-server
IDENTITY_SERVER_PORT: 8264
IDENTITY_SERVER_HOST: identity-server
SSE_SERVER_PORT: 7264
SSE_SERVER_HOST: sse-server
SELF_HOSTED: 1
IDENTITY_SERVER_URL: ${AUTH_SERVER_PUBLIC_URL}
NOTESNOOK_APP_HOST: ${NOTESNOOK_APP_PUBLIC_URL}
x-env-files: &env-files
- .env
services:
validate:
image: vandot/alpine-bash
entrypoint: /bin/bash
env_file: *env-files
command:
- -c
- |
required_vars=(
"INSTANCE_NAME"
"NOTESNOOK_API_SECRET"
"DISABLE_SIGNUPS"
"SMTP_USERNAME"
"SMTP_PASSWORD"
"SMTP_HOST"
"SMTP_PORT"
"AUTH_SERVER_PUBLIC_URL"
"NOTESNOOK_APP_PUBLIC_URL"
"MONOGRAPH_PUBLIC_URL"
"ATTACHMENTS_SERVER_PUBLIC_URL"
)
for var in "$${required_vars[@]}"; do
if [ -z "$${!var}" ]; then
echo "Error: Required environment variable $$var is not set."
exit 1
fi
done
echo "All required environment variables are set."
restart: "no"
notesnook-db:
image: mongo:7.0.12
hostname: notesnook-db
volumes:
- /srv/Files/Notesnook/db:/data/db
- /srv/Files/Notesnook/db:/data/configdb
networks:
- notesnook
command: --replSet rs0 --bind_ip_all
depends_on:
validate:
condition: service_completed_successfully
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh mongodb://localhost:27017 --quiet
interval: 40s
timeout: 30s
retries: 3
start_period: 60s
initiate-rs0:
image: mongo:7.0.12
networks:
- notesnook
depends_on:
- notesnook-db
entrypoint: /bin/sh
command:
- -c
- |
mongosh mongodb://notesnook-db:27017 <<EOF
rs.initiate();
rs.status();
EOF
notesnook-s3:
image: minio/minio:RELEASE.2024-07-29T22-14-52Z
ports:
- 9009:9000
- 9090:9090
networks:
- notesnook
volumes:
- /srv/Files/Notesnook/s3:/data/s3
environment:
MINIO_BROWSER: "on"
depends_on:
validate:
condition: service_completed_successfully
env_file: *env-files
command: server /data/s3 --console-address :9090
healthcheck:
test: timeout 5s bash -c ':> /dev/tcp/127.0.0.1/9000' || exit 1
interval: 40s
timeout: 30s
retries: 3
start_period: 60s
setup-s3:
image: minio/mc:RELEASE.2024-07-26T13-08-44Z
depends_on:
- notesnook-s3
networks:
- notesnook
entrypoint: /bin/bash
env_file: *env-files
command:
- -c
- |
until mc alias set minio http://notesnook-s3:9000/ ${MINIO_ROOT_USER:-minioadmin} ${MINIO_ROOT_PASSWORD:-minioadmin}; do
sleep 1;
done;
mc mb minio/attachments -p
identity-server:
image: streetwriters/identity:latest
ports:
- 8264:8264
networks:
- notesnook
env_file: *env-files
depends_on:
- notesnook-db
healthcheck:
test: wget --tries=1 -nv -q http://localhost:8264/health -O- || exit 1
interval: 40s
timeout: 30s
retries: 3
start_period: 60s
environment:
<<: *server-discovery
MONGODB_CONNECTION_STRING: mongodb://notesnook-db:27017/identity?replSet=rs0
MONGODB_DATABASE_NAME: identity
notesnook-server:
image: streetwriters/notesnook-sync:latest
ports:
- 5264:5264
networks:
- notesnook
env_file: *env-files
depends_on:
- notesnook-s3
- setup-s3
- identity-server
healthcheck:
test: wget --tries=1 -nv -q http://localhost:5264/health -O- || exit 1
interval: 40s
timeout: 30s
retries: 3
start_period: 60s
environment:
<<: *server-discovery
MONGODB_CONNECTION_STRING: mongodb://notesnook-db:27017/?replSet=rs0
MONGODB_DATABASE_NAME: notesnook
S3_INTERNAL_SERVICE_URL: "http://notesnook-s3:9000/"
S3_INTERNAL_BUCKET_NAME: "attachments"
S3_ACCESS_KEY_ID: "${MINIO_ROOT_USER:-minioadmin}"
S3_ACCESS_KEY: "${MINIO_ROOT_PASSWORD:-minioadmin}"
S3_SERVICE_URL: "${ATTACHMENTS_SERVER_PUBLIC_URL}"
S3_REGION: "us-east-1"
S3_BUCKET_NAME: "attachments"
sse-server:
image: streetwriters/sse:latest
ports:
- 7264:7264
env_file: *env-files
depends_on:
- identity-server
- notesnook-server
networks:
- notesnook
healthcheck:
test: wget --tries=1 -nv -q http://localhost:7264/health -O- || exit 1
interval: 40s
timeout: 30s
retries: 3
start_period: 60s
environment:
<<: *server-discovery
monograph-server:
image: streetwriters/monograph:latest
ports:
- 6264:3000
env_file: *env-files
depends_on:
- notesnook-server
networks:
- notesnook
healthcheck:
test: wget --tries=1 -nv -q http://localhost:3000/api/health -O- || exit 1
interval: 40s
timeout: 30s
retries: 3
start_period: 60s
environment:
<<: *server-discovery
API_HOST: http://notesnook-server:5264/
PUBLIC_URL: ${MONOGRAPH_PUBLIC_URL}
networks:
notesnook:
Pull all required images to avoid timeout issues:
cd /srv/Files/Notesnook/setup
docker pull mongo:7.0.12
docker pull minio/minio:RELEASE.2024-07-29T22-14-52Z
docker pull streetwriters/identity:latest
docker pull streetwriters/notesnook-sync:latest
docker pull streetwriters/sse:latest
docker pull streetwriters/monograph:latest
docker pull vandot/alpine-bash
or just
cd /srv/Files/Notesnook/setup
docker compose pull
Start the services:
cd /srv/Files/Notesnook/setup
docker compose up -d
docker compose ps
Expected status:
notesnook-db
notesnook-s3
identity-server
notesnook-server
sse-server
monograph-server
Exit 0
):
validate
initiate-rs0
setup-s3
docker compose logs
Visit: http://your-server:9009/
Enable WebSockets Support for:
notes.domain.com (port 5264) - For real-time synchronization
events.domain.com (port 7264) - For real-time notifications
Enable Cache Assets for: mono.domain.com (port 6264) - For optimizing public notes loading
sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx
sudo certbot --nginx -d auth.domain.com -d notes.domain.com -d events.domain.com -d mono.domain.com
Use the following example configurations for each subdomain:
# Auth Server - Basic (no cache/websocket needed)
server {
listen 80;
server_name auth.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name auth.domain.com;
ssl_certificate /etc/letsencrypt/live/auth.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://localhost:8264/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# Notes Server - With WebSocket
server {
listen 80;
server_name notes.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name notes.domain.com;
ssl_certificate /etc/letsencrypt/live/notes.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/notes.domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://localhost:5264/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600;
proxy_send_timeout 3600;
}
}
# Events Server - With WebSocket
server {
listen 80;
server_name events.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name events.domain.com;
ssl_certificate /etc/letsencrypt/live/events.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/events.domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://localhost:7264/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600;
proxy_send_timeout 3600;
}
}
# Monograph Server - With Cache
server {
listen 80;
server_name mono.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name mono.domain.com;
ssl_certificate /etc/letsencrypt/live/mono.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mono.domain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://localhost:6264/;
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_cache_valid 200 60m;
add_header X-Cache-Status $upstream_cache_status;
expires 1h;
add_header Cache-Control "public, no-transform";
}
}
# View real-time logs
docker compose logs -f
# View logs for specific service
docker compose logs [service-name]
# Restart specific service
docker compose restart [service-name]
# Stop all services
docker compose down
# Update services
docker compose pull
docker compose up -d
Regularly backup these directories:
/srv/Files/Notesnook/db/
(MongoDB data)/srv/Files/Notesnook/s3/
(MinIO data)/srv/Files/Notesnook/setup/.env
(Configuration)To update all services:
cd /srv/Files/Notesnook/setup
docker compose pull
docker compose down
docker compose up -d
docker compose logs [service-name]
docker compose logs notesnook-db
.docker compose logs notesnook-s3
..env
..env
..env
file secure.fail2ban
.If you encounter issues:
A place to share alternatives to popular online services that can be self-hosted without giving up privacy or locking you into a service you don’t control.
Rules:
Be civil: we’re here to support and learn from one another. Insults won’t be tolerated. Flame wars are frowned upon.
No spam posting.
Posts have to be centered around self-hosting. There are other communities for discussing hardware or home computing. If it’s not obvious why your post topic revolves around selfhosting, please include details to make it clear.
Don’t duplicate the full text of your blog or github here. Just post the link for folks to click.
Submission headline should match the article title (don’t cherry-pick information from the title to fit your agenda).
No trolling.
Resources:
Any issues on the community? Report it using the report flag.
Questions? DM the mods!
@Tiritibambix is this config working in a LAN envirovment too?
Thank you and best Regards!
As long as you use https, it should be working.