diff --git a/.env.example b/.env.example
index 3e7da31..dbd15e9 100644
--- a/.env.example
+++ b/.env.example
@@ -1,5 +1,5 @@
COMPOSE_PROFILES=
-COMPOSE_FILE=docker-compose.yml:adguardhome/docker-compose.yml:tandoor/docker-compose.yml
+COMPOSE_FILE=docker-compose.yml:adguardhome/docker-compose.yml:tandoor/docker-compose.yml:joplin/docker-compose.yml
USER_ID=1000
GROUP_ID=1000
TIMEZONE="America/New_York"
diff --git a/README.md b/README.md
index d344ded..baee727 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,7 @@ I am running it in Ubuntu Server 22.04; I also tested this setup on a [Synology
* [DHCP](#dhcp)
* [Expose DNS Server with Tailscale](#expose-dns-server-with-tailscale)
* [Tandoor](#tandoor)
+ * [Joplin](#joplin)
* [Customization](#customization)
* [Optional: Using the VPN for *arr apps](#optional-using-the-vpn-for-arr-apps)
* [Synology Quirks](#synology-quirks)
@@ -72,6 +73,7 @@ I am running it in Ubuntu Server 22.04; I also tested this setup on a [Synology
| [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) | Optional - Proxy server to bypass Cloudflare protection in Prowlarr
Enable with `COMPOSE_PROFILES=flaresolverr` | [flaresolverr/flaresolverr](https://hub.docker.com/r/flaresolverr/flaresolverr) | |
| [AdGuard Home](https://adguard.com/en/adguard-home/overview.html) | Optional - Network-wide software for blocking ads & tracking
Enable with `COMPOSE_PROFILES=adguardhome` | [adguard/adguardhome](https://hub.docker.com/r/adguard/adguardhome) | |
| [Tandoor](https://tandoor.dev) | Optional - Smart recipe management
Enable with `COMPOSE_PROFILES=tandoor` | [vabene1111/recipes](https://hub.docker.com/r/vabene1111/recipes) | /recipes |
+| [Joplin](https://joplinapp.org/) | Optional - Note taking application
Enable with `COMPOSE_PROFILES=joplin` | [joplin/server](https://hub.docker.com/r/joplin/server) | /joplin |
Optional containers are not enabled by default, they need to be enabled,
see [Optional Services](#optional-services) for more information.
@@ -370,6 +372,10 @@ Just make sure that AdGuard Home listens to all interfaces.
See [here](./tandoor/README.md).
+### Joplin
+
+See [here](./joplin/README.md).
+
## Customization
You can override the configuration of a service or add new services by creating a new `docker-compose.override.yml` file,
diff --git a/joplin/.env.example b/joplin/.env.example
new file mode 100644
index 0000000..d65ee4f
--- /dev/null
+++ b/joplin/.env.example
@@ -0,0 +1,8 @@
+MAILER_ENABLED=false
+MAILER_HOST=
+MAILER_PORT=465
+MAILER_SECURITY=MailerSecurity.Tls
+MAILER_AUTH_USER=
+MAILER_AUTH_PASSWORD=
+MAILER_NOREPLY_NAME=
+MAILER_NOREPLY_EMAIL=
\ No newline at end of file
diff --git a/joplin/.gitignore b/joplin/.gitignore
new file mode 100644
index 0000000..ba6d14b
--- /dev/null
+++ b/joplin/.gitignore
@@ -0,0 +1,4 @@
+/database
+/storage
+.env
+backup.env
\ No newline at end of file
diff --git a/joplin/README.md b/joplin/README.md
new file mode 100644
index 0000000..53ae6f6
--- /dev/null
+++ b/joplin/README.md
@@ -0,0 +1,49 @@
+# Joplin
+
+[Joplin](https://joplinapp.org/) is an open source note-taking app. Capture your thoughts and securely access them from any device.
+
+This service lets you host your own Joplin server, which your clients can connect to.
+
+## Installation
+
+Enable Joplin by setting `COMPOSE_PROFILES=joplin`. It will be accessible at `/joplin`.
+
+Copy the example environment file and edit as needed before running Joplin: `cp joplin/env.example joplin/.env`.
+
+## Backup
+
+Joplin's database and media files can be backed up in the cloud storage product of your choice with [Rclone](https://rclone.org/).
+
+Before a backup can be made, `rclone config` must be run to generate the configuration file:
+
+```shell
+docker compose run --rm -it joplin-backup rclone config
+```
+
+It will generate a `rclone.conf` configuration file in ./joplin/rclone/rclone.conf.
+
+Copy the backup environment file to `backup.env` and fill it as needed:
+`cp backup.env.exmple backup.env`
+
+| Variable | Description | Default |
+|------------------------|---------------------------------------------------------------------|---------------------------|
+| `MAILER_ENABLED` | Enable Joplin mailer | `false` |
+| `MAILER_HOST` | Mailer hostname | |
+| `MAILER_PORT` | Mailer port | `465` |
+| `MAILER_SECURITY` | Mailer security protocol | `MailerSecurity.Tls` |
+| `MAILER_AUTH_USER` | Mailer user | |
+| `MAILER_AUTH_PASSWORD` | Mailer password | |
+| `MAILER_NOREPLY_NAME` | No reply email name | |
+| `MAILER_NOREPLY_EMAIL` | No reply email address | |
+| `RCLONE_REMOTE_NAME` | Name of the remote you chose during rclone config | |
+| `RCLONE_REMOTE_DIR` | Name of the rclone remote dir, eg: S3 bucket name, folder name, etc | |
+| `CRON` | How often to run the backup | `@daily` backup every day |
+| `TIMEZONE` | Timezone, used for cron times | `America/New_York` |
+| `ZIP_PASSWORD` | Password to protect the backup archive with | `123456` |
+| `BACKUP_KEEP_DAYS` | How long to keep the backup in the destination | `31` days |
+
+You can test your backup manually with:
+
+```shell
+docker compose run --rm -it joplin-backup backup
+```
diff --git a/joplin/backup.env.example b/joplin/backup.env.example
new file mode 100644
index 0000000..d32fc9d
--- /dev/null
+++ b/joplin/backup.env.example
@@ -0,0 +1,6 @@
+RCLONE_REMOTE_NAME=
+RCLONE_REMOTE_DIR=
+CRON=@daily
+TIMEZONE=America/New_York
+ZIP_PASSWORD=123456
+BACKUP_KEEP_DAYS=31
diff --git a/tandoor/backup/.gitkeep b/joplin/database/.gitkeep
similarity index 100%
rename from tandoor/backup/.gitkeep
rename to joplin/database/.gitkeep
diff --git a/joplin/docker-compose.yml b/joplin/docker-compose.yml
new file mode 100644
index 0000000..68ab008
--- /dev/null
+++ b/joplin/docker-compose.yml
@@ -0,0 +1,55 @@
+services:
+ joplin:
+ image: joplin/server:latest
+ user: root # Not pretty, but non-root breaks volumes: https://github.com/laurent22/joplin/issues/9489
+ container_name: joplin
+ restart: always
+ environment:
+ - APP_PORT=22300
+ - APP_BASE_URL=https://${HOSTNAME}/joplin
+ - HOSTNAME=${HOSTNAME}
+ - DB_CLIENT=sqlite3
+ - SQLITE_DATABASE=/database/joplin.db
+ - STORAGE_DRIVER=Type=Filesystem; Path=/storage
+ volumes:
+ - ./joplin/database:/database
+ - ./joplin/storage:/storage
+ - ./joplin/healthcheck:/healthcheck
+ healthcheck:
+ test: ["CMD", "node", "/healthcheck/healthcheck.js"]
+ interval: 5s
+ retries: 10
+ labels:
+ - traefik.enable=true
+ - traefik.http.routers.joplin.rule=(Host(`${HOSTNAME}`) && PathPrefix(`/joplin`))
+ - traefik.http.routers.joplin.tls=true
+ - traefik.http.routers.joplin.tls.certresolver=myresolver
+ - traefik.http.routers.joplin.middlewares=joplin-stripprefix
+ - traefik.http.middlewares.joplin-stripprefix.stripPrefix.prefixes=/joplin
+ - traefik.http.services.joplin.loadbalancer.server.port=22300
+ - homepage.group=Apps
+ - homepage.name=joplin
+ - homepage.icon=joplin.png
+ - homepage.href=/joplin
+ - homepage.description=Note-taking application
+ - homepage.weight=2
+ profiles:
+ - joplin
+
+ joplin-backup:
+ image: adrienpoupa/rclone-backup:latest
+ container_name: joplin-backup
+ restart: always
+ env_file:
+ - ./joplin/backup.env
+ environment:
+ - BACKUP_FOLDER_NAME=storage
+ - BACKUP_FOLDER_PATH=/storage
+ - DB_TYPE=sqlite
+ - SQLITE_DATABASE=/database/joplin.db
+ volumes:
+ - ./joplin/database:/database
+ - ./joplin/storage:/storage
+ - ./joplin/backup:/config
+ profiles:
+ - joplin
\ No newline at end of file
diff --git a/joplin/healthcheck/healthcheck.js b/joplin/healthcheck/healthcheck.js
new file mode 100644
index 0000000..5194c18
--- /dev/null
+++ b/joplin/healthcheck/healthcheck.js
@@ -0,0 +1,28 @@
+// Inspired by: https://anthonymineo.com/docker-healthcheck-for-your-node-js-app/
+const http = require('http');
+const options = {
+ host: '127.0.0.1',
+ port: 22300,
+ timeout: 2000,
+ path: '/api/ping',
+ headers: {
+ 'Host': process.env.HOSTNAME,
+ }
+};
+
+const healthCheck = http.request(options, (res) => {
+ console.log(`HEALTHCHECK STATUS: ${res.statusCode}`);
+ if (res.statusCode === 200) {
+ process.exit(0);
+ }
+ else {
+ process.exit(1);
+ }
+});
+
+healthCheck.on('error', function (err) {
+ console.error('ERROR:' + err);
+ process.exit(1);
+});
+
+healthCheck.end();
diff --git a/tandoor/README.md b/tandoor/README.md
index 7c325a2..d1dfdc8 100644
--- a/tandoor/README.md
+++ b/tandoor/README.md
@@ -1,6 +1,6 @@
# Tandoor
-Tandoor is a recipe manager that allows you to manage your ever growing collection of digital recipes.
+[Tandoor](https://tandoor.dev/) is a recipe manager that allows you to manage your ever growing collection of digital recipes.
## Installation
diff --git a/tandoor/database/.gitkeep b/tandoor/database/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tandoor/mediafiles/.gitkeep b/tandoor/mediafiles/.gitkeep
deleted file mode 100755
index e69de29..0000000