Office intermediate ⏱ 45 minutes

OnlyOffice: Self-Hosted Document Suite

Microsoft Office-compatible document editing. Integration with Nextcloud and other platforms.

By Homelab Team • 2025-01-15
#onlyoffice#documents#office#collaboration#docker

Introduction

ONLYOFFICE Document Server is a powerful, self-hosted office suite that provides comprehensive document editing capabilities for your homelab. Think of it as your own private Microsoft Office 365 or Google Workspace, but running entirely on your infrastructure with complete data control.

What is ONLYOFFICE?

ONLYOFFICE Document Server is an open-source office suite that enables viewing, editing, and collaborative editing of text documents, spreadsheets, and presentations directly in your web browser. It supports all major Microsoft Office formats including DOCX, XLSX, and PPTX, making it a seamless replacement for cloud-based office suites.

Why Self-Host ONLYOFFICE?

Complete Data Privacy

When you self-host ONLYOFFICE, every document stays on your infrastructure. There’s no third-party accessing your sensitive business plans, financial spreadsheets, or personal documents. This is particularly crucial for businesses handling confidential information or individuals concerned about privacy.

Zero Licensing Costs

Microsoft 365 costs $6-22 per user per month. Google Workspace ranges from $6-18 per user per month. For a small team of 5 users, you’re looking at $360-1,320 annually. ONLYOFFICE Community Edition is completely free for self-hosting, with unlimited users.

Real-Time Collaboration

Multiple users can edit the same document simultaneously with real-time updates. Changes appear instantly for all collaborators, complete with user cursors, comments, and tracked changes - just like Google Docs.

Microsoft Office Compatibility

ONLYOFFICE provides the highest fidelity Microsoft Office format support among open-source alternatives. Complex documents with formatting, macros, and embedded objects maintain their structure better than other solutions.

ONLYOFFICE vs Alternatives

FeatureONLYOFFICECollaboraLibreOffice OnlineMicrosoft 365
MS Office CompatibilityExcellentGoodFairPerfect
Real-time CollaborationYesYesLimitedYes
Self-HostedYesYesYesNo
Cost (5 users)FreeFreeFree$360-1,100/year
Mobile EditingYesYesLimitedYes
Nextcloud IntegrationExcellentExcellentGoodN/A
PerformanceFastMediumMediumFast

Architecture Overview

Understanding the ONLYOFFICE architecture helps you deploy and troubleshoot effectively:

┌─────────────────────────────────────────────┐
│          Users (Web Browsers)               │
└────────────────┬────────────────────────────┘
                 │
          ┌──────▼──────┐
          │ Reverse Proxy│ (Nginx/Traefik)
          │   + SSL      │
          └──────┬──────┘
                 │
    ┌────────────┼────────────┐
    │            │            │
┌───▼────┐  ┌───▼─────┐  ┌──▼──────┐
│Nextcloud│  │ONLYOFFICE│  │ Other  │
│   or    │  │ Document │  │  Apps  │
│Platform │  │  Server  │  │        │
└───┬────┘  └────┬─────┘  └────────┘
    │            │
    └────────────┼────────────┐
                 │            │
          ┌──────▼──────┐ ┌──▼──────┐
          │  PostgreSQL │ │ RabbitMQ│
          │  (Optional) │ │(Optional)│
          └─────────────┘ └─────────┘

Components:

  • Document Server: Core service handling document editing, conversion, and collaboration
  • Nextcloud/Integration Platform: File management system that stores documents
  • PostgreSQL: Database for document history and collaboration data (optional, for production)
  • RabbitMQ: Message queue for handling concurrent editing sessions (optional, for production)
  • Reverse Proxy: HTTPS termination and routing

Prerequisites

Before deploying ONLYOFFICE, ensure you have:

  • Docker and Docker Compose installed
  • 4GB RAM minimum (8GB recommended for production)
  • 2 CPU cores minimum
  • 20GB storage space
  • Domain name with DNS access (for SSL certificates)
  • Basic understanding of Docker networking
  • Reverse proxy setup (Nginx, Traefik, or Caddy)

Basic Deployment: Standalone ONLYOFFICE

Let’s start with a basic ONLYOFFICE deployment that can be integrated with various platforms.

Step 1: Create Project Directory

# Create directory structure
mkdir -p ~/onlyoffice && cd ~/onlyoffice

# Create environment file
cat > .env <<EOF
# ONLYOFFICE Configuration
ONLYOFFICE_JWT_SECRET=your-super-secret-jwt-token-change-this
ONLYOFFICE_JWT_HEADER=Authorization

