{"id":24441777,"url":"https://github.com/erwinkramer/synology-nas-bootstrapper","last_synced_at":"2025-07-24T08:10:41.841Z","repository":{"id":270597510,"uuid":"910847615","full_name":"erwinkramer/synology-nas-bootstrapper","owner":"erwinkramer","description":"Bootstrap your Synology NAS setup with automatic provisioning for everything related to the filesystem, DSM and Container Manager.","archived":false,"fork":false,"pushed_at":"2025-04-12T15:23:27.000Z","size":115,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-12T20:13:20.396Z","etag":null,"topics":["architecture","caddy","container","container-manager","docker","docker-compose","dsm","duckdns","jellyfin","nas","synology"],"latest_commit_sha":null,"homepage":"https://www.guanchen.nl","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/erwinkramer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-01T16:07:19.000Z","updated_at":"2025-04-12T15:23:30.000Z","dependencies_parsed_at":"2025-01-20T19:31:06.245Z","dependency_job_id":"0b60f738-288c-4b24-838a-adec12c07f10","html_url":"https://github.com/erwinkramer/synology-nas-bootstrapper","commit_stats":null,"previous_names":["erwinkramer/synology-nas-bootstrapper"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erwinkramer%2Fsynology-nas-bootstrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erwinkramer%2Fsynology-nas-bootstrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erwinkramer%2Fsynology-nas-bootstrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/erwinkramer%2Fsynology-nas-bootstrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/erwinkramer","download_url":"https://codeload.github.com/erwinkramer/synology-nas-bootstrapper/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248625517,"owners_count":21135514,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["architecture","caddy","container","container-manager","docker","docker-compose","dsm","duckdns","jellyfin","nas","synology"],"created_at":"2025-01-20T21:20:10.072Z","updated_at":"2025-07-24T08:10:41.834Z","avatar_url":"https://github.com/erwinkramer.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Synology NAS Bootstrapper ✴\r\n\r\n[![CC BY-NC-SA 4.0][cc-by-nc-sa-shield]][cc-by-nc-sa]\r\n![GitHub commit activity](https://img.shields.io/github/commit-activity/m/erwinkramer/synology-nas-bootstrapper)\r\n\r\nBootstrap your Synology NAS setup with automatic provisioning for: filesystem structure, shares, users, groups, permissions, network, container orchestration and `.env` variables. Just configure the scheduled tasks and the Docker Compose `.env` file with your own dns and folder variables, that's it.\r\n\r\nMakes use of the Synology CLI [(pdf)](https://global.download.synology.com/download/Document/Software/DeveloperGuide/Firmware/DSM/All/enu/Synology_DiskStation_Administration_CLI_Guide.pdf), Synology Task Scheduler and [Synology Container Manager](https://www.synology.com/nl-nl/dsm/feature/container-manager).\r\n\r\n## Network Design\r\n\r\nFollowing is the partial network design. Refer to the code for full details.\r\n\r\n```mermaid\r\nflowchart TD\r\n\r\nsubgraph access[DNS Access layer]\r\nprivateservices[http://\r\ncode/whoami/qbittorrent/jellyfin/dozzle/based\r\n.yourinternal.domain.wow\r\n]\r\nexternalservices[https://\r\nwhoami/based\r\n.yourexternal.domain.wow\r\n]\r\nend\r\n\r\nsubgraph router L3\r\n6432[port 6432]\r\n80[port 80]\r\n443[port 443]\r\nend\r\n\r\nsubgraph cr7[frontend Caddy L7]\r\nextendspe[docker extends service/private]\r\nextendspub[docker extends service/public]\r\n\r\nextendscr7[docker extends service/base]\r\nend\r\n\r\nsubgraph cr4[frontend Caddy L4]\r\nextendscr4[docker extends service/base]\r\nend\r\n\r\nsubgraph cm[backend containers]\r\npostgres\r\nint[watchtower/cloudflare-ddns]\r\next[whoami]\r\nprv[whoami/dozzle/jellyfin/qbittorrent/code]\r\nend\r\n\r\nprivateservices -- A record '*.yourinternal' to local NAS ip  --\u003e 80 --\u003e extendspe\r\n\r\n6432 --\u003e extendscr4\r\nexternalservices -- A record '*.yourexternal' to public ip (DDNS) --\u003e 443 -- port forwarding to local NAS ip --\u003e extendspub\r\nextendscr7 --\u003e int\r\nextendscr4 --\u003e postgres\r\n\r\nextendspub --\u003e ext\r\nextendspe -- private_ip_range check --\u003eprv\r\n```\r\n\r\n## Prerequisites\r\n\r\nA Synology NAS, including:\r\n\r\n1. [Container Manager](https://www.synology.com/en-global/releaseNote/ContainerManager) `24.0.2-1525` or higher. Only this version supports Docker Compose `include` statements, introduced in Docker compose [2.20.3](https://docs.docker.com/compose/releases/release-notes/#2203), which this project uses.\r\n\r\n1. A compatible [DSM version](https://www.synology.com/nl-nl/releaseNote/DSM), confirmed to work on `7.2.2-72806` (Update 2 and 3).\r\n\r\n## Synology configuration\r\n\r\nPlace the entire project (repo) structure inside of your NAS with path `/volume1/docker/projects` (replace `volume1` with your own volume). You end up with `/volume1/docker/projects/garden`.\r\n\r\nChange the filename of [.env.example](garden/.env.example) to `.env` and use your own values.\r\n\r\nRemove the `.example` postfix of the files in the [secrets folder](garden/secrets) and use your own values.\r\n\r\n### Tasks\r\n\r\nThe [tasks folder](./garden/tasks/) provides boot scripts. Configure [garden/tasks/main.sh](/garden/tasks/main.sh) as specified the comment of that script. All scripts called by `main.sh` are idempotent and designed for repeated use without damaging an existing setup.\r\n\r\n1. [filesystem.sh](./garden/tasks/filesystem.sh) creates the filesystem structure, shares, users, groups and permissions (inspired by [DrFrankenstein](https://drfrankenstein.co.uk/step-2-setting-up-a-restricted-docker-user-and-obtaining-ids/)), also modifies `.env` file variables.\r\n\r\n1. [configuredocker.sh](./garden/tasks/configuredocker.sh) fixes the iptables for docker (introduced by [Pedro Lamas](https://gist.github.com/pedrolamas)) and sets the group permissions for docker socket.\r\n\r\n1. [freeports.sh](./garden/tasks/freeports.sh) frees port 443 and 80 for own use.\r\n\r\n### Containers\r\n\r\nThe [docker-compose.yaml file](./garden/docker-compose.yaml) configures all containers. Create a project called `garden` in Container Manager based on this file, and fill in the variables in the `.env` file. It does the following:\r\n\r\n1. Provisions `watchtower`, `cloudflare-ddns-private` and `cloudflare-ddns-public` as internal services without inbound traffic.\r\n\r\n1. Configures `caddy` as reverse proxy for all inbound traffic.\r\n\r\n1. Provisions `postgres` as a service via port 6432.\r\n\r\n1. Provisions `qBittorrent` as a service via port 50777.\r\n\r\n1. Provisions `coreDNS` as a service via port 53 (udp and tcp).\r\n\r\n1. Provisions the following http/https services:\r\n\r\n| public | Uri | Authentication |\r\n| --- | --- | -- |\r\nyes | https://auth.domain.wow | tinyauth itself |\r\nyes | https://whoami.yourexternal.domain.wow | tinyauth |\r\nyes | https://based.yourexternal.domain.wow | [DSM](https://kb.synology.com/en-af/DSM/help/DSM/AdminCenter/system_login_portal_dsm) |\r\nno  | http://based.yourinternal.domain.wow | [DSM](https://kb.synology.com/en-af/DSM/help/DSM/AdminCenter/system_login_portal_dsm) |\r\nno  | http://jellyfin.yourinternal.domain.wow | jellyfin |\r\nno  | http://code.yourinternal.domain.wow | tinyauth |\r\nno  | http://whoami.yourinternal.domain.wow | tinyauth |\r\nno  | http://qbittorrent.yourinternal.domain.wow | tinyauth |\r\nno  | http://dozzle.yourinternal.domain.wow | tinyauth |\r\nno  | http://radarr.yourinternal.domain.wow | tinyauth |\r\nno  | http://bazarr.yourinternal.domain.wow | tinyauth |\r\nno  | http://prowlarr.yourinternal.domain.wow | tinyauth |\r\n\r\nIf not public, it's;\r\n - blocking any traffic that doesn't originate `private_ip_range`;\r\n - only resolvable locally.\r\n\r\n## Application configuration\r\n\r\n### Jellyfin\r\n\r\nTranscoding settings in jellyfin admin dashboard, under \u003chttp://jellyfin.yourinternal.domain.wow/web/#/dashboard/playback/transcoding\u003e. Specific for each CPU, assumes you're using a [Gemini Lake Refresh](https://en.wikipedia.org/wiki/Goldmont_Plus#Desktop_processors_(Gemini_Lake_Refresh)) model. Check for `init_hw_device` in logs to confirm it's working.\r\n\r\nHardware acceleration: `Intel QuickSync`\r\n\r\nEnable hardware decoding for:\r\n\r\n- H264\r\n- HEVC\r\n- MPEG2\r\n- VC1\r\n- VP8\r\n- VP9\r\n- HEVC 10 bit\r\n- VP9 10 bit\r\n- Prefer OS native DXVA or VA-API hardware decoders\r\n\r\nHardware encoding options:\r\n\r\n- Enable hardware encoding\r\n- Allow encoding in HEVC format\r\n- Enable VPP Tone mapping\r\n- Enable Tone mapping\r\n\r\n### qBittorrent\r\n\r\n1. Default username: `admin`, password is printed in container log first time. Go to `Options` - `WebUI` - `Authentication` - check `Bypass authentication for clients in the whitelisted IP subnets` and add `0.0.0.0/0` as value since we use tinyauth instead.\r\n\r\n1. Change the listening port to `50777` for incoming connections.\r\n\r\n### Radarr\r\n\r\n1. Go to `Settings` - `Connections` and configure `Jellyfin` with: \r\n   - `Host` - `jellyfin`\r\n   - `Port` - `8096`\r\n\r\n1. Go to `Settings` - `General` and set `Authentication Required` to `Disabled for Local Addresses` since we use tinyauth instead.\r\n\r\n### Prowlarr\r\n\r\n1. Go to `Settings` - `Apps` and configure `Radarr` with: \r\n   - `Prowlarr Server` -  `http://prowlarr:9696`\r\n   - `Radarr Server` - `http://radarr:7878`\r\n\r\n1. Go to `Settings` - `General` and set `Authentication Required` to `Disabled for Local Addresses` since we use tinyauth instead.\r\n\r\n### Bazarr\r\n\r\n1. Go to `Settings` - `Radarr` and configure `Radarr` with:\r\n   - Enabled - `true`\r\n   - Host Address - `radarr`\r\n   - API Key - add from `Radarr` - `Settings` - `General` - `API Key`\r\n1. Go to `Settings` - `Languages` and configure via [bazarr languages guide](https://wiki.bazarr.media/Getting-Started/Setup-Guide/#languages).\r\n1. Go to `settings` - `Providers` and configure via [bazarr providers guide](https://wiki.bazarr.media/Getting-Started/Setup-Guide/#providers) for `OpenSubtitles.com`, `Supersubtitles` and `Gestdown (Addic7ed proxy)`.\r\n1. Set the language profile for existing media, via [bazarr - First Time Installation Configuration](https://wiki.bazarr.media/Getting-Started/First-time-installation-configuration/).\r\n\r\n### Postgres\r\n\r\n1. Make sure to create an `init.sql` file containing `ALTER ROLE admin SUPERUSER;`, or similar, and place it into `${host_data_config_path}/postgres/scripts`, this folder is mounted in `/docker-entrypoint-initdb.d/` so postgres picks this up.\r\n\r\n## License\r\n\r\nThis work is licensed under a\r\n[Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa].\r\n\r\n[![CC BY-NC-SA 4.0][cc-by-nc-sa-image]][cc-by-nc-sa]\r\n\r\n[cc-by-nc-sa]: http://creativecommons.org/licenses/by-nc-sa/4.0/\r\n[cc-by-nc-sa-image]: https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png\r\n[cc-by-nc-sa-shield]: https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferwinkramer%2Fsynology-nas-bootstrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ferwinkramer%2Fsynology-nas-bootstrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ferwinkramer%2Fsynology-nas-bootstrapper/lists"}