Hi. I have installed cryptpad on my vps with nginx. I followed the guide on github and now i’m stuck with the cryptpad logo just before it loads its applications. Nginx is configured on port 4433 with letsencrypt certificates. the error reported by nginx is as follows:

2022/12/05 23:02:41 [error] 356#356: *37 connect() failed (111: Connection refused) while connecting to upstream, client: 123.123.123.123, server: cryptpad.virebent.art, request: "GET /api/config?cb=184e4500a6a HTTP/2.0", upstream: "http://127.0.0.1:3000/api/config?cb=184e4500a6a", host: "cryptpad.virebent.art:4433", referrer: "https://cryptpad.virebent.art:4433/"

I tried adding this snippet:

location /api/* {
allow all;
}

But without success.
I found the configuration of the nginx virtualhost for cryptpad quite complex.
Regards

  • It looks like CryptPad isn't running. You have to install it under a dedicated user, not running it as root.

    Create a dedicated user

    adduser cryptpad --disabled-password

    Switch to it

    su - cryptpad

    And then follow the instructions of the administrator guide: https://docs.cryptpad.org/en/admin_guide/installation.html#software

Hello!

Thanks for reaching out on our community forum! As said on the Matrix chat it's much more convenient to keep track of problems and debug issues. 😊

Could you share with us:

  1. Your complete Nginx configuration file
  2. Your complete config.js file

Thanks in advance!

Thanks for picking up.
First of all the operating system is debian stable, I missed to say this.
This is the configuration file for the nginx virtualhost:

server {
    listen 4433 ssl http2;

    # CryptPad serves static assets over these two domains.
    # `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 `sandbox_domain`.
    # "Content Security Policy" headers prevent content loaded via the sandbox
    # from accessing privileged information.
    # These variables must be different 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.
    set $main_domain "cryptpad.virebent.art";
    set $sandbox_domain "sandbox.virebent.art";
    set $api_domain "cryptpad.virebent.art";
    #set $files_domain "cryptpad.virebent.art";
    # By default CryptPad allows remote domains to embed CryptPad documents in iframes.
    # This behaviour can be blocked by changing $allowed_origins from "*" to the
    # sandbox domain, which must be permitted to load content from the main domain
    # in order for CryptPad to work as expected.
    #
    # An example is given below which can be uncommented if you want to block
    # remote sites from including content from your server
    #set $allowed_origins "*";
    set $allowed_origins "https://${sandbox_domain}";

    # CryptPad's dynamic content (websocket traffic and encrypted blobs)
    # can be served over separate domains. Using dedicated domains (or subdomains)
    # for these purposes allows you to move them to a separate machine at a later date
    # if you find that a single machine cannot handle all of your users.
    # If you don't use dedicated domains, this can be the same as $main_domain
    # If you do, they can be added as exceptions to any rules which block connections to remote domains.
    # You can find these variables referenced below in the relevant places
    #set $api_domain "api.your-main-domain.com";
    #set $files_domain "files.your-main-domain.com";

    # nginx doesn't let you set server_name via variables, so you need to hardcode your domains here
    server_name cryptpad.virebent.art sandbox.virebent.art;

    # Cryptpad API requests
#     location /api/* {
#     allow all;
#     }
    # 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/cryptpad.virebent.art/fullchain.pem;
    ssl_certificate_key     /etc/letsencrypt/live/cryptpad.virebent.art/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/cryptpad.virebent.art/chain.pem;

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

    # Speeds things up a little bit when resuming a session
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:5m;

    # You'll need nginx 1.13.0 or better to support TLSv1.3
    ssl_protocols TLSv1.2 TLSv1.3;

    # https://cipherli.st/
    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;
    ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;


    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options nosniff;
    add_header Access-Control-Allow-Origin "${allowed_origins}";
    add_header X-Frame-Options "SAMEORIGIN";

    # Opt out of Google's FLoC Network
    add_header Permissions-Policy interest-cohort=();

    # Enable SharedArrayBuffer in Firefox (for .xlsx export)
    add_header Cross-Origin-Resource-Policy cross-origin;
    add_header Cross-Origin-Embedder-Policy require-corp;

    # Insert the path to your CryptPad repository root here
    root /var/www/cryptpad;
    index index.html;
    error_page 404 /customize.dist/404.html;

    # any static assets loaded with "ver=" in their URL will be cached for a year
    if ($uri ~ ^(\/|.*\/|.*\.html)$) {
        set $cacheControl no-cache;
    }
    if ($args ~ ver=) {
        set $cacheControl max-age=31536000;
    }
    # Will not set any header if it is emptystring
    add_header Cache-Control $cacheControl;

    # CSS can be dynamically set inline, loaded from the same domain, or from $main_domain
    set $styleSrc   "'unsafe-inline' 'self' https://${main_domain}";

    # connect-src restricts URLs which can be loaded using script interfaces
    # if you have configured your instance to use a dedicated $files_domain or $api_domain
    # you will need to add them below as: https://${files_domain} and https://${api_domain}
    set $connectSrc "'self' https://${main_domain} blob: wss://${api_domain} https://${sandbox_domain}";

    # fonts can be loaded from data-URLs or the main domain
    set $fontSrc    "'self' data: https://${main_domain}";

    # images can be loaded from anywhere, though we'd like to deprecate this as it allows the use of images for tracking
    set $imgSrc     "'self' data: blob: https://${main_domain}";

    # frame-src specifies valid sources for nested browsing contexts.
    # this prevents loading any iframes from anywhere other than the sandbox domain
    set $frameSrc   "'self' https://${sandbox_domain} blob:";

    # specifies valid sources for loading media using video or audio
    set $mediaSrc   "blob:";

    # defines valid sources for webworkers and nested browser contexts
    # deprecated in favour of worker-src and frame-src
    set $childSrc   "https://${main_domain}";

    # specifies valid sources for Worker, SharedWorker, or ServiceWorker scripts.
    # supercedes child-src but is unfortunately not yet universally supported.
    set $workerSrc  "'self'";

    # script-src specifies valid sources for javascript, including inline handlers
    set $scriptSrc  "'self' resource: https://${main_domain}";

    # frame-ancestors specifies which origins can embed your CryptPad instance
    # this must include 'self' and your main domain (over HTTPS) in order for CryptPad to work
    # if you have enabled remote embedding via the admin panel then this must be more permissive.
    # note: cryptpad.fr permits web pages served via https: and vector: (element desktop app)
    set $frameAncestors "'self' https://${main_domain}";
    # set $frameAncestors "'self' https: vector:";

    set $unsafe 0;
    # the following assets are loaded via the sandbox domain
    # they unfortunately still require exceptions to the sandboxing to work correctly.
    if ($uri ~ ^\/(sheet|doc|presentation)\/inner.html.*$) { set $unsafe 1; }
    if ($uri ~ ^\/common\/onlyoffice\/.*\/.*\.html.*$) { set $unsafe 1; }

    # everything except the sandbox domain is a privileged scope, as they might be used to handle keys
    if ($host != $sandbox_domain) { set $unsafe 0; }
    # this iframe is an exception. Office file formats are converted outside of the sandboxed scope
    # because of bugs in Chromium-based browsers that incorrectly ignore headers that are supposed to enable
    # the use of some modern APIs that we require when javascript is run in a cross-origin context.
    # We've applied other sandboxing techniques to mitigate the risk of running WebAssembly in this privileged scope
    if ($uri ~ ^\/unsafeiframe\/inner\.html.*$) { set $unsafe 1; }

    # privileged contexts allow a few more rights than unprivileged contexts, though limits are still applied
    if ($unsafe) {
        set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' resource: https://${main_domain}";
    }

    # Finally, set all the rules you composed above.
    #add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc; frame-ancestors $frameAncestors";
    # connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc; frame-ancestors $frameAncestors";
    add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc; frame-ancestors $frameAncestors";
    # The nodejs process can handle all traffic whether accessed over websocket or as static assets
    # We prefer to serve static content from nginx directly and to leave the API server to handle
    # the dynamic content that only it can manage. This is primarily an optimization
    location ^~ /cryptpad_websocket {
        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;

        # WebSocket support (nginx 1.4)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection upgrade;
    }

    location ^~ /customize.dist/ {
        # This is needed in order to prevent infinite recursion between /customize/ and the root
    }
    # try to load customizeable content via /customize/ and fall back to the default content
    # located at /customize.dist/
    # This is what allows you to override behaviour.
    location ^~ /customize/ {
        rewrite ^/customize/(.*)$ $1 break;
        try_files /customize/$uri /customize.dist/$uri;
    }

    # /api/config is loaded once per page load and is used to retrieve
    # the caching variable which is applied to every other resource
    # which is loaded during that session.
    #########
    location ~ ^/api/.*$ {
        allow all;
        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;

        # These settings prevent both NGINX and the API server
        # from setting the same headers and creating duplicates
        proxy_hide_header Cross-Origin-Resource-Policy;
        add_header Cross-Origin-Resource-Policy cross-origin;
        proxy_hide_header Cross-Origin-Embedder-Policy;
        add_header Cross-Origin-Embedder-Policy require-corp;
    }

    # encrypted blobs are immutable and are thus cached for a year
    location ^~ /blob/ {
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' "${allowed_origins}";
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'application/octet-stream; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
        add_header X-Content-Type-Options nosniff;
        add_header Cache-Control max-age=31536000;
        add_header 'Access-Control-Allow-Origin' "${allowed_origins}";
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';
        add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';
        try_files $uri =404;
    }

    # the "block-store" serves encrypted payloads containing users' drive keys
    # these payloads are unlocked via login credentials. They are mutable
    # and are thus never cached. They're small enough that it doesn't matter, in any case.
    location ^~ /block/ {
        add_header X-Content-Type-Options nosniff;
        add_header Cache-Control max-age=0;
        try_files $uri =404;
    }

    # This block provides an alternative means of loading content
    # otherwise only served via websocket. This is solely for debugging purposes,
    # and is thus not allowed by default.
    #location ^~ /datastore/ {
        #add_header Cache-Control max-age=0;
        #try_files $uri =404;
    #}

    # The nodejs server has some built-in forwarding rules to prevent
    # URLs like /pad from resulting in a 404. This simply adds a trailing slash
    # to a variety of applications.
    location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc|form|report|convert|checkup)$ {
        rewrite ^(.*)$ $1/ redirect;
    }

    # Finally, serve anything the above exceptions don't govern.
    try_files /customize/www/$uri /customize/www/$uri/index.html /www/$uri /www/$uri/index.html /customize/$uri;
}

This is the cryptpad config.js:

/* globals module */

