Skip to main content

Server

Architecture and General Flow

High-Level Architecture Diagram of APEX Office Edit

Hardware Requirements

Operating System: Linux, Mac OS, Windows (any other OS that supports Docker)

Other requirements are as follows:

  • 10 users / CPU thread
  • 100 Mb RAM / user
  • 100 kbits / user

Running the APEX Office Edit Server

Docker Installation

Firstly, ensure Docker is installed on the machine. If not, install Docker.

The detailed steps to install Docker in Ubuntu can be found on:

https://docs.docker.com/engine/install/ubuntu

For other environments, refer to: https://docs.docker.com/engine/install

Docker installation can be verified with:

docker --version

It will return the output as:

Docker version <version number>, build <id>

Example: Docker version 20.10.12, build e91ed57

AOE Image

Pull the image of AOE from the official registry.

docker pull unitedcodes/apexofficeedit

AOE Container

After downloading the AOE image, a new container can be created as follows:

docker run -p 8030:8080 --name container_name -d --restart always unitedcodes/apexofficeedit

Example:

docker run -p 8030:8080 --name aoe -d --restart always unitedcodes/apexofficeedit

Please check all the available configuration options.

-p Parameter that specifies the port to use on the docker host to forward the exposed port of the container to. If a different port is desired on the docker host, this can be easily changed by changing the first number, e.g., -p 8030:8080. By default, the AOE docker container exposes port 8080 and maps it to port 8030 on the host.

--name A parameter that can be used to identify the running container. If no container name is assigned with the --name option, then the daemon generates a random name. Defining a name can be a handy way to add meaning to a container. If a name is specified, it can be used when referencing the container within a Docker network. This works for both background and foreground Docker containers.

The other general run parameters can be found on:

https://docs.docker.com/engine/reference/run

To constrain the memory and available CPU for the running container, please refer to:

https://docs.docker.com/engine/reference/run/#runtime-constraints-on-resources

Memory and CPU limitations:

ParameterDescription
-m, --memory=""Memory limit (format: <number>[<unit>]). Number is a positive integer.
Unit can be one of b, k, m, or g. Minimum is 4M.
--cpus=valueSpecify how much of the available CPU resources a container can use. For instance, if the host machine has two CPUs and you set --cpus="1.5", the container is guaranteed at most one and a half of the CPUs

The limitations and stats can be found by running:

docker stats

For SSL configuration settings, see Network Configuration.

Steps to activate AOE

To activate APEX Office Edit, first, run the AOE container (aoe) and then execute the following command to access the shell inside the docker container.

docker exec -u root -it container_name or container_id /bin/bash

Example:

docker exec -u root -it aoe /bin/bash

After that, change the directory to APEXOfficeEdit (inside the container)

cd /APEXOfficeEdit

Then activate AOE as follows:

./AOEInterfaceLinux64 -a --email email_address

Example:

./AOEInterfaceLinux64 -a --email test@aoe.com

Optionally, a proxy can also be specified (if required) as follows:

./AOEInterfaceLinux64 -a --email email_address --proxy proxy_url or boolean

The proxy URL can be directly given with the proxy parameter.

If a Boolean value (true or false) is given, then the proxy URL will be the environment variable "http_proxy".

process.env.http_proxy= proxy_url

You can now safely end the AOE process using the key combination Ctrl + C. If the process was successful, a file with the filename aoe.license should have been created in the same directory. You can check this by running the ls command.

Afterward, exit the docker shell by using the key combination Ctrl + D or just type:

exit

Once this is completed, restart the docker instance with the following command:

docker restart container_name or container_id

Example:

docker restart aoe

Steps to re-activate AOE

Similar to the activation of AOE, reactivation can be achieved by accessing the shell of the running container as follows:

docker exec -u root -it container_name or container_id /bin/bash

Example:

docker exec -u root -it aoe /bin/bash

After that, change the directory inside the container to APEXOfficeEdit

cd /APEXOfficeEdit

Then re-activate AOE as follows:

./AOEInterfaceLinux64 -r

NOTE: For the reactivation process, a license file should be present (i.e. AOE should have been activated already)

AOE expects the license file to be in the same directory. If it is saved in a different location, then the license arguments can be given to indicate the path of the license file as follows:

./AOEInterfaceLinux64 -r --license path_of_file

Example:

./AOEInterfaceLinux64 -r --license /home/auth/aoe.license

Optionally, a proxy can also be specified (if required) as follows:

*./AOEInterfaceLinux64 -a --email email_address --proxy proxy_url or boolean

The proxy URL can be directly given with the proxy parameter.

