JUDLEX

Technical guide: preparing the firm's server

For whoever runs the firm's server. What JUDLEX does over WebDAV, S3 and SFTP, which permissions it needs and how to set it up properly.

This page is for the IT technician who prepares the firm's storage. If you use JUDLEX and do not run the server, If an IT person runs the server, what to ask them for is all you need.

It explains what JUDLEX does on the server, what it needs from it, and how to set it up so it works without surprises. Everything below applies to all three connection types unless it says otherwise.

Common to all three

Network

  • JUDLEX only opens outgoing connections from the firm's computer to the server. No port has to be opened towards the computers.

  • WebDAV and S3 always go over HTTPS. With http:// it only connects to a server on the same computer (localhost, 127.0.0.1 or ::1); a local network address over http:// is refused.

  • It does not follow redirects. If the server answers with a 3xx, JUDLEX sends nothing to the new address: it tells the user what it is, so they can type it in. The only exception is a redirect within the same server that only adds or removes the trailing slash of a WebDAV folder. So give the final address (with its https://, its port and its path), not one that redirects.

  • Credentials never go inside the address (https://user:password@… is refused).

  • Timeouts: 20 seconds to connect and 120 for each normal answer. An upload has no time limit while it moves; it is given up if 120 seconds pass without sending anything, or if after the last byte the server does not answer within 5 minutes plus one second per MiB (30 minutes at most). A proxy in front of the server has to allow for those times.

  • It only retries what is temporary (network errors, 429, 503, 423 and 5xx except 501), up to five times, waiting 1, 2, 4 and 8 seconds, or what Retry-After says in seconds, up to 60.

Certificates

  • WebDAV and S3 check the certificate against the operating system's trusted certificates. With a certificate from a recognised authority (Let's Encrypt, for example) nothing needs doing.

  • With its own certificate (a NAS that signs its own, or access by IP), the user can pin the SHA-256 fingerprint of the server's certificate (the leaf, not the authority's): JUDLEX trusts that exact certificate and no other, without checking the name or the dates. If the certificate changes (renewal included), it stops connecting until the user compares and pins the new fingerprint. Give the firm that fingerprint so they can compare it with the one JUDLEX shows (with or without colons, upper or lower case, it does not matter). On Linux it is shown by openssl x509 -in cert.pem -noout -fingerprint -sha256.

  • TLS 1.2 or 1.3. Client certificates are not used.

  • SFTP does not use TLS: the server's key is pinned (see below).

What JUDLEX creates on the server

Inside the folder it is given (the WebDAV address, the bucket and its prefix, or the SFTP folder), JUDLEX works only in a JUDLEX subfolder, and in the office folder if it is used for sharing:

<connection folder>/
β”œβ”€β”€ JUDLEX/
β”‚   β”œβ”€β”€ probe/                 test files from "Test", deleted straight away
β”‚   β”œβ”€β”€ backup/<lineage>/      each computer's backup
β”‚   └── outbox/                what is shared by link (encrypted), expires after 14 days (7 on S3)
└── JUDLEX-despacho/           only if sharing through the office folder
    β”œβ”€β”€ packages/  inbox/  done/  presence/
  • Names only use unaccented letters, digits, ., - and _, up to 200 bytes.

  • Each computer has its own backup lineage (backup/<32 hex digits> when encrypted, backup/plain-<…> when not). Several computers can use the same connection without getting in each other's way.

  • Encrypted backup: the server only holds files with meaningless names and rounded sizes. What is inside cannot be known.

  • Unencrypted backup (the default, unless the firm chooses to encrypt it): files/ holds the documents with their folders and names, and snapshots/ holds the JUDLEX database as it is and a list with each file's hash. Whoever can read that folder can read the case files. Give access to it to JUDLEX only and protect it as you would protect the firm itself.

  • What is shared with a colleague is always encrypted.

  • Passwords, keys and secrets are never stored on the server: they stay on the computer.

