#!/usr/bin/env bash # Copyright (c) 2021-2026 community-scripts ORG # Author: MickLesk (CanbiZ) # License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE # Source: https://github.com/toeverything/AFFiNE source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" color verb_ip6 catch_errors setting_up_container network_check update_os msg_info "Installing Dependencies" $STD apt install -y \ build-essential \ git \ pkg-config \ openssl \ libssl-dev \ libjemalloc2 \ redis-server \ nginx msg_ok "Installed Dependencies" PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql PG_DB_NAME="affine" PG_DB_USER="affine" setup_postgresql_db NODE_VERSION="22" setup_nodejs setup_rust import_local_ip fetch_and_deploy_gh_release "affine_app" "toeverything/AFFiNE" "tarball" "latest" "/opt/affine" msg_info "Setting up Directories" rm -rf /root/.affine mkdir -p /root/.affine/{storage,config} msg_ok "Set up Directories" msg_info "Configuring Environment" SECRET_KEY=$(openssl rand -hex 32) cat </opt/affine/.env NODE_ENV=production AFFINE_SERVER_PORT=3010 AFFINE_SERVER_HOST=${LOCAL_IP} AFFINE_SERVER_EXTERNAL_URL=http://${LOCAL_IP}:3010 DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME} REDIS_SERVER_HOST=localhost REDIS_SERVER_PORT=6379 AFFINE_INDEXER_ENABLED=false NODE_OPTIONS=--max-old-space-size=6144 SECRET_KEY=${SECRET_KEY} EOF msg_ok "Configured Environment" msg_info "Building AFFiNE (this will take 20-30 minutes)" cd /opt/affine source /root/.profile export PATH="/root/.cargo/bin:$PATH" set -a && source /opt/affine/.env && set +a export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 export VITE_CORE_COMMIT_SHA="v0.25.7" # Initialize git repo (required for build process) git init -q git config user.email "build@local" git config user.name "Build" git add -A git commit -q -m "initial" # Force Turbo to run sequentially mkdir -p /opt/affine/.turbo cat </opt/affine/.turbo/config.json { "concurrency": 1 } TURBO $STD corepack enable $STD corepack prepare yarn@4.12.0 --activate $STD yarn config set enableTelemetry 0 export NODE_OPTIONS="--max-old-space-size=4096" export TSC_COMPILE_ON_ERROR=true $STD yarn install # Make TypeScript available via npx/yarn exec $STD npm install -g typescript $STD yarn affine @affine/native build $STD yarn affine @affine/server-native build # Create architecture-specific symlinks for server-native ln -sf /opt/affine/packages/backend/native/server-native.node \ /opt/affine/packages/backend/native/server-native.x64.node ln -sf /opt/affine/packages/backend/native/server-native.node \ /opt/affine/packages/backend/native/server-native.arm64.node ln -sf /opt/affine/packages/backend/native/server-native.node \ /opt/affine/packages/backend/native/server-native.armv7.node $STD yarn affine init msg_info "Building packages sequentially (this takes a while)" $STD yarn affine build -p @affine/reader $STD yarn affine build -p @affine/server # Web build needs more memory export NODE_OPTIONS="--max-old-space-size=4096" $STD yarn affine build -p @affine/web # Copy web assets to server static directory mkdir -p /opt/affine/packages/backend/server/static cp -r /opt/affine/packages/frontend/apps/web/dist/* /opt/affine/packages/backend/server/static/ # Create empty mobile manifest (server expects it but we don't build mobile) mkdir -p /opt/affine/packages/backend/server/static/mobile cat <<'MANIFEST' >/opt/affine/packages/backend/server/static/mobile/assets-manifest.json {"publicPath":"/","js":[],"css":[],"gitHash":"","description":""} MANIFEST # Copy selfhost.html to admin directory mkdir -p /opt/affine/packages/backend/server/static/admin cp /opt/affine/packages/backend/server/static/selfhost.html \ /opt/affine/packages/backend/server/static/admin/selfhost.html msg_ok "Built AFFiNE" msg_info "Running Initial Migration" cd /opt/affine/packages/backend/server set -a && source /opt/affine/.env && set +a $STD node ./scripts/self-host-predeploy.js msg_ok "Ran Initial Migration" msg_info "Creating Services" cat </etc/systemd/system/affine-web.service [Unit] Description=AFFiNE Web Server After=network.target postgresql.service redis-server.service Requires=postgresql.service redis-server.service [Service] Type=simple WorkingDirectory=/opt/affine/packages/backend/server EnvironmentFile=/opt/affine/.env Environment=LD_PRELOAD=libjemalloc.so.2 ExecStart=/usr/bin/node ./dist/main.js Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF cat </etc/systemd/system/affine-worker.service [Unit] Description=AFFiNE Background Worker After=network.target postgresql.service redis-server.service affine-web.service Requires=postgresql.service redis-server.service [Service] Type=simple WorkingDirectory=/opt/affine/packages/backend/server EnvironmentFile=/opt/affine/.env Environment=LD_PRELOAD=libjemalloc.so.2 ExecStart=/usr/bin/node ./dist/main.js --worker Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF systemctl enable -q --now redis-server affine-web affine-worker msg_ok "Created Services" msg_info "Configuring Nginx" cat </etc/nginx/sites-available/affine.conf upstream affine_backend { server 127.0.0.1:3010; } server { listen 80; server_name _; client_max_body_size 100M; location / { proxy_pass http://affine_backend; proxy_http_version 1.1; 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 Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_redirect off; proxy_buffering off; } } EOF ln -sf /etc/nginx/sites-available/affine.conf /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default systemctl enable -q --now nginx msg_ok "Configured Nginx" motd_ssh customize cleanup_lxc