Skip to content

Commit 6a42ee8

Browse files
authored
feat: Add Paperless-NGX (#183)
* feat(paperless): Add Paperless Ngx service * feat(paperless): Add admin user and password to environment configuration * fix(paperless): Update PAPERLESS_URL to remove redundant path
1 parent 7d4c456 commit 6a42ee8

6 files changed

Lines changed: 366 additions & 1 deletion

File tree

.env.example

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
COMPOSE_PROFILES=
22
COMPOSE_PATH_SEPARATOR=:
3-
COMPOSE_FILE=docker-compose.yml:adguardhome/docker-compose.yml:tandoor/docker-compose.yml:joplin/docker-compose.yml:homeassistant/docker-compose.yml:immich/docker-compose.yml:vaultwarden/docker-compose.yml:privoxy/docker-compose.yml
3+
COMPOSE_FILE=docker-compose.yml:adguardhome/docker-compose.yml:tandoor/docker-compose.yml:joplin/docker-compose.yml:homeassistant/docker-compose.yml:immich/docker-compose.yml:vaultwarden/docker-compose.yml:privoxy/docker-compose.yml:paperless/docker-compose.yml
44
USER_ID=1000
55
GROUP_ID=1000
66
TIMEZONE="America/New_York"
@@ -50,3 +50,5 @@ IMMICH_DB_PASSWORD=postgres
5050
CALIBRE_USERNAME=admin
5151
CALIBRE_PASSWORD=admin123
5252
SEERR_HOSTNAME="seerr.${BASE_HOSTNAME}"
53+
PAPERLESS_ADMIN_USER=admin
54+
PAPERLESS_ADMIN_PASSWORD=changeme

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ I am running it in Ubuntu Server 22.04; I also tested this setup on a [Synology
4545
- [Home Assistant](#home-assistant)
4646
- [Immich](#immich)
4747
- [Vaultwarden](#vaultwarden)
48+
- [Paperless Ngx](#paperless-ngx)
4849
- [Customization](#customization)
4950
- [Optional: Using the VPN for \*arr apps](#optional-using-the-vpn-for-arr-apps)
5051
- [Synology Quirks](#synology-quirks)
@@ -90,6 +91,7 @@ I am running it in Ubuntu Server 22.04; I also tested this setup on a [Synology
9091
| [Cross-Seed](https://github.com/cross-seed/cross-seed) | Optional - Cross-Seed is a tool for automating the cross-seeding of torrents<br/>Enable with `COMPOSE_PROFILES=cross-seed` | [cross-seed/cross-seed](https://ghcr.io/cross-seed/cross-seed) | |
9192
| [Autobrr](https://github.com/autobrr/autobrr) | Optional - Autobrr is a tool for automating the downloading of torrents<br/>Enable with `COMPOSE_PROFILES=autobrr` | [autobrr/autobrr](https://ghcr.io/autobrr/autobrr) | /autobrr |
9293
| [Suggestarr](github.com/giuseppe99barchetta/SuggestArr) | Optional - SuggestArr is a project designed to automate media content recommendations and download requests<br/>Enable with `COMPOSE_PROFILES=suggestarr` | [ciuse99/suggestarr](https://hub.docker.com/r/ciuse99/suggestarr) | /suggestarr |
94+
| [Paperless Ngx](https://paperless-ngx.com) | Optional - Document management system for organizing and searching your documents<br/>Enable with `COMPOSE_PROFILES=paperless` | [paperless-ngx/paperless-ngx](https://ghcr.io/paperless-ngx/paperless-ngx) | /paperless |
9395

9496
Optional containers are not enabled by default, they need to be enabled,
9597
see [Optional Services](#optional-services) for more information.
@@ -466,6 +468,10 @@ See [here](./immich/README.md).
466468

467469
See [here](./vaultwarden/README.md).
468470

471+
### Paperless Ngx
472+
473+
See [here](./paperless/README.md).
474+
469475
## Customization
470476

471477
You can override the configuration of a service or add new services by creating a new `docker-compose.override.yml` file,

paperless/.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
PAPERLESS_SECRET_KEY=
2+
3+
PAPERLESS_TIME_ZONE=America/New_York
4+
5+
PAPERLESS_OCR_LANGUAGE=eng

paperless/README.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# Paperless Ngx
2+
3+
Document management system for organizing, indexing, and searching your documents.
4+
5+
## Installation
6+
7+
Enable Paperless by setting `COMPOSE_PROFILES=paperless`.
8+
9+
Paperless will be accessible at `/paperless`.
10+
11+
On first run, an admin account will be created with the credentials specified in `paperless/.env`.
12+
13+
## Environment Variables
14+
15+
| Variable | Description | Default |
16+
|----------------------------|-------------------------------------------------|-----------------|
17+
| `PAPERLESS_SECRET_KEY` | Secret key for production, generate with `openssl rand -base64 32` | |
18+
| `PAPERLESS_TIME_ZONE` | Timezone for the container | `America/New_York` |
19+
| `PAPERLESS_OCR_LANGUAGE` | Default OCR language | `eng` |
20+
| `PAPERLESS_ADMIN_USER` | Admin username | `admin` |
21+
| `PAPERLESS_ADMIN_PASSWORD` | Admin password | `changeme` |
22+
23+
## Backup
24+
25+
Paperless data can be backed up to any cloud storage product using [Restic](https://restic.readthedocs.io/) via [resticker](https://github.com/djmaze/resticker).
26+
27+
Restic provides:
28+
- **Incremental backups**: Only changed data is backed up
29+
- **Deduplication**: Identical content across snapshots uses minimal space
30+
- **Encryption**: All data encrypted with your repository password
31+
- **Compression**: Optional, doesn't interfere with deduplication
32+
- **Remote backends**: S3, B2, SFTP, Rclone remotes, and more
33+
34+
### What Gets Backed Up
35+
36+
- **Data directory** (`/usr/src/paperless/data`): SQLite database and settings
37+
- **Media directory** (`/usr/src/paperless/media`): Documents, thumbnails, and attachments
38+
39+
### What Is Excluded
40+
41+
- **Thumbnails** (`/data/media/.thumbnails/`): Can be regenerated
42+
43+
### Initial Setup
44+
45+
#### 1. Configure Backup Environment
46+
47+
Copy the backup environment template and customize it:
48+
49+
```bash
50+
cp paperless/backup.env.example paperless/backup.env
51+
```
52+
53+
Edit `paperless/backup.env` and set the following:
54+
55+
| Variable | Description | Example |
56+
|-----------------------|-----------------------------------------------|----------------------------|
57+
| `RESTIC_REPOSITORY` | Backup destination URI for Restic | See examples below |
58+
| `RESTIC_PASSWORD` | Strong password to encrypt the repository | Generate with `openssl rand -base64 32` |
59+
| `CRON` | Backup schedule (cron format with seconds) | `0 30 3 * * *` (3:30 AM daily) |
60+
| `TIMEZONE` | Timezone for cron scheduling | `America/New_York` |
61+
| `RESTIC_FORGET_ARGS` | Backup retention policy | `--keep-last 7 --keep-daily 7 --keep-weekly 4 --keep-monthly 3` |
62+
63+
#### 2. Choose Your Backup Destination
64+
65+
Restic supports multiple backends. Pick one based on your infrastructure:
66+
67+
**Rclone Remote** (Optional - reuse existing rclone configuration):
68+
69+
Rclone is optional. Use this only if your `RESTIC_REPOSITORY` URI starts with `rclone:`. If you prefer to use Rclone, it allows you to back up to any service supported by Rclone (S3, B2, SFTP, Google Drive, OneDrive, Dropbox, etc.) without direct Restic support, or if you want to reuse existing Rclone configurations.
70+
71+
First, configure your rclone remote destination:
72+
73+
```bash
74+
docker compose run --rm -it paperless-backup rclone config
75+
```
76+
77+
This interactive command will guide you through:
78+
1. Creating a new remote (choose `n`)
79+
2. Naming your remote (e.g., `backup-s3`, `backup-b2`, `backup-sftp`, etc.)
80+
3. Selecting your storage type (S3, B2, SFTP, etc.)
81+
4. Entering credentials and configuration
82+
83+
The configuration will be saved to `paperless/.rclone/rclone.conf`. Do not manually edit this file; use the `rclone config` command above to modify it.
84+
85+
Then set in `backup.env`:
86+
87+
```bash
88+
RESTIC_REPOSITORY=rclone:myremote:/nas-backups/paperless
89+
```
90+
91+
This allows you to use any rclone-supported backend seamlessly.
92+
93+
**S3-Compatible (Direct)** (AWS, Wasabi, MinIO, DigitalOcean Spaces, etc. - no Rclone needed):
94+
95+
You can also back up directly to S3-compatible services without using Rclone:
96+
97+
```bash
98+
# Set in backup.env:
99+
RESTIC_REPOSITORY=s3:s3.amazonaws.com/my-bucket/paperless
100+
101+
# Or for S3-compatible services:
102+
RESTIC_REPOSITORY=s3:https://s3.wasabisys.com/my-bucket/paperless
103+
104+
# Additional environment variables:
105+
AWS_ACCESS_KEY_ID=your_key
106+
AWS_SECRET_ACCESS_KEY=your_secret
107+
```
108+
109+
**Backblaze B2** (Direct - no Rclone needed):
110+
```bash
111+
# Set in backup.env:
112+
RESTIC_REPOSITORY=b2:my-bucket:paperless
113+
114+
# And provide credentials:
115+
B2_ACCOUNT_ID=your_account_id
116+
B2_ACCOUNT_KEY=your_account_key
117+
```
118+
119+
**SFTP** (Direct - no Rclone needed):
120+
```bash
121+
# Set in backup.env:
122+
RESTIC_REPOSITORY=sftp://user@backup.example.com/paperless
123+
124+
# Password authentication is interactive or set:
125+
SFTP_PASSWORD=your_sftp_password
126+
```
127+
128+
**Local Path** (NAS mounted volume or local directory - no Rclone needed):
129+
```bash
130+
# Set in backup.env:
131+
RESTIC_REPOSITORY=/mnt/backup-drive/paperless
132+
133+
# Ensure the directory exists and is writable:
134+
mkdir -p /mnt/backup-drive/paperless
135+
```
136+
137+
**Google Cloud Storage** (Direct - no Rclone needed):
138+
```bash
139+
# Set in backup.env:
140+
RESTIC_REPOSITORY=gs://my-bucket/paperless
141+
142+
# And provide credentials (via service account JSON):
143+
GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
144+
```
145+
146+
**Azure Blob Storage** (Direct - no Rclone needed):
147+
```bash
148+
# Set in backup.env:
149+
RESTIC_REPOSITORY=azure://paperless-container/paperless
150+
151+
# And provide credentials:
152+
AZURE_ACCOUNT_NAME=myaccount
153+
AZURE_ACCOUNT_KEY=mykey
154+
```
155+
156+
#### 3. Generate a Secure Password
157+
158+
```bash
159+
# Generate a strong random password
160+
openssl rand -base64 32
161+
162+
# Copy the output and paste it into backup.env as RESTIC_PASSWORD
163+
```
164+
165+
**Important**: Store this password securely. You'll need it to restore backups. If lost, your backup data becomes inaccessible.
166+
167+
### Testing the Backup
168+
169+
#### List Existing Snapshots
170+
171+
```bash
172+
docker compose run --rm paperless-backup snapshots
173+
```
174+
175+
This will list all backup snapshots. If the repository doesn't exist yet, it will be initialized automatically on the first scheduled backup.
176+
177+
#### Manually Trigger a Backup
178+
179+
Perform a one-time backup:
180+
181+
```bash
182+
docker compose run --rm paperless-backup backup /data
183+
```
184+
185+
Then apply the retention policy to clean up old snapshots:
186+
187+
```bash
188+
docker compose run --rm paperless-backup forget --prune --keep-last 7 --keep-daily 7 --keep-weekly 4 --keep-monthly 3
189+
```
190+
191+
(Note: Replace the `--keep-*` arguments with your configured `RESTIC_FORGET_ARGS` from `backup.env`)
192+
193+
#### Check Repository Status
194+
195+
```bash
196+
docker compose run --rm paperless-backup check
197+
```
198+
199+
#### Monitor Scheduled Backups
200+
201+
Start the Paperless backup service:
202+
203+
```bash
204+
COMPOSE_PROFILES=paperless,paperless-backup docker compose up -d
205+
```
206+
207+
Then monitor backup logs:
208+
209+
```bash
210+
docker compose logs -f paperless-backup
211+
```
212+
213+
The backup will run automatically according to the schedule in `backup.env` (default: 3:30 AM daily).
214+
215+
### Restoration
216+
217+
#### Quick restore overview:
218+
219+
1. Stop the Paperless service
220+
2. Restore the SQLite database from the Restic snapshot
221+
3. Restore the media directory from the Restic snapshot
222+
4. Start Paperless again
223+
224+
To restore a specific snapshot:
225+
226+
```bash
227+
docker compose run --rm paperless-backup restore <snapshot-id> --target /restored
228+
```
229+
230+
Then:
231+
1. Copy the database: `cp /restored/paperless.db /restored/data/paperless.db`
232+
2. Copy the media: `cp -r /restored/media/* paperless-media/`
233+
3. Restart Paperless

paperless/backup.env.example

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Restic backup configuration for Paperless
2+
# Configure the backup repository destination and schedule
3+
4+
# Restic repository URL (required)
5+
# Supports all Restic backends. Uncomment the appropriate example for your setup:
6+
#
7+
# Rclone remote (requires prior: docker compose run --rm -it paperless-backup rclone config):
8+
# RESTIC_REPOSITORY=rclone:myremote:/nas-backups/paperless
9+
#
10+
# S3 (AWS, Wasabi, MinIO, DigitalOcean Spaces, etc.):
11+
# RESTIC_REPOSITORY=s3:s3.amazonaws.com/my-bucket/paperless
12+
# RESTIC_REPOSITORY=s3:https://s3-compatible.example.com/bucket/paperless
13+
#
14+
# Backblaze B2:
15+
# RESTIC_REPOSITORY=b2:my-bucket:path/to/paperless
16+
#
17+
# SFTP:
18+
# RESTIC_REPOSITORY=sftp://user@host/path/to/paperless
19+
#
20+
# Local path:
21+
# RESTIC_REPOSITORY=/mnt/backup/paperless
22+
#
23+
# Azure Blob Storage:
24+
# RESTIC_REPOSITORY=azure://container/paperless
25+
#
26+
# Google Cloud Storage:
27+
# RESTIC_REPOSITORY=gs://bucket-name/paperless
28+
RESTIC_REPOSITORY=
29+
30+
# Restic repository password (required)
31+
# Used to encrypt and decrypt the restic backup repository
32+
# Generate a strong password with: openssl rand -base64 32
33+
RESTIC_PASSWORD=
34+
35+
# Backup schedule (cron format with optional seconds)
36+
# Examples:
37+
# 0 30 3 * * * = 3:30 AM daily
38+
# 0 0 4 * * 0 = 4:00 AM every Sunday
39+
# 0 0 */12 * * * = Every 12 hours
40+
BACKUP_CRON=0 30 3 * * *
41+
42+
# Timezone for cron scheduling
43+
# Used to interpret the CRON schedule
44+
TIMEZONE=America/New_York
45+
46+
# Retention policy (backup rotation)
47+
# Keep the last 7 daily snapshots, 4 weekly, and 3 monthly for long-term storage
48+
RESTIC_FORGET_ARGS=--keep-last 7 --keep-daily 7 --keep-weekly 4 --keep-monthly 3

0 commit comments

Comments
 (0)