How much it writes, and when

  • The backup runs on its own when there are changes, after 10 minutes without activity and at most once an hour, and at least once a day. Each run uploads the whole database (one file) and only the new or changed documents.

  • What is kept: the last backup of each of the last 30 days and the last of each of the last 12 months. JUDLEX deletes what is no longer needed, and nothing else.

  • The office folder is checked every 5 minutes (each computer can change its interval). If the server rejects the password, JUDLEX stops checking until the user changes the details, and the backup tries again at most once an hour: it will not trigger fail2ban or Nextcloud's brute-force protection.

  • "Test" writes a test file in JUDLEX/probe/, reads it, lists the folder, deletes it and checks it is gone. If listing or deleting is not allowed, the test says so. Removing the connection in JUDLEX does not delete anything on the server.

  • Leftovers of cut uploads: temporary files more than a day old are removed automatically (on WebDAV and SFTP, when their folder is listed; on S3, unfinished multipart uploads are aborted).

WebDAV

What the server needs

  • Basic authentication over HTTPS. Digest, NTLM and Negotiate are not supported: if the server only offers those, JUDLEX says so.

  • PROPFIND with Depth: 0 and Depth: 1 answering 207 Multi-Status. Depth: infinity is not used.

  • MKCOL, PUT with Content-Length, GET, and DELETE of folders with their contents.

  • Recommended: MOVE with an absolute Destination and Overwrite, and accepting names that start with a dot. JUDLEX uploads each file to a hidden temporary (.jlx-tmp-…) and renames it afterwards, so a half-written file never sits under its real name. If the server does not allow it, it uploads directly.

  • LOCK, COPY and PROPPATCH are not used.

  • You will see 405 answers to MKCOL in the logs: that is JUDLEX checking the folder already exists. They are normal.

Behind a proxy (nginx, Apache, a load balancer)

  • Let the PROPFIND, MKCOL, MOVE, PUT, GET and DELETE methods through, and the Depth, Destination and Overwrite headers.

  • Destination carries the absolute address JUDLEX sees: if the proxy changes the path prefix, it has to rewrite that too. JUDLEX checks the first MOVE and stops using it if the file does not appear where it should.

  • Size: outside Nextcloud, each file goes in a single PUT, whatever its size. Set the request body limit (client_max_body_size in nginx, LimitRequestBody in Apache) to the largest document the firm may have, or remove it for that path. If the server returns 413, JUDLEX tells the user the server does not accept files that large.

  • Timeouts: after receiving a large file, the server may take a while to answer. Allow at least 5 minutes for the answer (proxy_read_timeout) and do not cut slow uploads.

  • Do not redirect http to https expecting JUDLEX to follow: give it the https:// address directly.

Nextcloud and ownCloud

  • The address has to be the user's files: https://<server>/remote.php/dav/files/<user>/<folder> (or the old …/remote.php/webdav/<folder>). A bare …/remote.php/dav/, without files/<user>, is refused.

  • Use an app password just for JUDLEX.

  • On these servers the temporary plus MOVE is not used (Nextcloud already writes atomically). Files over 64 MiB are uploaded in 32 MiB chunks through Nextcloud's chunked upload (/remote.php/dav/uploads/<user>/…), if the server announces it in its capabilities.

  • Share links: JUDLEX creates read-only public links through Nextcloud's sharing API (/ocs/v2.php/…), with an expiry date (14 days, or less if the server enforces less) and no password: the content is encrypted and only the computers it is meant for can open it. If the server enforces link passwords or has links switched off, JUDLEX says so and does not offer them. For them to work: Administration settings β†’ Sharing, public links allowed, no enforced password. The server has to be reachable from the internet with a recognised certificate: the colleague opens it without the pinned fingerprint. With a local network address, JUDLEX does not offer links.

  • A 507 (no space) and a 423 (file locked, for example during a virus scan) are understood: the first is shown to the user as storage full; the second is retried.

S3-compatible