/*  DISCLAIMER:

    There are two recommended methods of running a CryptPad instance:

    1. Using a standalone nodejs server without HTTPS (suitable for local development)
    2. Using NGINX to serve static assets and to handle HTTPS for API server's websocket traffic

    We do not officially recommend or support Apache, Docker, Kubernetes, Traefik, or any other configuration.
    Support requests for such setups should be directed to their authors.

    If you're having difficulty difficulty configuring your instance
    we suggest that you join the project's Matrix channel.

    If you don't have any difficulty configuring your instance and you'd like to
    support us for the work that went into making it pain-free we are quite happy
    to accept donations via our opencollective page: https://opencollective.com/cryptpad

*/
module.exports = {
/*  CryptPad is designed to serve its content over two domains.
 *  Account passwords and cryptographic content is handled on the 'main' domain,
 *  while the user interface is loaded on a 'sandbox' domain
 *  which can only access information which the main domain willingly shares.
 *
 *  In the event of an XSS vulnerability in the UI (that's bad)
 *  this system prevents attackers from gaining access to your account (that's good).
 *
 *  Most problems with new instances are related to this system blocking access
 *  because of incorrectly configured sandboxes. If you only see a white screen
 *  when you try to load CryptPad, this is probably the cause.
 *
 *  PLEASE READ THE FOLLOWING COMMENTS CAREFULLY.
 *
 */

/*  httpUnsafeOrigin is the URL that clients will enter to load your instance.
 *  Any other URL that somehow points to your instance is supposed to be blocked.
 *  The default provided below assumes you are loading CryptPad from a server
 *  which is running on the same machine, using port 3000.
 *
 *  In a production instance this should be available ONLY over HTTPS
 *  using the default port for HTTPS (443) ie. https://cryptpad.fr
 *  In such a case this should be also handled by NGINX, as documented in
 *  cryptpad/docs/example.nginx.conf (see the $main_domain variable)
 *
 */
    httpUnsafeOrigin: 'https://cryptpad.virebent.art',

/*  httpSafeOrigin is the URL that is used for the 'sandbox' described above.
 *  If you're testing or developing with CryptPad on your local machine then
 *  it is appropriate to leave this blank. The default behaviour is to serve
 *  the main domain over port 3000 and to serve the sandbox content over port 3001.
 *
 *  This is not appropriate in a production environment where invasive networks
 *  may filter traffic going over abnormal ports.
 *  To correctly configure your production instance you must provide a URL
 *  with a different domain (a subdomain is sufficient).
 *  It will be used to load the UI in our 'sandbox' system.
 *
 *  This value corresponds to the $sandbox_domain variable
 *  in the example nginx file.
 *
 *  Note that in order for the sandboxing system to be effective
 *  httpSafeOrigin must be different from httpUnsafeOrigin.
 *
 *  CUSTOMIZE AND UNCOMMENT THIS FOR PRODUCTION INSTALLATIONS.
 */
    httpSafeOrigin: "https://sandbox.virebent.art",

/*  httpAddress specifies the address on which the nodejs server
 *  should be accessible. By default it will listen on 127.0.0.1
 *  (IPv4 localhost on most systems). If you want it to listen on
 *  all addresses, including IPv6, set this to '::'.
 *
 */
    //httpAddress: '::',

/*  httpPort specifies on which port the nodejs server should listen.
 *  By default it will serve content over port 3000, which is suitable
 *  for both local development and for use with the provided nginx example,
 *  which will proxy websocket traffic to your node server.
 *
 */
    //httpPort: 3000,

/*  httpSafePort allows you to specify an alternative port from which
 *  the node process should serve sandboxed assets. The default value is
 *  that of your httpPort + 1. You probably don't need to change this.
 *
 */
    //httpSafePort: 3001,

/*  CryptPad will launch a child process for every core available
 *  in order to perform CPU-intensive tasks in parallel.
 *  Some host environments may have a very large number of cores available
 *  or you may want to limit how much computing power CryptPad can take.
 *  If so, set 'maxWorkers' to a positive integer.
 */
    // maxWorkers: 4,

    /* =====================
     *         Admin
     * ===================== */

    /*
     *  CryptPad contains an administration panel. Its access is restricted to specific
     *  users using the following list.
     *  To give access to the admin panel to a user account, just add their public signing
     *  key, which can be found on the settings page for registered users.
     *  Entries should be strings separated by a comma.
     *  adminKeys: [
     *      "[cryptpad-user1@my.awesome.website/YZgXQxKR0Rcb6r6CmxHPdAGLVludrAF2lEnkbx1vVOo=]",
     *      "[cryptpad-user2@my.awesome.website/jA-9c5iNuG7SyxzGCjwJXVnk5NPfAOO8fQuQ0dC83RE=]",
     *  ]
     *
     */
    adminKeys: [

    ],

    /* =====================
     *        STORAGE
     * ===================== */

    /*  Pads that are not 'pinned' by any registered user can be set to expire
     *  after a configurable number of days of inactivity (default 90 days).
     *  The value can be changed or set to false to remove expiration.
     *  Expired pads can then be removed using a cron job calling the
     *  `evict-inactive.js` script with node
     *
     *  defaults to 90 days if nothing is provided
     */
    //inactiveTime: 90, // days

    /*  CryptPad archives some data instead of deleting it outright.
     *  This archived data still takes up space and so you'll probably still want to
     *  remove these files after a brief period.
     *
     *  cryptpad/scripts/evict-inactive.js is intended to be run daily
     *  from a crontab or similar scheduling service.
     *
     *  The intent with this feature is to provide a safety net in case of accidental
     *  deletion. Set this value to the number of days you'd like to retain
     *  archived data before it's removed permanently.
     *
     *  defaults to 15 days if nothing is provided
     */
    //archiveRetentionTime: 15,

    /*  It's possible to configure your instance to remove data
     *  stored on behalf of inactive accounts. Set 'accountRetentionTime'
     *  to the number of days an account can remain idle before its
     *  documents and other account data is removed.
     *
     *  Leave this value commented out to preserve all data stored
     *  by user accounts regardless of inactivity.
     */
     //accountRetentionTime: 365,

    /*  Starting with CryptPad 3.23.0, the server automatically runs
     *  the script responsible for removing inactive data according to
     *  your configured definition of inactivity. Set this value to `true`
     *  if you prefer not to remove inactive data, or if you prefer to
     *  do so manually using `scripts/evict-inactive.js`.
     */
    //disableIntegratedEviction: true,


    /*  Max Upload Size (bytes)
     *  this sets the maximum size of any one file uploaded to the server.
     *  anything larger than this size will be rejected
     *  defaults to 20MB if no value is provided
     */
    //maxUploadSize: 20 * 1024 * 1024,

    /*  Users with premium accounts (those with a plan included in their customLimit)
     *  can benefit from an increased upload size limit. By default they are restricted to the same
     *  upload size as any other registered user.
     *
     */
    //premiumUploadSize: 100 * 1024 * 1024,

    /* =====================
     *   DATABASE VOLUMES
     * ===================== */

    /*
     *  CryptPad stores each document in an individual file on your hard drive.
     *  Specify a directory where files should be stored.
     *  It will be created automatically if it does not already exist.
     */
    filePath: './datastore/',

    /*  CryptPad offers the ability to archive data for a configurable period
     *  before deleting it, allowing a means of recovering data in the event
     *  that it was deleted accidentally.
     *
     *  To set the location of this archive directory to a custom value, change
     *  the path below:
     */
    archivePath: './data/archive',

    /*  CryptPad allows logged in users to request that particular documents be
     *  stored by the server indefinitely. This is called 'pinning'.
     *  Pin requests are stored in a pin-store. The location of this store is
     *  defined here.
     */
    pinPath: './data/pins',

    /*  if you would like the list of scheduled tasks to be stored in
        a custom location, change the path below:
    */
    taskPath: './data/tasks',

    /*  if you would like users' authenticated blocks to be stored in
        a custom location, change the path below:
    */
    blockPath: './block',

    /*  CryptPad allows logged in users to upload encrypted files. Files/blobs
     *  are stored in a 'blob-store'. Set its location here.
     */
    blobPath: './blob',

    /*  CryptPad stores incomplete blobs in a 'staging' area until they are
     *  fully uploaded. Set its location here.
     */
    blobStagingPath: './data/blobstage',

    decreePath: './data/decrees',

    /* CryptPad supports logging events directly to the disk in a 'logs' directory
     * Set its location here, or set it to false (or nothing) if you'd rather not log
     */
    logPath: './data/logs',

    /* =====================
     *       Debugging
     * ===================== */

    /*  CryptPad can log activity to stdout
     *  This may be useful for debugging
     */
    logToStdout: false,

    /* CryptPad can be configured to log more or less
     * the various settings are listed below by order of importance
     *
     * silly, verbose, debug, feedback, info, warn, error
     *
     * Choose the least important level of logging you wish to see.
     * For example, a 'silly' logLevel will display everything,
     * while 'info' will display 'info', 'warn', and 'error' logs
     *
     * This will affect both logging to the console and the disk.
     */
    logLevel: 'info',

    /*  clients can use the /settings/ app to opt out of usage feedback
     *  which informs the server of things like how much each app is being
     *  used, and whether certain clientside features are supported by
     *  the client's browser. The intent is to provide feedback to the admin
     *  such that the service can be improved. Enable this with `true`
     *  and ignore feedback with `false` or by commenting the attribute
     *
     *  You will need to set your logLevel to include 'feedback'. Set this
     *  to false if you'd like to exclude feedback from your logs.
     */
    logFeedback: false,

    /*  CryptPad supports verbose logging
     *  (false by default)
     */
    verbose: false,

    /*  Surplus information:
     *
     *  'installMethod' is included in server telemetry to voluntarily
     *  indicate how many instances are using unofficial installation methods
     *  such as Docker.
     *
     */
    installMethod: 'unspecified',
};

