wip - cryptpad
This commit is contained in:
parent
2e99f5b18d
commit
1c691cd333
3 changed files with 629 additions and 6 deletions
191
nixos/boxes/vpsfree1/cryptpad.config.js
Normal file
191
nixos/boxes/vpsfree1/cryptpad.config.js
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
/* globals module */
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
httpUnsafeOrigin: 'https://notes.purrfect.estate',
|
||||||
|
httpSafeOrigin: "https://notes-sandbox.purrfect.estate",
|
||||||
|
httpAddress: '::',
|
||||||
|
httpPort: 3000,
|
||||||
|
httpSafePort: 3001,
|
||||||
|
|
||||||
|
/* =====================
|
||||||
|
* 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=]",
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* =====================
|
||||||
|
* 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: 'debug',
|
||||||
|
|
||||||
|
/* 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',
|
||||||
|
};
|
||||||
|
|
215
nixos/boxes/vpsfree1/cryptpad.nginx.config
Normal file
215
nixos/boxes/vpsfree1/cryptpad.nginx.config
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
# This file is included strictly as an example of how Nginx can be configured
|
||||||
|
# to work with CryptPad. This example WILL NOT WORK AS IS. For best results,
|
||||||
|
# compare the sections of this configuration file against a working CryptPad
|
||||||
|
# installation (http server by the Nodejs process). If you are using CryptPad
|
||||||
|
# in production and require professional support please contact sales@cryptpad.fr
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 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 "notes.purrfect.estate";
|
||||||
|
set $sandbox_domain "notes-sandbox.purrfect.estate";
|
||||||
|
|
||||||
|
# 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 "notes.purrfect.estate";
|
||||||
|
set $files_domain "notes.purrfect.estate";
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
# any static assets loaded with "ver=" in their URL will be cached for a year
|
||||||
|
if ($args ~ ver=) {
|
||||||
|
set $cacheControl max-age=31536000;
|
||||||
|
}
|
||||||
|
if ($uri ~ ^/.*(\/|\.html)$) {
|
||||||
|
set $cacheControl no-cache;
|
||||||
|
}
|
||||||
|
# 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; 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/.*$ {
|
||||||
|
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 /www/$uri /www/$uri/index.html /customize/$uri;
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
{ config, pkgs, inputs, lib, ... }: {
|
{ config, pkgs, inputs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
imports = [ ../nginx.nix ];
|
imports = [ ../nginx.nix ];
|
||||||
|
|
||||||
|
@ -7,17 +9,232 @@
|
||||||
"notes.purrfect.estate" = {
|
"notes.purrfect.estate" = {
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
locations."/" = {
|
serverAliases = [ "notes-sandbox.purrfect.estate" ];
|
||||||
proxyPass = "http://localhost:9005";
|
extraConfig = ''
|
||||||
proxyWebsockets = true;
|
set $main_domain "notes.purrfect.estate";
|
||||||
};
|
set $sandbox_domain "notes-sandbox.purrfect.estate";
|
||||||
|
|
||||||
|
# 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 "notes.purrfect.estate";
|
||||||
|
set $files_domain "notes.purrfect.estate";
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
# any static assets loaded with "ver=" in their URL will be cached for a year
|
||||||
|
if ($args ~ ver=) {
|
||||||
|
set $cacheControl max-age=31536000;
|
||||||
|
}
|
||||||
|
if ($uri ~ ^/.*(\/|\.html)$) {
|
||||||
|
set $cacheControl no-cache;
|
||||||
|
}
|
||||||
|
# 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; 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;
|
||||||
|
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";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Cache-Control $cacheControl;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Cache-Control $cacheControl;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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;
|
||||||
|
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";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Cache-Control $cacheControl;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
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';
|
||||||
|
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";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Cache-Control $cacheControl;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
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;
|
||||||
|
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";
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
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 /www/$uri /www/$uri/index.html /customize/$uri;
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualisation.oci-containers.containers.cryptpad = {
|
virtualisation.oci-containers.containers.cryptpad = {
|
||||||
image = "promasu/cryptpad";
|
image = "promasu/cryptpad";
|
||||||
ports = [ "9005:3000" ];
|
ports = [ "9005:3000" "9006:3001" ];
|
||||||
|
volumes = [ "${./cryptpad.config.js}:/cryptpad/config/config.js" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue