# documentation: https://docs.documenso.com/ # slogan: Document signing, finally open source # category: productivity # tags: signing, opensource, document, pdf, e-signature, digital-signature, document-signing, pdf-signing, docusign # logo: svgs/documenso.png # port: 3000 services: documenso: image: documenso/documenso:v1.12.10 # Released at Oct 9, 2025 depends_on: database: condition: service_healthy environment: - SERVICE_URL_DOCUMENSO_3000 - NEXTAUTH_URL=${SERVICE_URL_DOCUMENSO} - NEXTAUTH_SECRET=${SERVICE_BASE64_AUTHSECRET} - NEXT_PRIVATE_ENCRYPTION_KEY=${SERVICE_BASE64_ENCRYPTIONKEY} - NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=${SERVICE_BASE64_SECONDARYENCRYPTIONKEY} - NEXT_PUBLIC_WEBAPP_URL=${SERVICE_URL_DOCUMENSO} - NEXT_PRIVATE_RESEND_API_KEY=${NEXT_PRIVATE_RESEND_API_KEY} - NEXT_PRIVATE_SMTP_TRANSPORT=${NEXT_PRIVATE_SMTP_TRANSPORT} - NEXT_PRIVATE_SMTP_HOST=${NEXT_PRIVATE_SMTP_HOST} - NEXT_PRIVATE_SMTP_PORT=${NEXT_PRIVATE_SMTP_PORT} - NEXT_PRIVATE_SMTP_USERNAME=${NEXT_PRIVATE_SMTP_USERNAME} - NEXT_PRIVATE_SMTP_PASSWORD=${NEXT_PRIVATE_SMTP_PASSWORD} - NEXT_PRIVATE_SMTP_FROM_NAME=${NEXT_PRIVATE_SMTP_FROM_NAME} - NEXT_PRIVATE_SMTP_FROM_ADDRESS=${NEXT_PRIVATE_SMTP_FROM_ADDRESS} - NEXT_PRIVATE_DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@database/${POSTGRES_DB:-documenso-db}?schema=public - NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://${SERVICE_USER_POSTGRES}:${SERVICE_PASSWORD_POSTGRES}@database/${POSTGRES_DB:-documenso-db}?schema=public - NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=/app/apps/remix/certs/certificate.p12 - NEXT_PRIVATE_SIGNING_PASSPHRASE=${SERVICE_PASSWORD_DOCUMENSO} - NEXT_PRIVATE_SIGNING_TRANSPORT=local - NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=/app/certs/cert.p12 - NEXT_PRIVATE_SIGNING_LOCAL_FILE_PASSPHRASE=${SERVICE_PASSWORD_DOCUMENSO} - CERT_VALID_DAYS=${CERT_VALID_DAYS:-365} - CERT_INFO_COUNTRY_NAME=${CERT_INFO_COUNTRY_NAME:-DO} - CERT_INFO_STATE_OR_PROVIDENCE=${CERT_INFO_STATE_OR_PROVIDENCE:-Santiago} - CERT_INFO_LOCALITY_NAME=${CERT_INFO_LOCALITY_NAME:-Santiago} - CERT_INFO_ORGANIZATION_NAME=${CERT_INFO_ORGANIZATION_NAME:-Example INC} - CERT_INFO_ORGANIZATIONAL_UNIT=${CERT_INFO_ORGANIZATIONAL_UNIT:-IT Department} - CERT_INFO_EMAIL=${CERT_INFO_EMAIL:-example@gmail.com} - NEXT_PUBLIC_DISABLE_SIGNUP=${DISABLE_LOGIN:-false} - SERVICE_PASSWORD_DOCUMENSO=${SERVICE_PASSWORD_DOCUMENSO:-} healthcheck: test: - CMD-SHELL - "wget -q -O - http://documenso:3000/ | grep -q 'Sign in to your account'" interval: 2s timeout: 10s retries: 20 entrypoint: - /bin/sh - -c - | CERT_PASSPHRASE="$${NEXT_PRIVATE_SIGNING_LOCAL_FILE_PASSPHRASE}" PASSPHRASE_FILE="/tmp/cert_passphrase" # Save original working directory ORIGINAL_DIR="$$(pwd)" # Find openssl binary (should be available in v1.12.10+) OPENSSL_CMD="$$(which openssl 2>/dev/null || command -v openssl 2>/dev/null || echo '/usr/bin/openssl')" # Verify openssl is available if ! $$OPENSSL_CMD version >/dev/null 2>&1; then echo "Error: OpenSSL not found. Please use Documenso image v1.12.10 or later." exit 1 fi # Create certificate directory - use /app/certs (writable by user 1001) CERT_DIR="/app/certs" mkdir -p "$$CERT_DIR" || { # Fallback to tmp if app directory not writable CERT_DIR="/tmp/certs" mkdir -p "$$CERT_DIR" echo "Warning: Using fallback directory: $$CERT_DIR" } # Create passphrase file for secure handling (prevents exposure in process list) # This avoids shell word-splitting issues and prevents passphrase from appearing in ps/process list echo -n "$$CERT_PASSPHRASE" > "$$PASSPHRASE_FILE" chmod 600 "$$PASSPHRASE_FILE" touch /tmp/cert_info_path cat < /tmp/cert_info_path [ req ] distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] C = ${CERT_INFO_COUNTRY_NAME} ST = ${CERT_INFO_STATE_OR_PROVIDENCE} L = ${CERT_INFO_LOCALITY_NAME} O = ${CERT_INFO_ORGANIZATION_NAME} OU = ${CERT_INFO_ORGANIZATIONAL_UNIT} CN = ${SERVICE_URL_DOCUMENSO} emailAddress = ${CERT_INFO_EMAIL} EOF cd "$$CERT_DIR" $$OPENSSL_CMD genrsa -out private.key 2048 $$OPENSSL_CMD req \ -new \ -x509 \ -key private.key \ -out certificate.crt \ -days $${CERT_VALID_DAYS} \ -config /tmp/cert_info_path # Create P12 certificate using file-based passphrase (prevents exposure in process list) # Private key is not encrypted, so we only need -passout (not -passin) $$OPENSSL_CMD pkcs12 \ -export \ -out cert.p12 \ -inkey private.key \ -in certificate.crt \ -legacy \ -passout file:"$$PASSPHRASE_FILE" # Clean up passphrase file immediately after use rm -f "$$PASSPHRASE_FILE" # Set permissions (may fail if not root, but will work in Coolify) chown 1001:1001 cert.p12 private.key certificate.crt 2>/dev/null || true chmod 400 cert.p12 private.key certificate.crt # Update environment variable if directory changed if [ "$$CERT_DIR" != "/app/certs" ]; then export NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH="$$CERT_DIR/cert.p12" fi # Return to original directory before starting application cd "$$ORIGINAL_DIR" ./start.sh database: image: postgres:17 environment: - POSTGRES_USER=${SERVICE_USER_POSTGRES} - POSTGRES_PASSWORD=${SERVICE_PASSWORD_POSTGRES} - POSTGRES_DB=${POSTGRES_DB:-documenso-db} volumes: - documenso_postgresql_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 20s retries: 10