If a Boolean value (true or false) is given, then the proxy URL will be the environment variable "http_proxy".

process.env.http_proxy=proxy url

You can now safely end the AOE process by using the key combination Ctrl + C. If the process was successful, a file with the filename "aoe.license" should have been created in the same directory. You can check this by running the ls command.

Afterward, exit the docker shell by using the key combination Ctrl + D or just type:

exit

Once this is completed, restart the docker instance with the following command:

docker restart container_name or container_id

Example:

docker restart aoe

Steps to deactivate AOE

First, access the shell of the running container as follows:

docker exec -u root -it container_name or container_id /bin/bash

Example:

docker exec -u root -it aoe /bin/bash

After that, change the directory inside the container to APEXOfficeEdit

cd /APEXOfficeEdit

Then deactivate AOE as follows:

./AOEInterfaceLinux64 -d

NOTE: For the deactivation process, the license file should be present (i.e. AOE should have been activated already).

AOE expects the license file to be in the same directory. If it is saved in a different location, then the license arguments can be given to indicate the path of the license file as follows:

*./AOEInterfaceLinux64 -d --license path_of_file

Example:

./AOEInterfaceLinux64 -d --license /home/auth/aoe.license

You can now safely end the AOE process by using the key combination Ctrl + C. Afterward, exit from the docker shell by using the key combination Ctrl+D or just type

exit

Once this is completed, copy out the deactivation request file from the docker instance as:

docker cp container_name or container_id:/APEXOfficeEdit/aoe_deactivation.request aoe_deactivation.request

It will copy the file to the docker host machine, which can be sent to the AOE support team to complete the deactivation process.

Also, the docker container can be stopped as follows:

docker stop container_name or container_id

Example:

docker stop aoe

Other options

Other options are also available and can be viewed as follows:

./AOEInterfaceLinux64 --help

It will display all available options:

Usage: AOE Utils [options]

AOE utility for licensing and configuring.

Options:

-v, --version Show version information

-a, --activate Activate License

-r, --reactivate Reactivate License

-d, --deactivate Deactivate License. Creates a deactivation request file.

-p, --port [port] Port number to listen on. (default: 8080)

--license [path] File path of license file (default:"./aoe.license")

--email [email] Email address of license holder

--proxy [proxy] Proxy to use (default: false)

--docs Documentation

--examples Examples

--mid Display the Machine ID

-h, --help Show help

Configuring APEX Office Edit

Configuration file

The configuration file for AOE is located inside/APEXOfficeEdit/aoe_config.jsonc. Once Docker has started, you can pull the configuration out of the Docker container using:

docker cp <container_name>:/APEXOfficeEdit/aoe_config.jsonc ./aoe_config.jsonc

Once modified, this can be put back into the container using:

docker cp ./aoe_config.jsonc <container_name>:/APEXOfficeEdit/aoe_config.jsonc

Once changes have been pushed, the container should be restarted using:

docker restart <container_name>

A lot of things can be configured in the aoe_config.jsonc file. The file itself contains comments which help with the configuration.

// The number of idle seconds after which the document, if modified, should be saved.
// Default: 300
"idlesave_duration_secs": 300,

// The maximum file size allowed to each document process to write. 0 for unlimited.
// Default: 200
"limit_file_size_mb": 200,

// The resolution, in DPI, used to render PDF documents as images. Memory consumption grows proportionally. Must be a positive value of less than 385.
// Default: 96
"pdf_resolution_dpi": 96,

// External hostname:port of the server running AOE. If empty, it's derived from the request (please set it if this doesn't work). May be specified when behind a reverse-proxy or when the hostname is not reachable directly.
// Default: ""
"server_name": "",

// Maximum number of seconds to wait for a document load to succeed. 0 for unlimited.
// Default: 20
"limit_load_secs": 20,

// Maximum number of consecutive save-and-upload to storage failures when unloading the document. 0 for unlimited (not recommended).
// Default: 5
"limit_store_failures": 5,

// Maximum number of seconds to wait for document conversion to succeed. 0 for unlimited.
// Default: 100
"limit_convert_secs": 100,

// This should be true if users are accessing AOE through HTTPS.
// Default: true
"ssl_termination": true,

// Specifies whether macro execution is enabled in general. This will enable Basic, Beanshell, JavaScript and Python scripts. If it is set to false, the macro_security_level is ignored. If it is set to true, the mentioned entry specifies the level of macro security.
// Default: false
"enable_macros_execution": false,

// The maximum virtual memory allowed to each document process. 0 for unlimited.
// Default: 0
"max_mem_per_document": 0,

