NextCloud and OnlyOffice via Docker

From WikiMLT

Here is a short step-by-step man­u­al: How to set­up On­ly­Of­fice Doc­u­ment Serv­er Dock­er con­tain­er and proxy it by Apache2 for us­age via NextCloud.

In­stall Dock­er

Ac­cord­ing to the Dock­er and Dock­er-com­pose in­stal­la­tion read the guide Dock­er Ba­sic Set­up.

Set­up the On­ly­Of­fice Dock­er Con­tain­er

Cre­ate a di­rec­to­ry where the con­fig­u­ra­tion file docker-compose.yaml and the per­sis­tent vol­umes will live.

mkdir /home/docker/onlyoffice
cd /home/docker/onlyoffice

Pull the Dock­er im­ages and run an On­ly­Of­fice con­tain­er for a first time

sudo docker run -i -t -d -p 8081:80 --restart=always" \
-v "$PWD/DocumentServer/logs:/var/log/onlyoffice" \
-v "$PWD/DocumentServer/data:/var/www/onlyoffice/Data" \
-v "$PWD/DocumentServer/lib:/var/lib/onlyoffice" \
-v "$PWD/DocumentServer/db:/var/lib/postgresql" \
-v "$PWD/DocumentServer/usr/share/fonts:/usr/share/fonts" \
--hostname docs --name onlyoffice-docs \
onlyoffice/documentserver:latest

Test whether it works. At this point the On­ly­Of­fice doc­u­ment serv­er must be ac­ces­si­ble the brows­er, prob­a­bly you maybe need to wait about 10 sec­onds be­fore it be­come ac­ces­si­ble. Note the host port 8081 must be open (for you) with­in the host's fire­wall.

#De­tails
http://<host-ip>:8081/welcome/

En­able the in­te­grat­ed test ex­am­ples.

docker exec onlyoffice-docs supervisorctl start ds:example
docker exec onlyoffice-docs sed 's,autostart=false,autostart=true,' -i /etc/supervisor/conf.d/ds-example.conf

Now you can ac­cess the ex­am­ples at the fol­low­ing ad­dress.

http://<host-ip>:8081/example/

Ex­port the con­fig­u­ra­tion files. For some rea­son the con­fig­u­ra­tion files can­not be ex­port­ed via the vol­ume op­tion as this is done above for some oth­er di­rec­to­ries. So, if we need that, we need first to copy them man­u­al­ly.

#De­tails
sudo mkdir DocumentServer/etc
sudo docker cp onlyoffice-docs:/etc/onlyoffice DocumentServer/etc
sudo docker cp onlyoffice-docs:/etc/supervisor DocumentServer/etc

Now we can stop and prune the con­tain­er.

docker stop onlyoffice-docs
docker container prune

Now cre­ate new con­tain­er and at­tach the di­rec­to­ries with the con­fig­u­ra­tion files as vol­umes.

sudo docker run -i -t -d -p 8081:80 --restart=always \
-v "$PWD/DocumentServer/logs:/var/log/onlyoffice" \
-v "$PWD/DocumentServer/data:/var/www/onlyoffice/Data" \
-v "$PWD/DocumentServer/lib:/var/lib/onlyoffice" \
-v "$PWD/DocumentServer/db:/var/lib/postgresql" \
-v "$PWD/DocumentServer/usr/share/fonts:/usr/share/fonts" \
-v "$PWD/DocumentServer/etc/onlyoffice:/etc/onlyoffice" \
-v "$PWD/DocumentServer/etc/supervisor:/etc/supervisor" \
--hostname docs --name onlyoffice-docs \
onlyoffice/documentserver:latest

Start­ing from ver­sion 7.2, JWT (JSON Web To­ken) is en­abled by de­fault. A ran­dom se­cret is gen­er­at­ed au­to­mat­i­cal­ly if a cus­tom se­cret has not been added dur­ing in­stal­la­tion. To ob­tain the de­fault se­cret, run this com­mand:

docker exec onlyoffice-docs /var/www/onlyoffice/documentserver/npm/json \
-f /etc/onlyoffice/documentserver/local.json 'services.CoAuthoring.secret.session.string'
xd4f2PO5hdHJHjpV1NdD

You can re­place the de­fault se­cret with a cus­tom key us­ing Dock­er env. More in­for­ma­tion about JWT in the doc­u­men­ta­tion. Once again, in or­der to make the JWT per­sis­tent you need to pro­vide it via Dock­er as en­vi­ron­ment vari­able – this will be done with­in the next sec­tion.

Fi­nal­ly. Stop and prune the con­tain­er, be­cause in the next sec­tion we will cre­ate a Dock­er-com­pose con­fig­u­ra­tion file.