# PostgreSQL Configuration (optional)
POSTGRES_DB=onlyoffice
POSTGRES_USER=onlyoffice
POSTGRES_PASSWORD=your-secure-postgres-password

# Domain Configuration
DOMAIN=office.yourdomain.com
EOF

# Secure the environment file
chmod 600 .env

Step 2: Basic Docker Compose Configuration

Create docker-compose.yml:

version: '3.8'

services:
  onlyoffice:
    image: onlyoffice/documentserver:latest
    container_name: onlyoffice-documentserver
    restart: unless-stopped
    environment:
      # JWT Configuration for security
      - JWT_ENABLED=true
      - JWT_SECRET=${ONLYOFFICE_JWT_SECRET}
      - JWT_HEADER=${ONLYOFFICE_JWT_HEADER}

      # Performance settings
      - WOPI_ENABLED=false
      - USE_UNAUTHORIZED_STORAGE=false

    ports:
      - "8080:80"

    volumes:
      # Persist data, logs, and configuration
      - onlyoffice_data:/var/www/onlyoffice/Data
      - onlyoffice_logs:/var/log/onlyoffice
      - onlyoffice_cache:/var/lib/onlyoffice
      - onlyoffice_fonts:/usr/share/fonts

    networks:
      - onlyoffice-net

volumes:
  onlyoffice_data:
  onlyoffice_logs:
  onlyoffice_cache:
  onlyoffice_fonts:

networks:
  onlyoffice-net:
    driver: bridge

Step 3: Launch ONLYOFFICE

# Start the service
docker-compose up -d

# Check logs
docker-compose logs -f onlyoffice

# Verify it's running
curl http://localhost:8080/healthcheck

Access ONLYOFFICE at http://localhost:8080 - you should see a welcome screen.

Production Deployment with PostgreSQL

For production use with better performance and scalability, add PostgreSQL:

version: '3.8'

services:
  # PostgreSQL Database
  postgresql:
    image: postgres:15-alpine
    container_name: onlyoffice-postgres
    restart: unless-stopped
    environment:
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    volumes:
      - postgresql_data:/var/lib/postgresql/data
    networks:
      - onlyoffice-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  # RabbitMQ for message queuing
  rabbitmq:
    image: rabbitmq:3-management-alpine
    container_name: onlyoffice-rabbitmq
    restart: unless-stopped
    environment:
      - RABBITMQ_DEFAULT_USER=onlyoffice
      - RABBITMQ_DEFAULT_PASS=${ONLYOFFICE_JWT_SECRET}
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq
    networks:
      - onlyoffice-net
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  # ONLYOFFICE Document Server
  onlyoffice:
    image: onlyoffice/documentserver:latest
    container_name: onlyoffice-documentserver
    restart: unless-stopped
    depends_on:
      postgresql:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
    environment:
      # Database Configuration
      - DB_TYPE=postgres
      - DB_HOST=postgresql
      - DB_PORT=5432
      - DB_NAME=${POSTGRES_DB}
      - DB_USER=${POSTGRES_USER}
      - DB_PWD=${POSTGRES_PASSWORD}

      # RabbitMQ Configuration
      - AMQP_URI=amqp://onlyoffice:${ONLYOFFICE_JWT_SECRET}@rabbitmq

      # JWT Configuration
      - JWT_ENABLED=true
      - JWT_SECRET=${ONLYOFFICE_JWT_SECRET}
      - JWT_HEADER=${ONLYOFFICE_JWT_HEADER}

      # Performance Tuning
      - WOPI_ENABLED=false
      - USE_UNAUTHORIZED_STORAGE=false

    ports:
      - "8080:80"

    volumes:
      - onlyoffice_data:/var/www/onlyoffice/Data
      - onlyoffice_logs:/var/log/onlyoffice
      - onlyoffice_cache:/var/lib/onlyoffice
      - onlyoffice_fonts:/usr/share/fonts

    networks:
      - onlyoffice-net

volumes:
  postgresql_data:
  rabbitmq_data:
  onlyoffice_data:
  onlyoffice_logs:
  onlyoffice_cache:
  onlyoffice_fonts:

networks:
  onlyoffice-net:
    driver: bridge

Nextcloud Integration

One of ONLYOFFICE’s most powerful features is seamless integration with Nextcloud. Here’s how to set it up.

Option 1: Using Docker Compose Network

If you’re running Nextcloud in Docker, add ONLYOFFICE to the same network:

# In your Nextcloud docker-compose.yml, add the network
networks:
  nextcloud-net:
    external: true