How it talks to the server

  • SigV4 signature in the address of each request, valid for one hour. The computer's clock has to be right: otherwise the server refuses it and JUDLEX tells the user to set the time.

  • Virtual-host addresses (<bucket>.<server>) by default, and path-style (<server>/<bucket>) if the option is ticked or when needed: with an IP, with localhost, or with a bucket name containing dots, capitals or _. For MinIO, Garage or SeaweedFS behind a single name, tick path style.

  • The region is worked out from the address for known providers; otherwise us-east-1. If the bucket is in another region, JUDLEX tells the user which, if the server says.

  • The bucket has to exist: JUDLEX does not create it or read its configuration.

  • A path in the service address is kept (a proxy at /s3/, for example), but …/<bucket>/folder is refused: the folder goes in its own field.

Operations it uses

ListObjectsV2 (with delimiter=/ and paging; if the server gives no continuation-token, it uses start-after or marker), HeadObject, GetObject, PutObject up to 16 MiB, multipart upload above that (CreateMultipartUpload, UploadPart one at a time, CompleteMultipartUpload, AbortMultipartUpload), ListMultipartUploads to abort unfinished uploads older than 24 hours, and DeleteObjects in batches of 1,000 (if missing, it deletes one by one). For sharing by link, a signed GetObject URL valid for 7 days at most.

  • Parts are 8 MiB, or larger if the file would otherwise need more than 10,000 parts.

  • To avoid overwriting what already exists, it sends If-None-Match: * when creating. If the server does not support it, it stops sending it and checks first with HeadObject.

  • It does not create folder objects: folders are prefixes.

  • Versioning and object lock: JUDLEX does not handle them. With versioning on, what JUDLEX deletes (old backups, temporaries) stays as an old version taking up space; if you turn it on, add a lifecycle rule that expires non-current versions. With object lock, deletes will fail.

The minimal access policy