docker stop onlyoffice-docs
docker container prune

Man­age an On­ly­Of­fice con­tain­er by Dock­er-com­pose

Cre­ate the docker-compose.yaml file. Tweak the val­ue of the host port 8081, and the time zone TZ if it is need­ed. The most im­por­tant thing is to set an unique val­ue for JWT_SECRET, thus the JWT will be­come per­sis­tent.

nano docker-compose.yaml
# https://hub.docker.com/r/onlyoffice/documentserver/
# https://github.com/ONLYOFFICE/onlyoffice-owncloud/issues/108

version: "3.9"
services:
  onlyoffice-docs:
    container_name: onlyoffice-docs
    image: onlyoffice/documentserver:latest
    hostname: docs
    #network_mode: host
    ports:
      - "8081:80/tcp"
    environment:
      TZ: 'Europe/Sofia'
      JWT_SECRET: "xd4f2PO5hdHJHjpV1NdD"
    # Volumes store your data between container upgrades
    volumes:
      - "./DocumentServer/logs:/var/log/onlyoffice"
      - "./DocumentServer/data:/var/www/onlyoffice/Data"
      - "./DocumentServer/lib:/var/lib/onlyoffice"
      - "./DocumentServer/db:/var/lib/postgresql"
      - "./DocumentServer/usr/share/fonts:/usr/share/fonts"
      - "./DocumentServer/etc/onlyoffice:/etc/onlyoffice"
      - "./DocumentServer/etc/supervisor:/etc/supervisor"
    restart: unless-stopped

volumes:
    DocumentServer:

Down­load the Dock­er im­ages and run the con­tain­er in de­tached (per­sis­tent) mode.

docker-compose up -d

Open the On­ly­Of­fice doc­u­ment serv­er via the brows­er. Note the host port 8081 must be open (for you) with­in the host's fire­wall.

http://<host-ip>:8081/welcome/

Add Cus­tom Fonts

Here is how to in­stall Mi­crosoft Se­goe UI font fam­i­ly, but af­ter the first step the set­up process is iden­ti­cal.

