Installing Cryptpad on Debian 12

CryptPad is a secure, collaborative online office suite that enables users to create documents, spreadsheets, presentations, and more, all while protecting their privacy through end-to-end encryption. It allows multiple users to work on the same document simultaneously without compromising the confidentiality of their data. CryptPad offers a range of tools for real-time collaboration, making it a versatile and secure solution for remote teamwork and document management.

First, set up a Debian server with firewall ufw.

Time for whole setup: 1 to 1.5 hours.

Reverse Proxy

Firewall

sudo ufw allow 443/tcp
sudo ufw reload
sudo ufw status

DNS/Domains

Go to your domain provider and point your domain at your server's IP 4 and IP 6 adresses.

Certificates

sudo certbot certonly --standalone -d office.foo.com -d sandbox.office.foo.com

Install Nginx

sudo apt-get install nginx
sudo systemctl start nginx
sudo systemctl enable nginx

Generate a DH parameter file:

sudo openssl dhparam -out /etc/ssl/dhparam.pem 4096
sudo systemctl restart nginx
sudo rm /etc/nginx/sites-enabled/default

Configure Nginx

sudo vi /etc/nginx/sites-available/office.foo.com.conf
sudo ln -s /etc/nginx/sites-available/office.foo.com.conf /etc/nginx/sites-enabled/

sudo systemctl restart nginx

Test Nginx configuration:

sudo nginx -t

Cryptpad

Install Docker

See official Docker documentation.

Container stack

Prepare:

CRYPTPAD_VERSION_NUMBER=<CRYPTPAD_VERSION_NUMBER>
CRYPTPAD_USAGE_ROLE=<EG_WORK_OR_PERSONAL>
CRYPTPAD_DIR=/opt/cryptpad-$CRYPTPAD_VERSION_NUMBER-$CRYPTPAD_USAGE_ROLE

mkdir Downloads && cd Downloads
wget https://codeload.github.com/cryptpad/cryptpad/zip/refs/tags/$CRYPTPAD_VERSION_NUMBER -O $CRYPTPAD_VERSION_NUMBER.zip
sudo apt-get install unzip
unzip $CRYPTPAD_VERSION_NUMBER.zip
sudo mv cryptpad-$CRYPTPAD_VERSION_NUMBER $CRYPTPAD_DIR
cd $CRYPTPAD_DIR

Remove popups for shared folders (e.g. advertisement):

# Advertisement
sudo sed -i 's^var crowdfundingState = false;^var crowdfundingState = true;^g' www/common/common-ui-elements.js

# Storage-popu-up
# FIXME: Don't block it so generally.
sudo sed -i 's^var storePopupState = false;^var storePopupState = true;^g' www/common/common-ui-elements.js

Build the container stack:

sudo apt-get install -y uidmap
sudo docker build -t cryptpad/cryptpad:version-$CRYPTPAD_VERSION_NUMBER-$CRYPTPAD_USAGE_ROLE .

Verify the container image is there, with the tag cryptpad:

sudo docker images

vi docker-compose.yml:

- CPAD_MAIN_DOMAIN=https://office.foo.com
- CPAD_SANDBOX_DOMAIN=https://sandbox.office.foo.com

Run the Cryptpad stack

sudo docker compose up -d
# This will throw an "access denied":
sudo docker-compose logs cryptpad

Change permissions:

sudo docker compose down -v
sudo chown -R 4001:4001 data customize
sudo docker compose up -d
sudo docker-compose logs cryptpad

Post installation tasks

Get the generated, setup-specific configuration files:

cd $CRYPTPAD_DIR
sudo docker ps
sudo docker exec -it <CONTAINER_ID> /bin/bash
cat /cryptpad/config/config.js
exit

Mark the content and copy it temporarily to an editor on the local machine.

sudo docker compose restart

Go to your new Cryptpad instance, and create an admin account.

Then go to user -> Settings -> Account -> Public Signing Key.

cd $CRYPTPAD_DIR
vi config/config.js

Delete the current content, paste the value of above content from the local machine, and insert the "Public Signing Key" from the user settings page into the list of adminKeys:

adminKeys: [
    "[suadmin@office.foo.com/+ldturnuitarenotrn78t8n9dtn8t9nt89ntr79fNBY=]",
],

While we are at this file, add:

module.exports = {
    # ...
    removeDonateButton: true,
    # ...

And change:

# For private use: 25 MB; business use: 100 MB
maxUploadSize: 25 * 1024 * 1024,

Mount the configuration file onto the Docker container ones by adding these lines vi vi docker-compose.yml:

services:
    cryptpad:
        # ...
        - ./config/config.js:/cryptpad/config/config.js

Customization

Activate features that are normally only for paid subscriptions:

sudo cp customize.dist/application_config.js customize/
sudo vi customize/application_config.js
define(['/common/application_config_internal.js'], function (AppConfig) {
    AppConfig.enableEarlyAccess = true;
    AppConfig.premiumTypes = [];

    // WARNING: This is enforced only on client side.
    AppConfig.disableAnonymousPadCreation = true;
    // AppConfig.disableAnonymousStore = false;

    AppConfig.emojiAvatars = '♈ ♉ ♊ ♌ ♍ ♎ ♏ ♑ ♒ ♓ ⛎'.split(/\s+/);

    # ...
}

Save and exit.

Default language:

sudo cp customize.dist/messages.js customize/messages.js
sudo sed -i "s^ : 'en'));^: 'de'));^g" customize/messages.js

Remove not-needed links from start page:

sudo cp customize.dist/pages.js customize/
sudo vi customize/pages.js

Search for features.html and delete /features.html and https://docs.cryptpad.org h... blocks.

In their place, insert (same link as originally in customize/pages/index.js, but with different CSS class):

h('a.nav-item.nav-link', {'href': '/drive/'}, [
    h('i.fa.fa-hdd-o', {'aria-hidden': 'true'}),
    Msg.team_cat_drive
]),

Search for div.cp-footer-center and delete that block as well.

sudo mkdir customize/pages
sudo cp customize.dist/pages/index.js customize/pages/index.js
sudo vi customize/pages/index.js

Search for contact.html and remove that link block.

Delete the h('div.cp-app-grid', [ block.

Delete the div.cp-app-drive block.

Set list-view for drive as default (grid-view cuts-off file names):

sudo mkdir customize/www/common
sudo cp www/common/drive-ui.js customize/www/common/
sudo sed -i "s^return 'cp-app-drive-content-grid';^return 'cp-app-drive-content-list';^g" customize/www/common/drive-ui.js

Change permissions of local files to user running inside of the container, so it can access the files:

sudo chown 4001:4001 config/config.js
sudo chown -R 4001:4001 customize/

Restart the container:

sudo docker compose restart

Refresh the web page, and there should be a new menu item "Administration" in the user drop down.

As an admin, change the following values in the Administration panel:

  • User directory: Close registration: on

    You don't want random people to register on your instance, even more so as you wouldn't find out. With this turned on, you can still invite people, and this way they get registered in a user directory.

  • User storage: Storage limit: 500 MB

  • Network: Disable server telemetry

As a normal user, click on the bell icon, and "Accept messages". This will make you get informed about users writing you new messages without having the browser in the foreground on your desktop system, as it allows using the popups of the local information system.

Trouble Shooting

For error shooting, see the logs:

# Docker falls back on the running instance if a restart fails, so you won't
# see any errors, so make sure to shutdown completely first.
sudo docker compose down -v
sudo docker compose up -d
# Show logs.
sudo docker-compose logs cryptpad

Appendix

/etc/nginx/sites-available/office.foo.com.conf

# NOTE: Not part of Cryptpad's example config, but without it, HTTP requests
# get forwarded to HTTPS of other configured websites that configured a
# forward from HTTP.
server {
    listen       80;
    listen       [::]:80;
    server_name office.foo.com sandbox.office.foo.com;

    location / {
        access_log off;
        return 301 https://$server_name$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # Let's Encrypt webroot
    # CHRIS: Deactivated
    # include letsencrypt-webroot;

    # Include mime.types to be able to support .mjs files (see "types" below)
    include mime.types;

    # CryptPad serves static assets over these two domains.
    # `your-main-domain` is what users will enter in their address bar.
    # Privileged computation such as key management is handled in this scope
    # UI content is loaded via the `your-sandbox-domain`.
    # "Content Security Policy" headers prevent content loaded via the sandbox
    # from accessing privileged information.
    # This setup allows to take advantage of CryptPad's sandboxing techniques.
    # In the event of an XSS vulnerability in CryptPad's front-end code
    # this will limit the amount of information accessible to attackers.
    server_name office.foo.com sandbox.office.foo.com;

    # You'll need to Set the path to your certificates and keys here
    # IMPORTANT: this config is intended to serve assets for at least two domains
    # (your main domain and your sandbox domain). As such, you'll need to generate a single SSL certificate
    # that includes both domains in order for things to work as expected.
    ssl_certificate         /etc/letsencrypt/live/office.foo.com/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/office.foo.com/privkey.pem;

    # diffie-hellman parameters are used to negotiate keys for your session
    # generate strong parameters using the following command
    # openssl dhparam -out /etc/nginx/dhparam.pem 4096
    ssl_dhparam /etc/nginx/dhparam.pem;

    # Speeds things up a little bit when resuming a session
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;

    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;

    # replace with the IP address of your resolver
    resolver 8.8.8.8 8.8.4.4 1.1.1.1 1.0.0.1 9.9.9.9 149.112.112.112 208.67.222.222 208.67.220.220;

    location / {
        proxy_pass            http://localhost:3000;
        proxy_set_header      X-Real-IP $remote_addr;
        proxy_set_header      Host $host;
        proxy_set_header      X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size  150m;

        proxy_http_version    1.1;
        proxy_set_header      Upgrade $http_upgrade;
        proxy_set_header      Connection upgrade;
    }
}

Upgrading

Also read: https://docs.cryptpad.org/en/admin_guide/maintenance.html

Build a new container stack as depicted above, but without the post-installation tasks. It's crucial to follow each step and apply modifications manually.

Then, copy over configuration and data from the production instance:

OLD_CRYPTPAD_VERSION_NUMBER=<OLD_CRYPTPAD_VERSION_NUMBER>
NEW_CRYPTPAD_VERSION_NUMBER=<NEW_CRYPTPAD_VERSION_NUMBER>
CRYPTPAD_USAGE_ROLE=<EG_WORK_OR_PERSONAL>
NEW_CRYPTPAD_DIR=/opt/cryptpad-$NEW_CRYPTPAD_VERSION_NUMBER-$CRYPTPAD_USAGE_ROLE
OLD_CRYPTPAD_DIR=/opt/cryptpad-$OLD_CRYPTPAD_VERSION_NUMBER-$CRYPTPAD_USAGE_ROLE

cd $OLD_CRYPTPAD_DIR
sudo docker compose down -v
cd $NEW_CRYPTPAD_DIR
sudo mv data data_ORIGINAL
sudo mv customize customize_ORIGINAL
sudo mv config config_ORIGINAL
sudo cp -r $OLD_CRYPTPAD_DIR/data/ .
sudo cp -r $OLD_CRYPTPAD_DIR/customize/ .
sudo cp -r $OLD_CRYPTPAD_DIR/config/ .
sudo chown -R 4001:4001 data customize
sudo chown -R 1000:1000 config
sudo chown -R 4001:4001 config/config.js
sudo docker compose up -d

Mount the configuration files onto the Docker container ones by adding these lines vi vi docker-compose.yml:

services:
    cryptpad:
        # ...
        - ./config/config.js:/cryptpad/config/config.js
        - ./customize.dist/application_config.js:/cryptpad/customize.dist/application_config.js
sudo docker restart

You might want to diff the configuration files to check for changes in the new version, and then delete them:

sudo rm -r data_ORIGINAL
sudo rm -r customize customize_ORIGINAL
sudo rm -r config config_ORIGINAL

Customization

sudo cp customize.dist/src/less2/include/colortheme.less customize/src/less2/include/
sudo cp customize.dist/src/less2/include/colortheme-dark.less customize/src/less2/include/
sudo chown -R 4001:4001 customize/src/

Note that there are more files, see https://docs.cryptpad.org/en/admin_guide/customization.html.

Edit the respective files.

Restart the container:

sudo docker compose restart

Development tickets to have an eye on

Change domain

Create new domain bar.com, and sub domains office.bar.com and sandbox.office.bar.com, and point them to the server where Cryptpad is running.

Reconfigure server:

# Container
sudo sed -i 's^foo.com^bar.com^g' config/config.js
sudo sed -i 's^foo.com^bar.com^g' docker-compose.yml
sudo docker compose restart

# Webserver
sudo cp /etc/nginx/sites-available/office.foo.com.conf /etc/nginx/sites-available/office.bar.com.conf
sudo sed -i 's^foo.com^bar.com^g' /etc/nginx/sites-available/office.bar.com.conf
sudo ln -s /etc/nginx/sites-available/office.bar.com.conf /etc/nginx/sites-enabled/
sudo service nginx stop
sudo certbot certonly --standalone -d office.bar.com -d sandbox.office.bar.com
sudo nginx -t
sudo service nginx start