A key only for JUDLEX and only for that bucket. In AWS IAM (the equivalent elsewhere):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket", "s3:ListBucketMultipartUploads"],
      "Resource": "arn:aws:s3:::judlex-firm"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject", "s3:AbortMultipartUpload"],
      "Resource": "arn:aws:s3:::judlex-firm/*"
    }
  ]
}
  • If the bucket is shared with other things and JUDLEX works under a prefix, you can limit objects to judlex-firm/<prefix>/* and s3:ListBucket with the s3:prefix condition.

  • s3:ListBucket is essential: without it, asking for a file that does not exist returns 403 instead of 404, and the test fails.

  • s3:ListBucketMultipartUploads is optional (without it unfinished uploads are not cleaned up; add a lifecycle rule that aborts them).

  • No permission on the bucket's configuration is needed.

SFTP

SSH connection

  • Modern algorithms first: key exchange curve25519-sha256 (and mlkem768x25519-sha256), ciphers chacha20-poly1305 and AES-GCM/CTR, MACs hmac-sha2-256/512. As a last resort, for old servers, also ecdh-sha2-nistp*, diffie-hellman-group14-sha1, AES-CBC and hmac-sha1. diffie-hellman-group1-sha1, 3des-cbc, DSA keys and compression are not offered. If nothing matches, JUDLEX tells the user what the server offers.

  • The server's key is always pinned: SHA256 fingerprint (as ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub prints it) and type (ed25519, ecdsa or rsa). If it changes, JUDLEX does not connect. If you reinstall the server or change its keys, tell the firm and give them the new fingerprint.

  • It keeps the connection alive every 30 seconds and closes it after 10 minutes unused. If it drops, it reconnects once without the user noticing.

How it signs in

  • With a key (recommended). JUDLEX generates an Ed25519 key on the computer and gives the user the public line for authorized_keys. It can also use a key you give it: OpenSSH (Ed25519, ECDSA or RSA), PEM, PKCS#8 or PuTTY, with or without a passphrase (if it has one, JUDLEX opens it with it and keeps it on that computer without one). Giving the firm a key of yours is handy if they will restore the backup on another computer: the same key is used there and the server does not have to be touched.

  • With a password, through password or, if that is all the server offers, keyboard-interactive with a single question.

  • No second factor (a code, or key and password together: AuthenticationMethods publickey,password). For the JUDLEX user, leave a single method.

  • RSA keys sign with rsa-sha2-512 or rsa-sha2-256; ssh-rsa (SHA-1) only if the server announces nothing else.

What the server needs

  • The sftp subsystem enabled for that user (Subsystem sftp internal-sftp or the system's sftp-server). SFTP version 3.

  • A login that prints nothing. An echo in .bashrc or a shell welcome message breaks SFTP; JUDLEX detects it and tells the user. With internal-sftp and ForceCommand internal-sftp it does not happen.

  • OpenSSH extensions it uses when present: posix-rename@openssh.com (atomic replace), fsync@openssh.com (flush to disk before renaming), statvfs@openssh.com (check free space before uploading a file of 8 MiB or more) and limits@openssh.com (block size, up to 64 KiB). Without them it still works, with fewer guarantees.

  • Each file is uploaded to a hidden temporary (.jt- and ten digits) in the same folder and then renamed. Temporaries more than a day old are removed automatically.

The folder

  • Empty: the user's home folder (in a chroot, the folder where it starts).

  • Without a leading slash (backups): relative to the home folder. With one (/firm): absolute; inside a chroot, absolute within the chroot.

  • It has to exist already (except the home folder). JUDLEX does not create it, so a typo never ends up saving somewhere else; inside it, it creates its JUDLEX folder.

Permissions of what it creates

  • Private by default: folders 0700 and files 0600. Only the JUDLEX user can read them.

  • In a team folder: if the connection folder is writable by its group, JUDLEX takes it as a folder shared by the firm and creates its items as 0770 and 0660, keeping the folder's setgid bit so the group carries down. That way several colleagues signing in as different users of the same group can use the same folder (the office folder, or a backup another computer has to read). It sets the mode again after creating each file, even with a server umask of 022.

  • A folder the group can only read (0750, 0755) does not count as shared.

  • Bear in mind that with an unencrypted backup, the whole group will be able to read the documents.

For example, for a team folder on a Linux server:

groupadd firm
usermod -aG firm ana
usermod -aG firm luis
mkdir -p /srv/firm
chgrp firm /srv/firm
chmod 2770 /srv/firm

And in JUDLEX, as Folder, /srv/firm.

An SFTP-only user, locked into its folder

Match User judlex
    ChrootDirectory /srv/sftp/judlex
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
    PasswordAuthentication no

/srv/sftp/judlex has to be owned by root and not writable by anyone else (OpenSSH requires it). Create a folder for the user inside, for example /srv/sftp/judlex/backups owned by judlex, and in JUDLEX set Folder to /backups. The public key goes in the user's authorized_keys, outside the chroot (~judlex/.ssh/authorized_keys, or wherever AuthorizedKeysFile says).

Space

  • With statvfs@openssh.com, JUDLEX checks a large file fits before uploading it, and if the disk fills up it reports "storage full".

  • A per-user quota cannot be queried over SFTP, and OpenSSH answers an exhausted quota with a failure and no explanation. When that happens with free disk space, JUDLEX tells the user their account has most likely reached its space limit. If you set quotas, leave room for 30 daily and 12 monthly backups.

Checklist

  • Final address over https:// (or SFTP server with its port), without redirects.

  • A recognised certificate, or the certificate's SHA-256 fingerprint for the firm.

  • A user or key only for JUDLEX, with access only to its folder or bucket.

  • Permission to list, read, write and delete in that folder.

  • The bucket (S3) or the folder (SFTP) already created.

  • Proxy: WebDAV methods allowed, no small size limit and generous timeouts.

  • SFTP: the server key's fingerprint for the firm, a single sign-in method and a login that prints nothing.

  • If the backup is unencrypted: nobody else can read that folder.

  • Press Test in JUDLEX and check it passes.

Was this page helpful?