cd /home/docker/onlyoffice
FONTS_DIR="." FC_CACHE="false" \
bash <(curl -s https://raw.githubusercontent.com/metalevel-tech/segoe-ui-linux/update/install.sh)

Here starts the ac­tu­al de­ploy­ment.

sudo mv Microsoft/ DocumentServer/usr/share/fonts/
sudo chown -R root:root DocumentServer/usr/share/fonts/Microsoft/
docker exec -it onlyoffice-docs /usr/bin/documentserver-generate-allfonts.sh
docker-compose down
docker-compose up -d

Then you need to flush the cache of your brows­er, at least the cached files and hard re­load the win­dow where your NextCloud is opened. Then try to ed­it some file and check the list of the avail­able fonts.

Apache2 HTTPS Re­verse Proxy

It is pos­si­ble to set-up On­ly­Of­fice to use HTTPS and cer­tain FQDN through its con­fig­u­ra­tion. How­ev­er in this sec­tion i de­scribed how to cre­ate Apache2 Re­verse proxy that will han­dle this.

First, test whether the nec­es­sary Apache2 mod­ules are en­abled. Be­low is show the list of the mod­ules re­tired for this set-up.

sudo apache2ctl -M | grep -E 'auth[nz]_core|unixd|proxy|headers|setenvif'
 unixd_module (static)          # Required
 authn_core_module (shared)     # Required
 authz_core_module (shared)     # Required
 headers_module (shared)        # Required
 proxy_module (shared)          # Required
 proxy_fcgi_module (shared)
 proxy_http_module (shared)     # Required
 proxy_http2_module (shared)
 proxy_wstunnel_module (shared) # Required
 setenvif_module (shared)       # Required

Then set­up a new vir­tu­al host as fol­low and restart Apache2. Note in this sce­nario you need a valid SSL/TLS cer­tifi­cate. In my case I'm us­ing Let's en­crypt wild­card cer­tifi­cate for the base do­main where the in­stances of NextCloud and On­ly­Of­fice are in­stalled.

sudo nano /etc/apache2/sites-enabled/docs.example.com.conf
Define docs_base_fqdn example.com
Define docs_fqdn docs.example.com
Define docs_srvr 127.0.0.1
Define docs_port 8081
Define docs_doc_root "/var/www/${docs_fqdn}"
 
<VirtualHost *:80>
    ServerName ${docs_fqdn}
    ServerAdmin admin@${docs_base_fqdn}

    ErrorLog ${APACHE_LOG_DIR}/${docs_fqdn}.error.log
    CustomLog ${APACHE_LOG_DIR}/${docs_fqdn}.access.log combined

    # Redirect Requests to HTTPS
    Redirect permanent "/" "https://${docs_fqdn}/"
</VirtualHost>

<IfModule mod_ssl.c>
<VirtualHost _default_:443>
    ServerName ${docs_fqdn}
    ServerAdmin admin@${docs_base_fqdn}

    ErrorLog ${APACHE_LOG_DIR}/${docs_fqdn}.error.log
    CustomLog ${APACHE_LOG_DIR}/${docs_fqdn}.access.log combined

    <IfModule http2_module>
        # https://httpd.apache.org/docs/2.4/mod/mod_http2.html
        # https://httpd.apache.org/docs/2.4/howto/http2.html

        Protocols h2 h2c http/1.1
        #ProtocolsHonorOrder Off
        #H2Direct on
        H2Upgrade on

        H2Push on
        # Default Priority Rule:
        # H2PushPriority *                      After 16 
        # More complex ruleset:
        H2PushPriority *                        after
        H2PushPriority text/css                 before
        H2PushPriority image/jpg                after 32
        H2PushPriority image/jpeg               after 32
        H2PushPriority image/png                after 32
        H2PushPriority application/javascript   interleaved
        <LocationMatch "^.*$">
            # Header add Link "</example.png>; rel=preload; as=image"
            # Header add Link "</style.css>; rel=preload; as=style"
            # Header add Link "</script.js>; rel=preload; as=script"
        </LocationMatch>

        # From apache2/mods-available/http2.conf
        # Since mod_http2 doesn't support the mod_logio module (which provide the %O format),
        # you may want to change your LogFormat directive as follow:
		LogFormat "%v:%p %h %l %u %t \"%r\" %>s %B \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
        LogFormat "%h %l %u %t \"%r\" %>s %B \"%{Referer}i\" \"%{User-Agent}i\"" combined
        LogFormat "%h %l %u %t \"%r\" %>s %B" common
    </IfModule>

    SSLEngine on
    #SSLCertificateFile /etc/letsencrypt/live/${docs_base_fqdn}/cert.pem
    #SSLCertificateKeyFile /etc/letsencrypt/live/${docs_base_fqdn}/privkey.pem
    #SSLCertificateChainFile /etc/letsencrypt/live/${docs_base_fqdn}/chain.pem
    SSLCertificateFile /etc/letsencrypt/live/${docs_base_fqdn}/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/${docs_base_fqdn}/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    SetEnvIf Host "^(.*)$" THE_HOST=$1

    Header edit Set-Cookie ^(.*)$ "$1; HttpOnly; Secure"
    RequestHeader setifempty X-Forwarded-Proto https
    RequestHeader setifempty X-Forwarded-Host %{THE_HOST}e

    # Reference about OnlyOffice Proxy settings
    # https://github.com/ONLYOFFICE/onlyoffice-owncloud/issues/108
    ProxyAddHeaders Off
    <Location "/">
        ProxyPass "http://${docs_srvr}:${docs_port}/"
        ProxyPassReverse "http://${docs_srvr}:${docs_port}/"
    </Location>

    ProxyPassMatch (.*)(\/websocket)$ "ws://${docs_srvr}:${docs_port}/$1$2"
    
    # DocumentRoot "${docs_doc_root}"
    # <Directory "${docs_doc_root}">
    #     DirectoryIndex index.php index.html hello.html
    #     Require all granted
    #     #Options None FollowSymLinks MultiViews
    #     Options None FollowSymLinks
    #     # AllowOverride None
    #     AllowOverride All
    #     <IfModule security2_module>
    #         #SecRuleEngine Off
    #     </IfModule>
    # </Directory>

    # Limit the acces to the URIs  /, /welcome, /example, /healthcheck
    <ifModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond "%{REMOTE_ADDR}" "!^(172\.16\.[0-9]{1,3}\.[0-9]{1,3}|0\.0\.0\.0|127\.0\.0\.[0-9]{1,3})$"
        RewriteCond "%{REQUEST_URI}" "^/(welcome.*$|example.*$|healthcheck.*$|$)"
        RewriteRule "^(.*)$" https://cloud.example.com/? [L,R=307]
    </ifModule>
</VirtualHost>
</IfModule>

Set­up NextCloud On­ly­Of­fice App

As it is shown at Screen 1, with­in the NextCloud On­ly­Of­fice App we need to pro­vide 1 the ad­dress of the doc­u­ment serv­er and 2 the JWT key.

Screen 1. Set­up NextCloud On­ly­Of­fice App. Screen 1. Setup NextCloud OnlyOffice App.

Ref­er­ences