// The maximum stack size allowed to each document process. 0 for unlimited.
// Default: 8000
"max_stack_mem_per_document": 8000,

// The maximum file size allowed to each document process to open. 0 for unlimited.
// Default: 0
"max_size_per_document": 0,

// The maximum number of files allowed to each document process to open. 0 for unlimited.
// Default: 0
"max_open_documents": 0,

// Maximum number of seconds to wait for a document load to succeed. 0 for unlimited.
// Default: 100
"max_load_secs": 100,

// Maximum consecutive save-and-upload to storage failures when unloading the document. 0 for unlimited (not recommended).
// Default: 3
"max_save_retries": 3,

// Maximum number of seconds to wait for document conversion to succeed. 0 for unlimited.
// Default: 100
"max_convert_secs": 100,

// If set to true, groups download as icons into a dropdown for the notebook bar view.
// Default: false
"group_download_as": false,

// The maximum number of seconds before dimming and stopping updates when the browser tab is no longer in focus.
// Default: 120
"out_of_focus_timeout": 120,

// The maximum number of seconds before dimming and stopping updates when the user is no longer active (even if the browser is in focus).
// Default: 900
"timeout_for_idle": 900,

// Protocol to use IPv4, IPv6 or all for both
// Default: "all"
"net_protocol": "all",

// Specifies the connection, send, and recv timeout in seconds for connections initiated by AOE (such as AOE REST connections).
// Default: 30
"connection_timeout_secs": 30,

// Whether or not Strict-Transport-Security is enabled. Enable only when ready for production. Cannot be disabled without resetting the browsers.
// Default: false
"ssl_sts": false,

// Strict-Transport-Security max-age directive, in seconds. 0 is allowed; please see rfc6797 for details.
// Default: 31536000
"ssl_sts_max_age": 31536000,

// Username for administration console.
// Default: "aoe_admin"
"console_username": "admin",

// Password for administration console
// Default: "admin"
"console_password": "admin"

Resource Optimization

On top of resource constraining, the resource can be optimized per document and can be found under the document section. Key settings are as follows:

// The maximum number of seconds before unloading an idle document. 
// Default: 3600 seconds (1 hour).
"idle_timeout_secs": 3600,
// The maximum virtual memory allowed to each document process. 0 for unlimited.
// Default: 0
"limit_virt_mem_mb": 0,

Logging

For logging, different options are available in the aoe_config.jsonc file, which can be modified.

// Can be 0-8 (with the lowest numbers being the least verbose), or none (turns off logging), fatal, critical, error, warning, notice, information, debug, trace
// Default: "error"
"log_level": "error",

// Log file path
// Default: "/tmp/aoe.log"
"log_file_path": "/tmp/aoe.log",

// The maximum age of log files to preserve in days
// Default: "10"
"log_purge_age": "10",

// Log file rotation strategy. See Poco FileChannel. (never, daily, weekly, monthly, <n> minutes/hours/days/weeks/months, <n> K (for kilobytes) M (megabytes))
// Default: "never"
"log_file_rotation": "never",

// The maximum age of log files to preserve. <n> seconds/minutes/hours/days/weeks/months.
// Default: "10 days"
"log_file_life": "10 days",

// The maximum number of log archives to preserve. (none for disabling it)
// Default: 10
"log_file_count": 10,

// Enable/disable flushing after logging each line. May harm performance. Note that without flushing after each line, the log lines from the different processes will not appear in chronological order.
// Default: false
"log_flush": false,

// Enable to see document handling information in logs.
// Default: false
"log_doc_stats": false,

// Enable user stats. i.e., logs the details of a file and user
// Default: false
"log_user_stats": false,

// Enable minimal client-site JS protocol logging from the start
// Default: false
"enable_client_js_logging": false,

// Logging to the browser console.
// Default: false
"enable_browser_logging": false,

Performance

The performance-related settings are available in the aoe_config.jsonc file.

// The maximum number of threads to use while processing a document.
// Default: 4
"max_concurrency_per_document": 4,

// The maximum percentage of system memory consumed by all of the AOE, after which AOE start cleaning up idle documents (can be 20-100)
// Default: 80
"memproportion": 80,

// Number of child processes to keep started in advance and waiting for new clients.
// Default: 1
"num_prespawn_children": 1,

Allowed dictionary languages

When there are a lot of spellchecker dictionaries and thesauri installed on a system, it may take considerable time at startup to preload them.