# In your ONLYOFFICE docker-compose.yml
networks:
  onlyoffice-net:
    external: true
    name: nextcloud_nextcloud-net

Option 2: Complete Nextcloud + ONLYOFFICE Stack

Here’s a complete stack with both services:

version: '3.8'

services:
  # MariaDB for Nextcloud
  nextcloud-db:
    image: mariadb:11
    container_name: nextcloud-db
    restart: unless-stopped
    command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
    environment:
      - MYSQL_ROOT_PASSWORD=secure-root-password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=secure-nextcloud-password
    volumes:
      - nextcloud_db:/var/lib/mysql
    networks:
      - collaboration-net

  # Redis Cache
  nextcloud-redis:
    image: redis:7-alpine
    container_name: nextcloud-redis
    restart: unless-stopped
    networks:
      - collaboration-net

  # Nextcloud
  nextcloud:
    image: nextcloud:29-fpm-alpine
    container_name: nextcloud
    restart: unless-stopped
    depends_on:
      - nextcloud-db
      - nextcloud-redis
      - onlyoffice
    environment:
      - MYSQL_HOST=nextcloud-db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=secure-nextcloud-password
      - REDIS_HOST=nextcloud-redis
    volumes:
      - nextcloud_app:/var/www/html
      - nextcloud_data:/var/www/html/data
    networks:
      - collaboration-net

  # Nextcloud Web Server
  nextcloud-web:
    image: nginx:alpine
    container_name: nextcloud-web
    restart: unless-stopped
    depends_on:
      - nextcloud
    ports:
      - "8081:80"
    volumes:
      - nextcloud_app:/var/www/html:ro
      - ./nextcloud-nginx.conf:/etc/nginx/nginx.conf:ro
    networks:
      - collaboration-net

  # PostgreSQL for ONLYOFFICE
  onlyoffice-db:
    image: postgres:15-alpine
    container_name: onlyoffice-db
    restart: unless-stopped
    environment:
      - POSTGRES_DB=onlyoffice
      - POSTGRES_USER=onlyoffice
      - POSTGRES_PASSWORD=secure-onlyoffice-password
    volumes:
      - onlyoffice_db:/var/lib/postgresql/data
    networks:
      - collaboration-net

  # ONLYOFFICE Document Server
  onlyoffice:
    image: onlyoffice/documentserver:latest
    container_name: onlyoffice
    restart: unless-stopped
    depends_on:
      - onlyoffice-db
    environment:
      - DB_TYPE=postgres
      - DB_HOST=onlyoffice-db
      - DB_PORT=5432
      - DB_NAME=onlyoffice
      - DB_USER=onlyoffice
      - DB_PWD=secure-onlyoffice-password
      - JWT_ENABLED=true
      - JWT_SECRET=your-jwt-secret-token
      - JWT_HEADER=Authorization
    ports:
      - "8080:80"
    volumes:
      - onlyoffice_data:/var/www/onlyoffice/Data
      - onlyoffice_logs:/var/log/onlyoffice
    networks:
      - collaboration-net

volumes:
  nextcloud_db:
  nextcloud_app:
  nextcloud_data:
  onlyoffice_db:
  onlyoffice_data:
  onlyoffice_logs:

networks:
  collaboration-net:
    driver: bridge

Configure Nextcloud Integration

After both services are running:

# Install ONLYOFFICE app in Nextcloud
docker exec -u www-data nextcloud php occ app:install onlyoffice

# Configure ONLYOFFICE server URL
docker exec -u www-data nextcloud php occ config:system:set onlyoffice DocumentServerUrl --value="http://onlyoffice/"

# Set JWT secret (must match ONLYOFFICE configuration)
docker exec -u www-data nextcloud php occ config:app:set onlyoffice jwt_secret --value="your-jwt-secret-token"

# Enable JWT verification
docker exec -u www-data nextcloud php occ config:app:set onlyoffice jwt_header --value="Authorization"

Alternatively, configure via web UI:

  1. Log into Nextcloud as admin
  2. Go to Settings > Administration > ONLYOFFICE
  3. Enter Document Server address: http://onlyoffice/
  4. Enter JWT Secret: your-jwt-secret-token
  5. Click Save

Now when you open any Office document in Nextcloud, it will open in ONLYOFFICE!

Reverse Proxy Setup

For production deployment with HTTPS, configure your reverse proxy.

Nginx Configuration

# /etc/nginx/sites-available/onlyoffice.conf

upstream onlyoffice {
    server localhost:8080;
}

server {
    listen 80;
    server_name office.yourdomain.com;

    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name office.yourdomain.com;

    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/office.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/office.yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Increase upload size for documents
    client_max_body_size 100M;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;

    location / {
        proxy_pass http://onlyoffice;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;

        # WebSocket support
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

Traefik Configuration (Labels)

Add these labels to your ONLYOFFICE service:

services:
  onlyoffice:
    # ... other configuration ...
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.onlyoffice.rule=Host(`office.yourdomain.com`)"
      - "traefik.http.routers.onlyoffice.entrypoints=websecure"
      - "traefik.http.routers.onlyoffice.tls.certresolver=letsencrypt"
      - "traefik.http.services.onlyoffice.loadbalancer.server.port=80"

      # WebSocket support
      - "traefik.http.middlewares.onlyoffice-headers.headers.customrequestheaders.X-Forwarded-Proto=https"

Caddy Configuration

office.yourdomain.com {
    reverse_proxy onlyoffice:80 {
        header_up X-Forwarded-Proto {scheme}
        header_up X-Forwarded-For {remote}
    }
}

Performance Tuning

Optimize ONLYOFFICE for better performance in your homelab.

Memory and CPU Optimization

Create a custom configuration file:

# Create custom configuration directory
mkdir -p ./onlyoffice-config

# Create local.json configuration
cat > ./onlyoffice-config/local.json <<EOF
{
  "services": {
    "CoAuthoring": {
      "sql": {
        "max_allowed_packet": 1048575
      },
      "redis": {
        "name": "redis",
        "host": "redis",
        "port": 6379
      },
      "server": {
        "port": 8000,
        "workerpercpu": 1
      },
      "autoAssembly": {
        "enable": true,
        "interval": "5m"
      }
    }
  },
  "queue": {
    "visibilityTimeout": 300,
    "retentionPeriod": 900
  },
  "storage": {
    "fs": {
      "secretString": "your-secret-string"
    }
  }
}
EOF

Add Redis for caching:

services:
  # Redis cache for ONLYOFFICE
  redis:
    image: redis:7-alpine
    container_name: onlyoffice-redis
    restart: unless-stopped
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
    networks:
      - onlyoffice-net

  onlyoffice:
    # ... other configuration ...
    depends_on:
      - redis
    volumes:
      - ./onlyoffice-config/local.json:/etc/onlyoffice/documentserver/local.json

Concurrent Users Optimization

For handling multiple simultaneous editors:

# Enter the ONLYOFFICE container
docker exec -it onlyoffice-documentserver bash

# Edit configuration
nano /etc/onlyoffice/documentserver/local.json

Add these settings:

{
  "services": {
    "CoAuthoring": {
      "server": {
        "edit_singleton": false
      },
      "requestDefaults": {
        "timeout": 120000
      }
    }
  },
  "FileConverter": {
    "converter": {
      "maxDownloadBytes": 104857600,
      "downloadTimeout": 120000
    }
  }
}

Font Installation for Better Compatibility

Add custom fonts for better document rendering:

# Create fonts directory
mkdir -p ./custom-fonts

# Download Microsoft fonts (if licensed)
# Or use open alternatives like Liberation fonts

# Add to docker-compose.yml
volumes:
  - ./custom-fonts:/usr/share/fonts/truetype/custom:ro

Then regenerate font cache:

docker exec onlyoffice-documentserver fc-cache -f -v
docker restart onlyoffice-documentserver

Security Hardening

Enable JWT Authentication

JWT (JSON Web Token) is essential for security. Always enable it:

environment:
  - JWT_ENABLED=true
  - JWT_SECRET=your-super-long-random-secret-at-least-32-characters
  - JWT_HEADER=Authorization
  - JWT_IN_BODY=true

Generate a secure JWT secret:

openssl rand -hex 32

Firewall Configuration

Restrict access to ONLYOFFICE:

# Allow only from your network
sudo ufw allow from 192.168.1.0/24 to any port 8080

# Or allow through reverse proxy only
sudo ufw deny 8080

Regular Updates

Keep ONLYOFFICE updated:

# Pull latest image
docker-compose pull onlyoffice

# Recreate container
docker-compose up -d onlyoffice

# Check version
docker exec onlyoffice-documentserver documentserver-version.sh

Monitoring and Maintenance

Health Checks

Monitor ONLYOFFICE health:

# Health check endpoint
curl http://localhost:8080/healthcheck

# Expected response: {"status":"OK"}

# Detailed status
docker exec onlyoffice-documentserver supervisorctl status

Log Management

Access and manage logs:

# View all logs
docker-compose logs -f onlyoffice

# View specific service logs
docker exec onlyoffice-documentserver tail -f /var/log/onlyoffice/documentserver/converter/out.log
docker exec onlyoffice-documentserver tail -f /var/log/onlyoffice/documentserver/docservice/out.log

# Clear old logs
docker exec onlyoffice-documentserver find /var/log/onlyoffice -name "*.log" -mtime +30 -delete

Backup Strategy

Backup important data:

# Create backup script
cat > ~/onlyoffice-backup.sh <<'EOF'
#!/bin/bash
BACKUP_DIR="/mnt/backups/onlyoffice"
DATE=$(date +%Y%m%d_%H%M%S)

# Backup volumes
docker run --rm   -v onlyoffice_onlyoffice_data:/data:ro   -v $BACKUP_DIR:/backup   alpine tar czf /backup/onlyoffice-data-$DATE.tar.gz -C /data .

# Backup database if using PostgreSQL
docker exec onlyoffice-postgres pg_dump -U onlyoffice onlyoffice > $BACKUP_DIR/onlyoffice-db-$DATE.sql

# Remove backups older than 30 days
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
find $BACKUP_DIR -name "*.sql" -mtime +30 -delete

echo "Backup completed: $DATE"
EOF

chmod +x ~/onlyoffice-backup.sh

# Schedule weekly backups
crontab -e
# Add: 0 2 * * 0 /home/user/onlyoffice-backup.sh

Troubleshooting

Issue: Documents Won’t Open

# Check JWT configuration matches in both ONLYOFFICE and integration
docker exec onlyoffice-documentserver grep -r "JWT_SECRET" /etc/onlyoffice/

# Verify service is running
curl http://localhost:8080/healthcheck

# Check logs for errors
docker-compose logs onlyoffice | grep -i error

Issue: Slow Document Loading

# Check resource usage
docker stats onlyoffice-documentserver

# Increase memory limits
docker-compose down
# Edit docker-compose.yml, add:
# deploy:
#   resources:
#     limits:
#       memory: 4G
docker-compose up -d

# Add Redis cache if not present

Issue: Connection Refused from Nextcloud

# Verify both services are on same network
docker network inspect onlyoffice_onlyoffice-net

# Test connectivity from Nextcloud container
docker exec nextcloud-app curl http://onlyoffice/healthcheck

# Check firewall rules
sudo ufw status

Issue: “Download Failed” Error

This usually indicates JWT mismatch:

# Ensure JWT_SECRET matches in:
# 1. ONLYOFFICE environment variables
# 2. Nextcloud ONLYOFFICE app settings

# Regenerate JWT secret
NEW_SECRET=$(openssl rand -hex 32)
echo "New JWT Secret: $NEW_SECRET"

# Update in both places
docker exec -u www-data nextcloud php occ config:app:set onlyoffice jwt_secret --value="$NEW_SECRET"

# Update docker-compose.yml and restart

Advanced Features

Mobile Editing

ONLYOFFICE supports mobile editing through responsive web interface:

  • Access through mobile browser at your ONLYOFFICE URL
  • Full editing capabilities on tablets
  • View-only mode optimized for smartphones
  • Native mobile apps available for iOS and Android (ONLYOFFICE Documents app)

Custom Branding

Customize ONLYOFFICE appearance:

# Create custom logo directory
mkdir -p ./onlyoffice-custom

# Add your logo files (logo.png, favicon.ico)
# Then mount in docker-compose.yml:
volumes:
  - ./onlyoffice-custom/logo.png:/var/www/onlyoffice/documentserver/web-apps/apps/common/main/resources/img/header/header-logo.png
  - ./onlyoffice-custom/favicon.ico:/var/www/onlyoffice/documentserver/favicon.ico

Document Conversion API

Use ONLYOFFICE for batch document conversion:

# Convert DOCX to PDF
curl -X POST http://localhost:8080/ConvertService.ashx   -H "Content-Type: application/json"   -d '{
    "async": false,
    "filetype": "docx",
    "key": "unique-document-key",
    "outputtype": "pdf",
    "title": "document.docx",
    "url": "http://example.com/document.docx"
  }'

Conclusion

You now have a fully functional ONLYOFFICE Document Server that provides:

  • Complete Microsoft Office compatibility
  • Real-time collaborative editing
  • Secure, self-hosted document management
  • Seamless Nextcloud integration
  • Production-ready performance

Next Steps

  1. Configure mobile apps for remote access
  2. Set up automated backups
  3. Integrate with other platforms (ownCloud, Seafile)
  4. Customize branding and themes
  5. Implement monitoring with Prometheus/Grafana

Resources

Your self-hosted office suite is ready for production use!