Regards

Thanks for your reply!

I allowed myself to edit your message to include the config files directly within, not redirecting to some pad. 😊

Did you properly generated the TLS certificates? You must have the two domains (main and sandbox) within one single certificate.

Also I can see a few changes in your Nginx config file, differing from the official example we provide. I would invite you to start fresh from the example provided and only change the directives you need:

  • Nginx port
  • main domain
  • sandbox domain
  • api domain (same as main in your case)
  • files domain (same as main in your case)
  • server names
  • certificates TLS
  • root directory
  • add api & files domain to connect-src section

Don't touch anything else and don't change the order of the directives, it matters.

  • Gabx replied to this.

    Mathilde I allowed myself to edit your message to include the config files directly within, not redirecting to some pad. 😊
    No problem i will include them in the text from now on.

    The certificates have been generated by Letsencrypt for domains cryptpad.$mydomain and sandbox.$mydomain. For the api domain and the files one i used cryptpad.$mydomain.

    server {
        listen 4433 ssl http2;
    
        set $allowed_origins "*";
        # set $allowed_origins "https://${sandbox_domain}";
    
        set $main_domain "cryptpad.$mydomain";
        set $sandbox_domain "sandbox.$mydomain";
        set $api_domain "cryptpad.$mydomain";
        set $files_domain "cryptpad.$mydomain";
        server_name cryptpad.$mydomain sandbox.$mydomain;
    
        ssl_certificate         /etc/letsencrypt/live/cryptpad.$mydomain/fullchain.pem;
        ssl_certificate_key     /etc/letsencrypt/live/cryptpad.$mydomain/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/cryptpad.$mydomain/chain.pem;
    
        ssl_dhparam /etc/nginx/dhparam.pem; 
    
        ssl_session_timeout 5m;
        ssl_session_cache shared:SSL:5m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
        ssl_ecdh_curve secp384r1; 
    
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Content-Type-Options nosniff;
        add_header Access-Control-Allow-Origin "${allowed_origins}";
        # add_header X-Frame-Options "SAMEORIGIN";
        add_header Permissions-Policy interest-cohort=();
        add_header Cross-Origin-Resource-Policy cross-origin;
        add_header Cross-Origin-Embedder-Policy require-corp;
        root /var/www/cryptpad;
        index index.html;
        error_page 404 /customize.dist/404.html;
    
        if ($uri ~ ^(\/|.*\/|.*\.html)$) {
            set $cacheControl no-cache;
        }
        if ($args ~ ver=) {
            set $cacheControl max-age=31536000;
        }
     
        add_header Cache-Control $cacheControl;
        set $styleSrc   "'unsafe-inline' 'self' https://${main_domain}";
        set $connectSrc "'self' https://${main_domain} blob: wss://${api_domain} https://${sandbox_domain}";
        set $fontSrc    "'self' data: https://${main_domain}";
        set $imgSrc     "'self' data: blob: https://${main_domain}";
        set $frameSrc   "'self' https://${sandbox_domain} blob:";
        set $mediaSrc   "blob:";
        set $childSrc   "https://${main_domain}";
        set $workerSrc  "'self'";
        set $scriptSrc  "'self' resource: https://${main_domain}";
        set $frameAncestors "'self' https://${main_domain}";
        # set $frameAncestors "'self' https: vector:";
    
        set $unsafe 0;
        # the following assets are loaded via the sandbox domain
        # they unfortunately still require exceptions to the sandboxing to work correctly.
        if ($uri ~ ^\/(sheet|doc|presentation)\/inner.html.*$) { set $unsafe 1; }
        if ($uri ~ ^\/common\/onlyoffice\/.*\/.*\.html.*$) { set $unsafe 1; }
    
        # everything except the sandbox domain is a privileged scope, as they might be used to handle keys
        if ($host != $sandbox_domain) { set $unsafe 0; }
    
        if ($uri ~ ^\/unsafeiframe\/inner\.html.*$) { set $unsafe 1; }
    
        # privileged contexts allow a few more rights than unprivileged contexts, though limits are still applied
        if ($unsafe) {
            set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' resource: https://${main_domain}";
        }
    
        # Finally, set all the rules you composed above.
        add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc; frame-ancestors $frameAncestors";
    
    
        location ^~ /cryptpad_websocket {
            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;
    
            # WebSocket support (nginx 1.4)
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection upgrade;
        }
    
        location ^~ /customize.dist/ {
            # This is needed in order to prevent infinite recursion between /customize/ and the root
        }
        # try to load customizeable content via /customize/ and fall back to the default content
        # located at /customize.dist/
        # This is what allows you to override behaviour.
        location ^~ /customize/ {
            rewrite ^/customize/(.*)$ $1 break;
            try_files /customize/$uri /customize.dist/$uri;
        }
    
        # /api/config is loaded once per page load and is used to retrieve
        # the caching variable which is applied to every other resource
        # which is loaded during that session.
        location ~ ^/api/.*$ {
            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;
    
            # These settings prevent both NGINX and the API server
            # from setting the same headers and creating duplicates
            proxy_hide_header Cross-Origin-Resource-Policy;
            add_header Cross-Origin-Resource-Policy cross-origin;
            proxy_hide_header Cross-Origin-Embedder-Policy;
            add_header Cross-Origin-Embedder-Policy require-corp;
        }
    
        # encrypted blobs are immutable and are thus cached for a year
        location ^~ /blob/ {
            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' "${allowed_origins}";
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'application/octet-stream; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            add_header X-Content-Type-Options nosniff;
            add_header Cache-Control max-age=31536000;
            add_header 'Access-Control-Allow-Origin' "${allowed_origins}";
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';
            add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length';
            try_files $uri =404;
        }
    
        # the "block-store" serves encrypted payloads containing users' drive keys
        # these payloads are unlocked via login credentials. They are mutable
        # and are thus never cached. They're small enough that it doesn't matter, in any case.
        location ^~ /block/ {
            add_header X-Content-Type-Options nosniff;
            add_header Cache-Control max-age=0;
            try_files $uri =404;
        }
    
        # This block provides an alternative means of loading content
        # otherwise only served via websocket. This is solely for debugging purposes,
        # and is thus not allowed by default.
        #location ^~ /datastore/ {
            #add_header Cache-Control max-age=0;
            #try_files $uri =404;
        #}
    
        # The nodejs server has some built-in forwarding rules to prevent
        # URLs like /pad from resulting in a 404. This simply adds a trailing slash
        # to a variety of applications.
        location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban|sheet|support|admin|notifications|teams|calendar|presentation|doc|form|report|convert|checkup)$ {
            rewrite ^(.*)$ $1/ redirect;
        }
    
        # Finally, serve anything the above exceptions don't govern.
        try_files /customize/www/$uri /customize/www/$uri/index.html /www/$uri /www/$uri/index.html /customize/$uri;
    }

    The above nginx virtualhost file produced:

    2022/12/07 12:21:32 [error] 27191#27191: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 176.151.188.2, server: cryptpad.virebent.art, request: "GET /api/config?cb=184ec51c30f HTTP/2.0", upstream: "http://127.0.0.1:3000/api/config?cb=184ec51c30f", host: "cryptpad.virebent.art:4433", referrer: "https://cryptpad.virebent.art:4433/"

    I followed your indication.
    The $connectSrc is defined by variables:
    set $connectSrc "'self' https://${main_domain} blob: wss://${api_domain} https://${sandbox_domain}";
    This $connectSrc?

    Regards

    I think you missed to add the 4433 ports on your configuration file. See those lines.

    httpUnsafeOrigin: 'https://cryptpad.$mydomain:4433',
    httpSafeOrigin: "https://sandbox.$mydomain:4433",

    I have changed them but cryptpad is still unavailable.

    systemctl restart nginx.service cryptpad.service

    Didn't you missed some of the dependencies upon installation?

    The error I get from your instance are the following now:

    GET https://cryptpad.virebent.art:4433/api/config?cb=184ec8cba38 [HTTP/2 502 Bad Gateway 33ms]

    And then:

    Uncaught Error: Script error for "/api/config?cb=184ec819a4c", needed by: /common/boot.js?ver=1.0
    http://requirejs.org/docs/errors.html#scripterror
        makeError https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:168
        onScriptError https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1738
        load https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1943
        load https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1685
        load https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:834
        fetch https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:824
        check https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:856
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1176
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1557
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1161
        bind https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:134
        each https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:59
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1113
        init https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:788
        callGetModule https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1203
        completeLoad https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1590
        onScriptLoad https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1717
        load https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1942
        load https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1685
        load https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:834
        fetch https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:824
        check https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:856
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1176
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1557
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1161
        bind https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:134
        each https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:59
        enable https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1113
        init https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:788
        localRequire https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1460
        setTimeout handler*req.nextTick< https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1815
        localRequire https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1449
        configure https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1387
        requirejs https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:1794
        <anonymous> https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:2144
        <anonymous> https://cryptpad.virebent.art:4433/bower_components/requirejs/require.js?ver=2.3.5:2145
    require.js:168:17

    A few ideas to go forward:

    • What is the content of your /etc/systemd/system/cryptpad.service file?
    • Also, what are the permissions of /var/www/cryptpad?
    • What happens when you run CryptPad directly from it's directory with the proper user & node server?

    I launched:

    # su - user -c "npm install && bower install"
    npm WARN saveError ENOENT: no such file or directory, open '/home/user/package.json'
    npm WARN enoent ENOENT: no such file or directory, open '/home/user/package.json'
    npm WARN user No description
    npm WARN user No repository field.
    npm WARN user No README data
    npm WARN user No license field.
    up to date in 0.421s
    found 0 vulnerabilities
    bower                           ENOENT No bower.json present

    I have found this directory /usr/lib/node_modules/ owned by root.
    Is it ok ?
    It looks a permissions problem.

    Regards

    It looks like CryptPad isn't running. You have to install it under a dedicated user, not running it as root.

    Create a dedicated user

    adduser cryptpad --disabled-password

    Switch to it

    su - cryptpad

    And then follow the instructions of the administrator guide: https://docs.cryptpad.org/en/admin_guide/installation.html#software

    Glad you managed to do it. Congrats! 🎉

    2 years later