Sign inSign up

certyiknofetch/cowrite

By certyiknofetch

Updated 3 months ago

Image
0

550

certyiknofetch/cowrite repository overview

Cowrite

Beautiful note-taking app with real-time collaboration, file attachments, OnlyOffice document editing, version history, sharing, 2FA, and more.

Features

  • Rich text editing via Quill editor with formatting, tables, images, and embeds
  • Real-time collaboration using Socket.IO — multiple users can edit the same note simultaneously
  • OnlyOffice integration — view and edit DOCX, XLSX, PPTX, ODT, ODS, ODP, and legacy Office formats directly in the browser
  • File attachments — upload, view, download, and manage files attached to any note
  • 500 MB upload limit for large file support
  • File encryption — all uploaded files are encrypted at rest using AES-256-CBC
  • Version history — every save creates a version; compare and restore previous versions
  • Share notes with other users with view/edit permissions
  • Two-factor authentication (TOTP)
  • Trash & archive — soft delete and archive notes
  • Tags & categories — organize notes with tags
  • Search across all notes with keyboard shortcut (Ctrl+K)
  • Gallery & list views for attachments
  • Dark/light theme toggle
  • ARKit & CAPTCHA for bot protection

Architecture

┌─────────────┐     ┌──────────────┐
│   Browser   │────▶│  Cowrite App │────▶ SQLite
└─────────────┘     │  (Node.js)   │
       │            └──────┬───────┘
       │                   │
       ▼                   ▼
┌─────────────┐     ┌──────────────┐
│  OnlyOffice │◀────│   Internal   │
│  Document   │     │   Proxy /oo  │
│   Server    │     └──────────────┘
└─────────────┘