// List of supported languages of Writing Aids (spell checker, grammar checker, thesaurus, hyphenation) on this instance. Allowing too many has a negative effect on startup performance. 
// Default: de_DE en_GB en_US es_ES fr_FR it nl pt_BR pt_PT ru
"written_language_support": [
"de_DE",
"en_GB",
"en_US",
"es_ES",
"fr_FR",
"it nl",
"pt_BR",
"pt_PT",
"ru"
],

Fonts configuration

Other configurations, like fonts, can be done using the container shell. Accessing the shell can be done by using the following command:

docker exec -it aoe /bin/bash

The APEX Office Edit container is based on Ubuntu 20.04. Once inside the container, the usual Ubuntu commands can be used to install the required fonts.

Easy guide for fonts:

• Copy the to install fonts into /usr/local/share/fonts

• Run fc-cache -fv

The fonts can be moved from the server to the container using:

docker cp font.ttf aoe:/user/local/share/fonts/font.ttf

Admin Console

You can do live monitoring of all the user sessions. The Admin Console URL is:

http(s)://SERVER_DOMAIN>/browser/dist/admin/admin.html or

http://localhost:8030/browser/dist/admin/admin.html from the server running Docker. The port must be changed to the configured port number while running the container. Also, the admin username and password can be changed through the aoe_config.jsonc file.

After entering the correct password, you should be able to monitor the live documents opened, total users, memory consumption, document URLs with the number of users viewing that document, etc. You can also kill the documents directly from the panel, which would result in closing the socket connection to the respective document.

The admin-console front-end presents and fetches its data via a defined web socket protocol, which can be used to collect information programmatically to integrate with other monitoring and control solutions.

Network Configuration

If you want to use AOE in SSL mode, you can either run AOE behind a proxy or start AOE in SSL Mode.

If SSL is desired, it is recommended to use a proxy (or a load balancer if you are using the cloud). This way, certificate management becomes more straightforward. You must set up a proxy server to forward the SSL requests to the AOE server.

Setting up Apache 2 reverse proxy

