name: affine
services:
affine:
image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
container_name: affine_server
ports:
- '127.0.0.1:${PORT:-3010}:3010'
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
affine_migration:
condition: service_completed_successfully
volumes:
# custom configurations
- ${UPLOAD_LOCATION}:/root/.affine/storage
- ${CONFIG_LOCATION}:/root/.affine/config
env_file:
- .env
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
- AFFINE_INDEXER_ENABLED=false
restart: unless-stopped
affine_migration:
image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
container_name: affine_migration_job
volumes:
# custom configurations
- ${UPLOAD_LOCATION}:/root/.affine/storage
- ${CONFIG_LOCATION}:/root/.affine/config
command: ['sh', '-c', 'node ./scripts/self-host-predeploy.js']
env_file:
- .env
environment:
- REDIS_SERVER_HOST=redis
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
- AFFINE_INDEXER_ENABLED=false
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
redis:
image: redis
container_name: affine_redis
healthcheck:
test: ['CMD', 'redis-cli', '--raw', 'incr', 'ping']
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
postgres:
image: pgvector/pgvector:pg16
container_name: affine_postgres
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
environment:
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_DATABASE:-affine}
POSTGRES_INITDB_ARGS: '--data-checksums'
# you better set a password for you database
# or you may add 'POSTGRES_HOST_AUTH_METHOD=trust' to ignore postgres security policy
POSTGRES_HOST_AUTH_METHOD: trust
healthcheck:
test:
['CMD', 'pg_isready', '-U', "${DB_USERNAME}", '-d', "${DB_DATABASE:-affine}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped# select a revision to deploy, available values: stable, beta, canary
AFFINE_REVISION=stable
# set the port for the server container it will expose the server on
PORT=3010
# set the host for the server for outgoing links
# AFFINE_SERVER_HTTPS=true
# AFFINE_SERVER_HOST=affine.yourdomain.com
# or
AFFINE_SERVER_EXTERNAL_URL=https://your.domain.sample
# position of the database data to persist
DB_DATA_LOCATION=~/.affine/self-host/postgres/pgdata
# position of the upload data(images, files, etc.) to persist
UPLOAD_LOCATION=~/.affine/self-host/storage
# position of the configuration files to persist
CONFIG_LOCATION=~/.affine/self-host/config
# database credentials
DB_USERNAME=YourBestUsername
DB_PASSWORD=YourBestPassword
DB_DATABASE=affineupstream your.domain.sample {
server 127.0.0.1:3010;
}
server {
server_name your.domain.sample;
# Log files
access_log /var/log/nginx/your.domain.sample.access.log;
error_log /var/log/nginx/your.domain.sample.error.log warn;
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
# Optional security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
# Proxy everything to the internal NGINX service at 8443
location / {
proxy_pass http://your.domain.sample; # Replace with actual internal IP
proxy_ssl_verify off; # Optional if using self-signed certs internally
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/your.domain.sample/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.domain.sample/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = your.domain.sample) {
return 301 https://$host$request_uri;
}
listen 80;
server_name your.domain.sample;
return 404;
}Official Super Productivity Site
services:
# Super Productivity app
app-sp:
image: johannesjo/super-productivity:v14.4.1
container_name: app-sp
ports:
- '8888:80'
environment:
# Pre-configured defaults for easier setup
WEBDAV_BASE_URL: ${WEBDAV_BASE_URL:-https://your.domain.sample/webdav/}
WEBDAV_USERNAME: ${WEBDAV_USERNAME:-admin}
WEBDAV_SYNC_FOLDER_PATH: ${WEBDAV_SYNC_FOLDER_PATH:-/}
SYNC_INTERVAL: ${SYNC_INTERVAL:-15}
IS_COMPRESSION_ENABLED: ${IS_COMPRESSION_ENABLED:-true}
IS_ENCRYPTION_ENABLED: ${IS_ENCRYPTION_ENABLED:-false}
# WebDAV sync server
webdav-sp:
container_name: webdav-sp
image: hacdias/webdav:v5.8
ports:
- '2345:2345'
volumes:
- ./webdav.yaml:/config.yml:ro
- ${WEBDAV_DATA_DIR:-./data}:/data
healthcheck:
test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider', 'http://localhost:2345/']
interval: 10s
timeout: 5s
retries: 3
start_period: 10saddress: 0.0.0.0
port: 2345
prefix: /
permissions: CRUD
# CORS configuration to allow all origins
cors:
enabled: true
credentials: true
allowed_headers:
- '*'
allowed_hosts:
- '*'
allowed_methods:
- GET
- HEAD
- POST
- PUT
- DELETE
- OPTIONS
- PROPFIND
- PROPPATCH
- MKCOL
- COPY
- MOVE
- LOCK
- UNLOCK
exposed_headers:
- '*'
users:
- username: YourBestUsername
password: YourBestPassword
directory: /dataupstream sp_app {
server 127.0.0.1:8888;
}
upstream sp_webdav {
server 127.0.0.1:2345;
}
server {
server_name your.domain.sample;
#Log
access_log /var/log/nginx/your.domain.sample.access.log;
error_log /var/log/nginx/your.domain.sample.error.log warn;
location / {
proxy_pass http://sp_app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_http_version 1.1;
chunked_transfer_encoding off;
}
location /webdav/ {
proxy_pass http://sp_webdav/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
proxy_http_version 1.1;
chunked_transfer_encoding off;
}
# listen 443 ssl;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/your.domain.sample/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.domain.sample/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = your.domain.sample) {
return 301 https://$host$request_uri;
}
server_name your.domain.sample;
listen 80;
return 404;
}