The app proxies /oo/* requests to OnlyOffice's internal server. When using useDirectStorageUrls: true, OnlyOffice generates direct-storage URLs so the browser loads cached document assets directly from the public domain.

Quick Start

Prerequisites
  • Docker and Docker Compose v2
  • A reverse proxy (e.g., Nginx Proxy Manager, Caddy, Traefik) to handle SSL and domain routing
docker-compose.yml
services:
  app:
    image: certyiknofetch/cowrite:0.1
    environment:
      JWT_SECRET: <generate a 64-char hex string>
      ONLYOFFICE_SECRET: <generate a 32-char hex string>
      FILE_ENCRYPTION_KEY: <generate a 64-char hex string>
      PORT: "3000"
      APP_INTERNAL_URL: "https://your-domain.com"
      PUBLIC_OO_URL: "/oo"
      ONLYOFFICE_INTERNAL_URL: "http://onlyoffice:80"
      CORS_ORIGIN: "https://your-domain.com"
      NODE_ENV: "production"
      JSON_PAYLOAD_LIMIT: "10 MB"
      UPLOAD_FILE_LIMIT: "100 MB"
    volumes:
      - ./data:/app/data
      - ./uploads:/app/uploads
    depends_on:
      - onlyoffice
    restart: unless-stopped
    networks:
      cowrite:
        ipv4_address: 172.29.99.2

  onlyoffice:
    image: onlyoffice/documentserver:latest
    expose:
      - "80"
    entrypoint:
      - /bin/bash
      - -c
      - sed -i 's/"useDirectStorageUrls": false/"useDirectStorageUrls": true/'
        /etc/onlyoffice/documentserver/default.json
        && exec /app/ds/run-document-server.sh
    environment:
      JWT_ENABLED: "true"
      JWT_SECRET: <same as ONLYOFFICE_SECRET above>
    volumes:
      - oo_data:/var/www/onlyoffice/Data
      - oo_logs:/var/log/onlyoffice
    restart: unless-stopped
    networks:
      cowrite:
        ipv4_address: 172.29.99.3

networks:
  cowrite:
    driver: bridge
    ipam:
      config:
        - subnet: 172.29.99.0/29
          gateway: 172.29.99.1

volumes:
  oo_data:
  oo_logs:
Setup
  1. Generate secrets — run these commands to create strong random keys:

    JWT_SECRET=$(openssl rand -hex 64)
    ONLYOFFICE_SECRET=$(openssl rand -hex 32)
    FILE_ENCRYPTION_KEY=$(openssl rand -hex 64)
    
    echo "JWT_SECRET=$JWT_SECRET"
    echo "ONLYOFFICE_SECRET=$ONLYOFFICE_SECRET"
    echo "FILE_ENCRYPTION_KEY=$FILE_ENCRYPTION_KEY"
    
  2. Replace the placeholders in docker-compose.yml with the generated secrets.

  3. Configure your reverse proxy to forward https://your-domain.com to http://172.29.99.2:3000.

    For Nginx Proxy Manager:

    • Domain: your-domain.com
    • Forward Hostname: 172.29.99.2
    • Forward Port: 3000
    • Enable SSL
    • Under Advanced, add:
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      
  4. Start the stack:

    docker compose up -d
    
  5. Open https://your-domain.com and register your account.

Port Mapping

The compose file uses a static private subnet (172.29.99.0/29) with no host port exposure:

ServiceInternal IPPort
App172.29.99.23000
OnlyOffice172.29.99.380

Your reverse proxy runs on the host network and proxies requests to these static IPs. This ensures the proxy never breaks on container restart (Docker's bridge network assigns the same IP via ipam config).

Environment Variables

App
VariableRequiredDefaultDescription
JWT_SECRETYes64-char hex string for JWT signing
ONLYOFFICE_SECRETYes32-char hex string shared with OnlyOffice
FILE_ENCRYPTION_KEYYes64-char hex string for AES-256-CBC file encryption
PORTNo3000Internal port
APP_INTERNAL_URLYesYour public domain (e.g. https://notes.example.com)
PUBLIC_OO_URLNo/ooURL prefix for OnlyOffice proxy
ONLYOFFICE_INTERNAL_URLNohttp://onlyoffice:80Internal OnlyOffice address
CORS_ORIGINYesSame as APP_INTERNAL_URL
NODE_ENVNoproductionEnvironment mode
JSON_PAYLOAD_LIMITNo500 MBMax JSON request body size
UPLOAD_FILE_LIMITNo500 MBMax file upload size
SESSION_SECRETNoauto-generatedSession cookie secret
ALTCHA_HMAC_SECRETNorandom (reset on restart)CAPTCHA HMAC key
ALTCHA_HMAC_KEY_SECRETNorandom (reset on restart)CAPTCHA key
OnlyOffice
VariableRequiredDefaultDescription
JWT_ENABLEDNotrueEnable JWT auth
JWT_SECRETYesMust match app's ONLYOFFICE_SECRET

File Type Support

Allowed for upload
CategoryFormats
ImagesJPG, JPEG, PNG, GIF, WebP, BMP, TIFF, TIF, HEIC, HEIF, PSD, AI
AudioMP3, WAV, OGG, FLAC, AAC, WMA, M4A, Opus
VideoMP4, WebM, AVI, MKV, MOV, WMV, FLV, M4V
DocumentsPDF, DOCX, DOC, XLSX, XLS, PPTX, PPT, ODT, ODS, ODP
E-books / DataEPUB, RTF, IPYNB, TXT, CSV, JSON, XML, MD, LOG, YAML, YML
ArchivesZIP, 7z, RAR, TAR, TGZ, GZ, BZ2, XZ, APK
Viewable in browser
TypeView Action
ImagesRendered inline via <img>
AudioInline player with <audio>
VideoInline player with <video>
PDFIn-browser PDF viewer
DOCX, DOC, ODTRendered to HTML + OnlyOffice edit
XLSX, XLS, ODSRendered to HTML table + OnlyOffice edit
PPTX, PPT, ODPRendered slide preview + OnlyOffice edit
EPUBFull reader with chapter navigation (TOC sidebar)
RTFRendered with basic formatting (bold, italic, underline)
CSVSortable HTML table
MDRendered Markdown with edit toggle
IPYNBRendered notebook
Archives (ZIP, 7z, RAR, etc.)File listing with size/compressed columns
HEIC, HEIF, PSD, AIConverted to JPEG on-the-fly via Sharp
Editable
EditorFormats
OnlyOfficeDOCX, DOC, XLSX, XLS, PPTX, PPT, ODT, ODS, ODP
Text editorMD, TXT, CSV

Storage

  • Database: SQLite via sql.js — stored in ./data/ volume
  • Uploads: Encrypted files stored in ./uploads/ volume and served via streaming decryption
  • OnlyOffice data: Persistent volumes oo_data and oo_logs

Multi-Architecture

The certyiknofetch/cowrite image supports both:

  • linux/amd64 — Intel/AMD servers, desktops, VPS
  • linux/arm64 — Raspberry Pi, Mac M-series, ARM servers

Docker automatically selects the correct architecture when pulling.

Security

  • All file uploads encrypted at rest with AES-256-CBC
  • JWT authentication with configurable secrets
  • OnlyOffice document server secured with shared JWT secret
  • CAPTCHA protection via Altcha
  • Two-factor authentication (TOTP) available
  • XSS protection via sanitize-html on all rendered content
  • CSRF protection with token-based validation
  • Rate limiting on auth endpoints
  • File type validation by extension AND magic bytes (rejects mismatched content)
  • Dangerous/insecure file types blocked: SVG, HTML, JS, scripts, executables, config files

License

MIT

Tag summary

Content type

Image

Digest

sha256:dd5a3056b

Size

114.3 MB

Last updated

3 months ago

docker pull certyiknofetch/cowrite