(https://web.archive.org/web/20210504000148/https://www.collaboraoffice.com/code/apache-reverse-proxy/)

mod_proxy_wstunnel should be enabled in the httpd.conf file. The necessary mods can be installed with a2enmod as follows:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_connect
sudo a2enmod proxy_wstunnel
sudo systemctl restart apache2 # restart apache for the changes to take effect

If using SSL, be sure to turn on SSL termination from the aoe_config.jsonc file.

<VirtualHost *:443>
ServerName api.apexofficeedit.com:443

# SSL configuration, you may want to take the easy route instead and use Lets Encrypt!
SSLEngine on
SSLCertificateFile /path/to/signed_certificate
SSLCertificateChainFile /path/to/intermediate_certificate
SSLCertificateKeyFile /path/to/private/key
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on

# Encoded slashes need to be allowed
AllowEncodedSlashes NoDecode

# Container uses a unique non-signed certificate
SSLProxyEngine On
SSLProxyVerify None
SSLProxyCheckPeerCN Off
SSLProxyCheckPeerName Off

# keep the host
ProxyPreserveHost On

# static HTML, js, images, etc., served from coolwsd
# loleaflet is the client part of LibreOffice Online
ProxyPass /loleaflet http://127.0.0.1:8030/loleaflet retry=0
ProxyPassReverse /loleaflet http://127.0.0.1:8030/loleaflet

# WOPI discovery URL
ProxyPass /hosting/discovery http://127.0.0.1:8030/hosting/discovery retry=0
ProxyPassReverse /hosting/discovery http://127.0.0.1:8030/hosting/discovery

# Capabilities
ProxyPass /hosting/capabilities http://127.0.0.1:8030/hosting/capabilities retry=0
ProxyPassReverse /hosting/capabilities http://127.0.0.1:8030/hosting/capabilities

# Main WebSocket
ProxyPassMatch "/cool/(.*)/ws$" ws://127.0.0.1:8030/cool/$1/ws nocanon

# Admin Console WebSocket
ProxyPass /cool/adminws ws://127.0.0.1:8030/cool/adminws

# Download as, Fullscreen presentation and Image upload operations
ProxyPass /cool http://127.0.0.1:8030/cool
ProxyPassReverse /cool http://127.0.0.1:8030/cool

ProxyPass / http://127.0.0.1:8030/
ProxyPassReverse / http://127.0.0.1:8030/
</VirtualHost>

Setting up Nginx reverse proxy

(https://web.archive.org/web/20210924112039/https://www.collaboraoffice.com/code/nginx-reverse-proxy/)

If using SSL, turn on SSL termination from the aoe_config.jsonc file.

server {
listen 443 ssl;
server_name api.apexofficeedit.com:443;

ssl_certificate /path/to/ssl_certificate;
ssl_certificate_key /path/to/ssl_certificate_key;

# static files
location ^~ /loleaflet {
proxy_pass http://localhost:9980;
proxy_set_header Host $http_host;
}

# main websocket
location ~ ^/cool/(.*)/ws$ {
proxy_pass http://localhost:9980;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
proxy_read_timeout 36000s;
}

# download, presentation and image upload
location ~ ^/cool {
proxy_pass http://localhost:9980;
proxy_set_header Host $http_host;
}

# Admin Console websocket
location ^~ /cool/adminws {
proxy_pass http://localhost:9980;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
proxy_read_timeout 36000s;
}
}

SSL termination (when using a proxy)

When the docker image is behind a proxy that uses HTTPS, the termination option should be set to true. This will cause the AOE page to use a secure WebSocket protocol instead of plain WebSocket.

// This should be true if users are accessing AOE through HTTPS.
// Default:true
"ssl_termination": true,

Start AOE in SSL Mode

First let's start AOE in plain HTTP Mode:

docker run -p 8030:8080 --name aoe -d --restart always unitedcodes/apexofficeedit

This will start AOE on port 8030, after some seconds, doing a curl command should give you polo string back

curl http://localhost:8030/marco

AOE has started on port 8030 succesfully.

AOE by default runs on http. Running on SSL requires private key and certificate files.

If you dont have these files. You can generate a self signed certificate as follows:

openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out aoe.crt -days 365
#fill in the details and password.
openssl rsa -in keytmp.pem -out aoe.key
#fill in the password.

The next step is to copy the aoe.key and aoe.crt files to the docker. You can copy these files inside the docker using:

docker cp ./aoe.key aoe:/APEXOfficeEdit/
docker cp ./aoe.crt aoe:/APEXOfficeEdit/

Once the files are copied, we need to configure AOE to start in HTTPS mode. For this we will execute a shell as root user and do the modifications.

docker exec -u 0 -it aoe  /bin/bash
#this will give you a shell as root user inside the docker.

chown cool:cool /APEXOfficeEdit/aoe.crt
chown cool:cool /APEXOfficeEdit/aoe.key
nano start-apex-office-edit.sh

Inside nano, change the following line and add the --https_cert and --https_key parameters.

/APEXOfficeEdit/AOEInterfaceLinux64 &

Your new line should look like this:

/APEXOfficeEdit/AOEInterfaceLinux64 --https_cert aoe.crt --https_key aoe.key &

Press Ctrl+O then enter to save the file.

Press Ctrl+X to exit nano.

Exit out of docker using:

exit

Restart AOE docker using:

docker restart aoe

APEX Office Edit will now start in HTTPS mode. You can check by doing a curl using https protocol:

curl https://localhost:8030/marco

Please note that if you are using self signed certificate, that this certificate should be trusted by the browser/OS. You can do so by navitating to the URL of AOE through the browser and adding the certificate as security exception.

REST URL using self signed certificate

In case when your internal apex instance is using a self signed certificate, AOE server will raise an error "INVALID_RESTSRC" error with error description of "self signed certificate in certificate chain".

You will need to specify AOE to ignore SSL verification. You can do so by providing the following environment variable while starting AOE docker:

docker run ... -e NODE_TLS_REJECT_UNAUTHORIZED=0 ...

Alternatively, you can also modify the start-apex-office-edit.sh script inside the running docker container:

docker exec -u 0 -it <<aoe_container_id>>  /bin/bash
nano start-apex-office-edit.sh

add the following line between #start AOE Interface and /APEXOfficeEdit/AOEInterfaceLinux64:

export NODE_TLS_REJECT_UNAUTHORIZED=0

The new file should look like this:

...
#start AOE Interface
export NODE_TLS_REJECT_UNAUTHORIZED=0
/APEXOfficeEdit/AOEInterfaceLinux64 &
...

Press Ctrl+O then enter to save the file.

Press Ctrl+X to exit nano.

Exit out of docker using:

exit

Restart AOE docker using:

docker restart <<aoe_container_id>>

Troubleshooting

After starting the container, try:

curl -k http(s)://localhost:9980/knockknock

You should get the Who's there? string, if everything is in order. Otherwise, you can check the log with:

docker logs aoe

(Instead of aoe, it might be something different if the name was changed while running docker run)

If the Docker doesn't restart automatically, it can be restarted using the command:

docker restart container_id or container_name

Example:

docker restart aoe