Skip to main content

File Storage

Yopass encrypts files client-side before upload. The server stores only the opaque binary ciphertext. Three storage backends are available.


Backends

Database (default)

Files are stored alongside text secrets in Memcached or Redis. No extra configuration is needed.

yopass-server # file-store defaults to the database backend

Limitations:

  • Memcached has a default item size limit of ~1 MB. Files larger than this will fail to store.
  • Redis has a higher default limit but is still not ideal for large binary objects.
  • A warning is printed at startup if --max-file-size exceeds 1 MB without a dedicated file store configured.

Use the database backend when file uploads are small or infrequent and you want to keep the deployment simple.


Disk

Files are written to the local filesystem as encrypted binary blobs. A sidecar .meta file tracks expiration for each upload.

yopass-server \
--file-store disk \
--file-store-path /data/yopass-files

The directory is created automatically if it does not exist. Files are organized in two-character subdirectories (e.g. /data/yopass-files/ab/abcdef123.bin).

A background goroutine scans for and deletes expired files based on the .meta sidecar. The scan interval defaults to 60 seconds and is controlled by --cleanup-interval.

Suitable for: single-node deployments, moderate file sizes, no object storage dependency.


S3

Files are stored in an AWS S3 bucket or any S3-compatible service (MinIO, Cloudflare R2, Backblaze B2, etc.).

# AWS S3
yopass-server \
--file-store s3 \
--file-store-s3-bucket my-yopass-bucket

# S3-compatible (MinIO, Cloudflare R2, etc.)
yopass-server \
--file-store s3 \
--file-store-s3-bucket my-bucket \
--file-store-s3-endpoint http://minio:9000 \
--file-store-s3-region us-east-1

AWS credentials are loaded from the standard credential chain: environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), ~/.aws/credentials, IAM instance profiles, etc.

Suitable for: multi-node deployments, large files, production environments where durability and scalability matter.


Flags

FlagEnv varDefaultDescription
--file-storeFILE_STORE(database)Backend: disk or s3. Omit for database.
--file-store-pathFILE_STORE_PATH/tmp/yopass-filesBase directory for disk backend
--file-store-s3-bucketFILE_STORE_S3_BUCKETS3 bucket name (required for S3 backend)
--file-store-s3-prefixFILE_STORE_S3_PREFIXyopass/Key prefix for all stored objects
--file-store-s3-endpointFILE_STORE_S3_ENDPOINTCustom endpoint URL for S3-compatible services
--file-store-s3-regionFILE_STORE_S3_REGIONus-east-1AWS region
--max-file-sizeMAX_FILE_SIZE512KBMaximum upload size. Accepts KB, MB, GB suffixes.
--cleanup-intervalCLEANUP_INTERVAL60Cleanup scan frequency in seconds (disk and S3 backends)
--disable-file-cleanupDISABLE_FILE_CLEANUPfalseDisable the built-in cleanup goroutine
--disable-uploadDISABLE_UPLOADfalseDisable all file upload endpoints

File size limits

The --max-file-size flag accepts human-readable sizes:

--max-file-size 10KB
--max-file-size 512KB
--max-file-size 10MB
--max-file-size 1.5GB

Without a valid --license-key, file size is capped at 1 MB regardless of what --max-file-size is set to. A warning is logged when the cap is applied.


Expiration and cleanup

Every uploaded file is given an expiration time matching the TTL chosen by the uploader (1 hour, 1 day, or 1 week). The built-in cleanup goroutine removes expired files on a regular interval.

Disk cleanup

The goroutine walks the --file-store-path directory, reads each .meta file, and deletes the corresponding .bin and .meta pair when expired.

S3 cleanup

The goroutine lists all objects in the bucket under the configured prefix, reads their yopass-expires tag, and calls DeleteObject for any that have passed their expiry. At scale this becomes expensive — see S3 lifecycle rules for the recommended alternative.

Disabling built-in cleanup

yopass-server --disable-file-cleanup

Use this flag when managing expiration externally (e.g. via S3 lifecycle rules or an external cron job).


S3 lifecycle rules

The built-in S3 cleanup scans and tags every object on each sweep. For buckets with many objects, this generates significant API costs. The recommended approach for production is to configure an S3 lifecycle rule and disable the built-in goroutine.

Since the maximum secret TTL is 1 week, a rule that deletes objects older than 7 days covers all cases:

{
"Rules": [
{
"ID": "yopass-expiration",
"Filter": { "Prefix": "yopass/" },
"Status": "Enabled",
"Expiration": { "Days": 7 }
}
]
}

Apply the rule via the AWS CLI:

aws s3api put-bucket-lifecycle-configuration \
--bucket my-yopass-bucket \
--lifecycle-configuration file://lifecycle.json

Then start Yopass without the cleanup goroutine:

yopass-server \
--file-store s3 \
--file-store-s3-bucket my-yopass-bucket \
--disable-file-cleanup

MinIO example

docker run -d \
-p 9000:9000 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=minioadmin \
minio/minio server /data

# Create the bucket
mc alias set local http://localhost:9000 minioadmin minioadmin
mc mb local/yopass-files

# Start Yopass
AWS_ACCESS_KEY_ID=minioadmin \
AWS_SECRET_ACCESS_KEY=minioadmin \
yopass-server \
--file-store s3 \
--file-store-s3-bucket yopass-files \
--file-store-s3-endpoint http://localhost:9000 \
--file-store-s3-region us-east-1

Docker Compose example (disk)

services:
yopass:
image: ghcr.io/jhaals/yopass:latest
ports:
- "1337:1337"
volumes:
- yopass-files:/data/yopass-files
environment:
MEMCACHED: memcached:11211
FILE_STORE: disk
FILE_STORE_PATH: /data/yopass-files
MAX_FILE_SIZE: 50MB
depends_on:
- memcached

memcached:
image: memcached

volumes:
yopass-files:

Docker Compose example (S3)

services:
yopass:
image: ghcr.io/jhaals/yopass:latest
ports:
- "1337:1337"
environment:
MEMCACHED: memcached:11211
FILE_STORE: s3
FILE_STORE_S3_BUCKET: my-yopass-bucket
FILE_STORE_S3_REGION: eu-west-1
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
DISABLE_FILE_CLEANUP: "true" # using S3 lifecycle rules instead
depends_on:
- memcached

memcached:
image: memcached