- Overview
- Prerequisites
- Set up directories
- Set up services
- Monitoring
- Remote Access
- Helpful commands
- Troubleshooting
- Additional notes
This server configuration provides the ability to download media using BitTorrent (via with VPN support) and/or Usenet. All media is automatically organized and served on the network by Plex Media Server.
All services in this guide are run in Docker containers managed via Docker Compose.
The remainder of this guide assumes the host server is running a Debian-based operating system. My current setup is listed below:
Platform | Optiplex 5060 Micro |
Operating System | Ubuntu Server 22.04 |
Processor | Intel Core i5-8500T 2.1GHz |
RAM | 16GB DDR4 RAM |
Internal Storage | 256GB M.2 NVMe SSD |
External Storage | 2TB USB 2.0 HDD |
Network | 1Gbps Ethernet port |
Install using the convenience script:
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh ./get-docker.sh
Run the Linux post-installation
steps to add your user to the docker
group:
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
Note: Not required for Ubuntu Server when openssh-server was installed at setup time
To allow remote access via SSH, install and configure openssh
on the host:
# Install openssh
sudo apt install openssh-server
# Enable service
sudo systemctl enable ssh --now
# Start service
sudo systemctl start ssh
Test the SSH connection by logging in from another computer on the network:
ssh <host-username>@<host-ip>
Optionally, you can install avahi
to enable connections using the server's
hostname:
sudo apt install avahi-daemon
# Now you can connect to <server-name>.local
ssh <host-username>@<server-hostname>.local
Optional
Note: Not required for Ubuntu Server since no desktop environment is installed
To allow remote desktop access to the server from another computer, install and
configure xrdp
on the host.
sudo apt update && sudo apt install xrdp
sudo systemctl enable xrdp
sudo ufw allow 3389/tcp
Install the Microsoft Remote Desktop application on any client computers you with to connect from.
- Mac: Microsoft Remote Desktop
- Windows: Microsoft Remote Desktop
Note: The instructions below are designed for local storage on the host
filesystem. To store media on a network share or USB drive, see the Additional
notes section. It is still recommended to store the
/data/config
directory on the host filesystem.
Run the setup.sh
script on the host to create the pre-determined directory
structure with the correct permissions. These folders will be used as volume
mounts for the Docker containers, and be referenced in each service's settings.
git clone git@github.com:nbn22385/htpc-docker.git
cd htpc-docker
./setup.sh
Expand to see the resulting folder structure
/config
├── bazarr
├── duckdns
├── grafana
├── nginx
├── overseerr
├── plex
├── prowlarr
├── qbittorrent
├── radarr
├── sabnzbd
├── sonarr
├── tautulli
└── wireguard
/data
├── media
│ ├── movies
│ └── tv
├── torrents
│ ├── movies
│ └── tv
└── usenet
├── movies
└── tv
Services are managed via Docker using docker-compose
.
Note: The base paths for service configuration and data are set within the
.env
file. Review the .env
file and set CONFIG_ROOT
and DATA_ROOT
to
your preferred paths.
Create the following files in a secrets/
directory with the following values for the
required services:
- Create a
secrets/
directory if it does not exist. This folder will be ignored by git.
mkdir -p secrets
- DuckDNS
Create a secret for your DuckDNS token. For more info see the DuckDNS section of this document.
printf "DUCKDNS-TOKEN" > ./secrets/duckdns_token.txt
- Plex
Create a secret for the following Plex values.
-
PLEX-USERNAME
: your Plex username. -
PLEX-TOKEN
: see these instructions for finding your Plex token. -
PLEX-ADDRESS
: The URL of your Plex server. For example,http://<SERVER-IP>:32400
printf "PLEX-USERNAME" > ./secrets/plex_user.txt printf "PLEX-TOKEN" > ./secrets/plex_token.txt printf "PLEX-ADDRESS" > ./secrets/plex_address.txt
- Real-Debrid
Create a secret for your Real-Debrid API key, which can be found here.
printf "REAL-DEBRID-API-KEY" > ./secrets/rd_api_key.txt
Optional (enabled by default)
Note: To disable use of a VPN for qBittorrent connections (not
recommended), remove the network_mode
line from the qbittorrent
service in
docker-compose.yml
. Configuration updates will need to be made to Prowlarr,
Radarr, and Sonarr download client settings, by pointing the server to
qbittorrent
, rather than wireguard
.
In order to use the Wireguard docker image, a Wireguard configuration file must
exist on the host as /config/wireguard/wg0.cfg
. In many cases, the
configuration file can be generated by following the instructions specific to
your VPN provider.
Update the [Interface]
section of your config file to allow incoming traffic
from the host (update the HOMENET
IP as needed for your network)
(Source):
[Interface]
# I had to modify this line to reach the web interface
DNS: 8.8.8.8
# Exclude the docker subnet from being routed via Wireguard
PostUp = DROUTE=$(ip route | grep default | awk '{print $3}'); HOMENET=192.168.0.0/16; HOMENET2=10.0.0.0/8; HOMENET3=172.16.0.0/12; ip route add $HOMENET3 via $DROUTE;ip route add $HOMENET2 via $DROUTE; ip route add $HOMENET via $DROUTE;iptables -I OUTPUT -d $HOMENET -j ACCEPT;iptables -A OUTPUT -d $HOMENET2 -j ACCEPT; iptables -A OUTPUT -d $HOMENET3 -j ACCEPT; iptables -A OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = HOMENET=192.168.0.0/16; HOMENET2=10.0.0.0/8; HOMENET3=172.16.0.0/12; ip route delete $HOMENET; ip route delete $HOMENET2; ip route delete $HOMENET3; iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT; iptables -D OUTPUT -d $HOMENET -j ACCEPT; iptables -D OUTPUT -d $HOMENET2 -j ACCEPT; iptables -D OUTPUT -d $HOMENET3 -j ACCEPT
For PIA VPN users, a config file is not provided and must be generated. Use the
instructions in this repository
to generate a configuration file. Once generated, ensure the output file is
named wg0.conf
, then copy it to the directory noted above.
cd /path/to/htpc-docker
docker compose up -d
Once all services are running, you can access each service's web UI using the following URLs:
Service | Role | URL |
---|---|---|
Plex | Media server | http://<server-ip> :32400/web |
qBitTorrent | Torrent client | http://<server-ip> :8080 |
SABnzbd | Usenet client | http://<server-ip> :8081 |
Radarr | Movie manager | http://<server-ip> :7878 |
Sonarr | TV show manager | http://<server-ip> :8989 |
Prowlarr | Indexer manager | http://<server-ip> :9696 |
Bazarr | Subtitle manager | http://<server-ip> :6767 |
Overseerr | Request manager | http://<server-ip> :5055 |
Tautulli | Notification manager | http://<server-ip> :8181 |
Settings must be manually configured for each service to properly use the directory structure we set up, as well as adjust other behaviors and integrations. I have listed the most important settings below, but adjust anything else as needed.
These custom settings are adapted from TRaSH Guide for Plex.
Plex settings
Settings
General
- 🔳 Send crash reports to Plex
- 🔳 Enable Plex Media Server debug logging
Remote Access
(Optional)- ☑️ Remote access (Note: may need to forward router port 32400 to the host)
- ☑️ Manually specify public port: 32400
Library
- ☑️ Scan my library automatically
- ☑️ Run a partial scan when changes are detected
- ☑️ Run scanner tasks at a lower priority
Manage
Libraries
Movies
Manage Recommendations
- Disable any recommendations you don't want to the client screen
Edit Library > Add Folders
- Ensure
/media/movies
is listed
- Ensure
TV
Manage Recommendations
- Disable any recommendations you don't want to the client screen
Edit Library > Add Folders
- Ensure
/media/tv
is listed
- Ensure
These custom settings are adapted from TRaSH Guide for qBittorrent.
qBittorrent settings
Settings
Downloads
- ☑️ Delete .torrent files afterwards
- ☑️ Pre-allocate disk space for all files
- Default torrent management mode: Automatic
- Default save path:
/data/torrents
- ☑️ (Optional) Email notification upon download completion
- From: "qBittorrent" (or any text)
- To: Destination email address (I used the T-Mobile email-to-sms gateway 10-digit-number@tmomail.net). Check your carrier.
- SMTP server: smtp.gmail.com
- ☑️ This server requires a secure connection (SSL)
Authentication
- Username: YOUR-EMAIL@gmail.com
- Password: generate a Google app password
Connection
- Peer connection protocol: TCP
Speed
Global Rate Limits
- Set limits here if desired
WebUI
- ☑️ Bypass authentication for clients on localhost
- ☑️ Bypass authentication for clients in whitelisted IP subnets
- Example: 192.168.1.0/24
- ☑️ (Optional) Use alternative WebUI
- VueTorrent already exists
in the container. To use it, set this path to
/vuetorrent
.
- VueTorrent already exists
in the container. To use it, set this path to
Tags & Categories
- Add category
movies
with save path/data/torrents/movies
- Add category
tv
with save path/data/torrents/tv
- Add category
Advanced
- Network Interface: wg0 (this is the Wireguard interface)
Click the 💾 icon to apply the changes. Then (optionally) apply the custom VueTorrent settings:
Settings
VueTorrent
- Copy/paste the following code and click the
Import Settings
button{"sort_options":{"isCustomSortEnabled":false,"sort":"completion_on","reverse":false,"filter":null,"category":null,"tag":null,"tracker":null},"webuiSettings":{"lang":"en","darkTheme":true,"showFreeSpace":true,"showSpeedGraph":true,"showSessionStat":true,"showAlltimeStat":true,"showCurrentSpeed":true,"showTrackerFilter":false,"showSpeedInTitle":false,"deleteWithFiles":true,"title":"Global Speed","rightDrawer":false,"topPagination":false,"paginationSize":15,"dateFormat":"DD/MM/YYYY, HH:mm:ss","openSideBarOnStart":false,"showShutdownButton":false,"useBitSpeed":false,"useBinaryUnits":false,"refreshInterval":2000,"contentInterval":5000,"torrentPieceCountRenderThreshold":5000,"busyDesktopTorrentProperties":[{"name":"Status","active":true},{"name":"Category","active":true},{"name":"Size","active":true},{"name":"Progress","active":true},{"name":"DownloadSpeed","active":true},{"name":"Downloaded","active":true},{"name":"SavePath","active":false},{"name":"UploadSpeed","active":true},{"name":"Uploaded","active":false},{"name":"ETA","active":true},{"name":"Peers","active":true},{"name":"Seeds","active":true},{"name":"Ratio","active":false},{"name":"Tracker","active":true},{"name":"Tags","active":false},{"name":"AddedOn","active":false},{"name":"Availability","active":false},{"name":"LastActivity","active":false},{"name":"CompletedOn","active":false},{"name":"AmountLeft","active":false},{"name":"ContentPath","active":false},{"name":"DownloadedSession","active":false},{"name":"DownloadLimit","active":false},{"name":"DownloadPath","active":false},{"name":"Hash","active":false},{"name":"InfoHashV1","active":false},{"name":"InfoHashV2","active":false},{"name":"SeenComplete","active":false},{"name":"TimeActive","active":false},{"name":"TotalSize","active":false},{"name":"TrackersCount","active":false},{"name":"UploadedSession","active":false},{"name":"UploadLimit","active":false},{"name":"GlobalSpeed","active":false},{"name":"GlobalVolume","active":false}],"doneDesktopTorrentProperties":[{"name":"Status","active":true},{"name":"Category","active":false},{"name":"Size","active":true},{"name":"Progress","active":false},{"name":"DownloadSpeed","active":false},{"name":"Downloaded","active":false},{"name":"SavePath","active":false},{"name":"UploadSpeed","active":true},{"name":"Uploaded","active":true},{"name":"ETA","active":false},{"name":"Peers","active":true},{"name":"Seeds","active":true},{"name":"Ratio","active":true},{"name":"Tracker","active":true},{"name":"Tags","active":false},{"name":"AddedOn","active":false},{"name":"Availability","active":false},{"name":"LastActivity","active":false},{"name":"CompletedOn","active":false},{"name":"AmountLeft","active":false},{"name":"ContentPath","active":false},{"name":"DownloadedSession","active":false},{"name":"DownloadLimit","active":false},{"name":"DownloadPath","active":false},{"name":"Hash","active":false},{"name":"InfoHashV1","active":false},{"name":"InfoHashV2","active":false},{"name":"SeenComplete","active":false},{"name":"TimeActive","active":true},{"name":"TotalSize","active":false},{"name":"TrackersCount","active":false},{"name":"UploadedSession","active":false},{"name":"UploadLimit","active":false},{"name":"GlobalSpeed","active":false},{"name":"GlobalVolume","active":false}],"busyMobileCardProperties":[{"name":"Status","active":true},{"name":"Tracker","active":false},{"name":"Category","active":true},{"name":"Tags","active":false},{"name":"Size","active":true},{"name":"Progress","active":true},{"name":"ProgressBar","active":true},{"name":"Ratio","active":false},{"name":"Uploaded","active":false},{"name":"ETA","active":true},{"name":"Seeds","active":true},{"name":"Peers","active":true},{"name":"DownloadSpeed","active":true},{"name":"UploadSpeed","active":true}],"doneMobileCardProperties":[{"name":"Status","active":true},{"name":"Tracker","active":false},{"name":"Category","active":true},{"name":"Tags","active":false},{"name":"Size","active":true},{"name":"Progress","active":true},{"name":"ProgressBar","active":true},{"name":"Ratio","active":false},{"name":"Uploaded","active":false},{"name":"ETA","active":true},{"name":"Seeds","active":true},{"name":"Peers","active":true},{"name":"DownloadSpeed","active":true},{"name":"UploadSpeed","active":true}]},"authenticated":true}
- Copy/paste the following code and click the
These custom settings are adapted from TRaSH Guide for SABnzbd.
SABnzbd settings
Config
Folders
- Temporary Download Folder: /data/usenet/incomplete
- Completed Download Folder: /data/usenet
- Click
Save Changes
Servers
- Click
+ Add Server
- Enter the Host, Username, and Password for your Usenet provider
- Test and add the server
- Click
Categories
- Note: these paths are relative to the Completed Download Folder set above
- For the
movies
category, set the Folder/Path tomovies
, clickSave
- For the
tv
category, set the Folder/Path totv
, clickSave
Special
Values
host_whitelist()
: Add an entry for the hostnamesabnzbd
- Note: This is necessary to allow access from Radarr/Sonarr
These custom settings are adapted from TRaSH Guide for Radarr.
Radarr settings
Settings
Media Management
- ☑️ Rename Movies
- ☑️ Replace Illegal Characters
Root Folders
- Add an entry for
/data/media/movies
- Add an entry for
Profiles
Quality Profiles
- I set up separate profiles for 1080p and 720p
Delay Profiles
- I set up a delay profile "Prefer torrent" with a Usenet delay of 2 minutes. An opposite configuration can be set up for torrents. Currently I have Overseerr using this tag
Release Profiles
- I set up an entry with keywords to avoid (i.e. "HDR")
Indexers
- The indexers will auto-populate once Prowlarr is set up
- Click
Show Advanced
RSS Sync Interval
: 0 (prevents hitting indexer API limits)
Download Clients
- Click
+
and selectqBittorrent
- Host: wireguard
- Username/Password: Use qbittorrent credentials
- Category: movies
- Click
+
and selectSABnzbd
- Host: sabnzbd
- Port: 8080 (even though the web interface is 8081)
- Api Key: SABnzbd API key from its
Config > General (Security)
page - Category: movies
- 🔳 Remove Completed (I like to preserve SABnzbd history)
- Click
Import Lists
(Optional, allows initiating downloads via the Plex Discover interface)- Click
+
and selectPlex Watchlist
- ☑️ Enable
- ☑️ Enable Automatic Add
- Monitor: select
None
to manually manage files in Radarr, otherwise leave default value - ☑️ Search on Add: enable to have Radarr automatically search for movie, otherwise leave default value
- Quality Profile: select desired profile
- Authenticate with Plex.tv: click button to authenticate
- Note: Clicking
Test
will produce a warning if your Plex watchlist contains no movies
- Note: Clicking
- Click
Save
- Click
These custom settings are adapted from TRaSH Guide for Sonarr.
Sonarr settings
Settings
Media Management
- ☑️ Rename Episodes
- ☑️ Replace Illegal Characters
Root Folders
- Add an entry for
/data/media/tv
- Add an entry for
Indexers
- The indexers will auto-populate once Prowlarr is set up
- Click
Show Advanced
RSS Sync Interval
: 0 (prevents hitting indexer API limits)
Download Clients
- Click
+
and selectqBittorrent
- Host: wireguard
- Username/Password: Use qbittorrent credentials
- Category: tv
- Click
+
and selectSABnzbd
- Host: sabnzbd
- Port: 8080 (even though the web interface is 8081)
- Api Key: SABnzbd API key from its
Config > General (Security)
page - Category: tv
- 🔳 Remove Completed (I like to preserve SABnzbd history)
- Click
Import Lists
(Optional, allows initiating downloads via the Plex Discover interface)- Click
+
and selectPlex Watchlist
- ☑️ Enable Automatic Add
- Monitor: select
None
to manually manage files in Sonarr, otherwise leave default value - Quality Profile: select desired profile
- Authenticate with Plex.tv: click button to authenticate
- Note: Clicking
Test
will produce a warning if your Plex watchlist contains no shows
- Note: Clicking
- Click
Save
- Click
These custom settings are adapted from Servarr Guide for Prowlarr.
Prowlarr settings
Settings
- Click
Show Advanced
(enables changing API limits below) Apps
Applications
- Click
+
and selectRadarr
- Prowlarr server: http://prowlarr:9696
- Radarr server: http://radarr:7878
- ApiKey: Radarr API key from its
Settings > General
page
- Click
+
and selectSonarr
- Prowlarr server: http://prowlarr:9696
- Sonarr server: http://sonarr:8989
- ApiKey: Sonarr API key from its
Settings > General
page
- Click
Sync Profiles
- Click
+
(this will be used later in the Indexers configuration)- Name: No RSS
- 🔳 Enable RSS
- ☑️ Enable Interactive Search
- ☑️ Enable Automatic Search
- Click
Download Clients
(Optional)- Note: If you intend to do searches directly within Prowlarr, you need to add Download Clients. Otherwise, you do not need to add them here. For searches from your Apps, the download clients configured there are used instead.
- Click
+
and selectqBittorrent
- Host: wireguard
- Username/Password: Use qbittorrent credentials
- Click
+
and selectSABnzbd
- Host: sabnzbd
- Port: 8080 (even though the web interface is 8081)
- Api Key: SABnzbd API key from its
Config > General (Security)
page - Default Category: you can add a
prowlarr
category in SABnzbd or use an existing category
General
Security
- Authentication Required: Disabled for Local Addresses
- Click
Indexers
Add Indexer
- Search for an indexer and click to configure it
- ☑️ Enable
- Torrent indexers: 1337x, LimeTorrents, TorrentDownload, YTS
- Usenet indexers (require accounts): abNZB, altHUB, DrunkenSlug
- Sync Profile: No RSS (prevents hitting indexer API limits)
- API Key: Get the API key from your indexer's settings page
- Query/Grab Limit: See this page for indexer query and grab limits
These custom settings are adapted from TRaSH Guide for qBittorrent.
Bazarr settings
Settings
Languages
Subtitles Language > Languages Filter
- Add
English
to the list
- Add
Language Profiles
- Add a new profile and choose the
English (Normal or hearing impaired)
language - You can also add
English (Forced)
- Add a new profile and choose the
Default Settings
- ☑️ Series
- Profile: English profile name
- ☑️ Movies
- Profile: English profile name
- ☑️ Series
Providers
- Add: OpenSubtitles.com, Embedded Subtitles, subf2m.co
- Note: Create an account on OpenSubtitles.com and input your login information
Sonarr
- Address: sonarr
- API Key: Sonarr API key from its
Settings > General
page
Radarr
- Address: radarr
- API Key: Radarr API key from its
Settings > General
page
Scheduler
- Sonarr/Radarr Sync: 24 Hours (all boxes)
- Disk Indexing: Manually (all boxes)
- Search and Upgrade Subtitles: 24 Hours (all boxes)
Overseerr settings
Settings
Users > User Settings
- ☑️ Enable New Plex Sign-In
- Global Movie Request Limit: set if desired
- Global Series Request Limit: set if desired
Plex
Plex Settings
- Server: Choose local Plex server (if not done during initial setup)
- Hostname/IP: Enter server IP (if not done during initial setup)
Plex Libraries
- Enable Movies and TV Shows (if not done during initial setup)
Tautulli Settings
(optional)- Hostname/IP: Enter server IP (if not done during initial setup)
- API Key: Tautulli API key from its
Settings > Web Interface
page
Services
Radarr
- ☑️ Default Server
- Hostname/IP: radarr
- API Key: Radarr API key from its
Settings > General
page - Set
Quality Profile
andRoot Folder
as desired
Sonarr
- ☑️ Default Server
- Hostname/IP: sonarr
- API Key: Sonarr API key from its
Settings > General
page - Set
Quality Profile
andRoot Folder
as desired
Notifications
- Configure desired notification agent. I used email to SMS.
Tautulli settings
Settings
Homepage > Watch Statistics
- I unchecked a bunch of these to clean up the homepage
Plex Media Server
- Plex IP Address: Choose local Plex server (192.168.x.y)
- ☑️ Use secure connection
Notification Agents
- I am using Webhook notification agents along with
ntfy.sh. An example notification is shown below.
Add a new notification agent
>Webhook
- Webhook URL:
https://ntfy.sh
- Webhook Method:
POST
- Triggers: ☑️
Playback Start
(or any other triggers you want) - Data:
Playback Start
>JSON Data
{ "topic": "nateflix-info", "icon": "{poster_url}", "title": "{server_name}", "message": "{user} started playing {title}{`str(' (S' + season_num00 + ':E' + episode_num00 + ')' if media_type != 'movie' else '')`}\nDevice: {player}\nContainer: {container_decision!c} ({container!u}{`str(' → ' + stream_container if container_decision == 'transcode' else '' )`!u})\nVideo: {`str('Direct stream' if user_direct_streams > 0 else 'Direct play' if user_direct_plays > 0 else video_decision)`!c} ({video_codec!u}{`str(' → ' + stream_video_codec if video_decision == 'transcode' else '')`!u} {stream_video_full_resolution})\nAudio: {`str('Direct stream' if user_direct_streams > 0 else 'Direct play' if user_direct_plays > 0 else audio_decision)`!c} ({audio_codec!u}{`str(' → ' + stream_audio_codec if audio_decision == 'transcode' else '' )`!u} {stream_audio_channel_layout})\nBitrate: {`round(float(stream_bandwidth) / 1000, 1)`> Mbps}" }
- Note:
notify_text_eval = 1
must be manually enabled in the Tautulliconfig.ini
file to enable expressions.
- I am using Webhook notification agents along with
ntfy.sh. An example notification is shown below.
- Changing the newsletter header
- Edit
${CONFIG_HOME}/tautulli/templates/recently_added.html
- Search for
newsletter-header.png
- Replace the line with your own image:
<img src="YOUR-IMAGE-URL-OR-PATH">
- Edit
A monitoring stack is included using Prometheus/Grafana with data collected via
cAdvisor and node-exporter. The monitoring services are deployed by including
the monitoring/docker-compose.yml
from the main docker-compose.yml
file.
The Grafana dashboard is accessible at http://<server-ip>:3000
.
Remote access to the server from the internet can be configured using dynamic DNS and a reverse proxy.
Service | Description |
---|---|
DuckDNS | Static IP management |
Nginx Proxy Manager | Forwards traffic to your services running at home, including free SSL |
The DuckDNS service automatically keeps your DuckDNS account in sync with your server's public IP address.
- Create a free DuckDNS account
- Create a unique subdomain that will be used as an alias to your server's public IP address
- Copy the Token from the DuckDNS account homepage
- Write the token to a file that will be handled by Docker Secrets:
printf "YOUR-TOKEN" > secrets/duckdns_token.txt
The Ngnix Proxy Manager service allows you to manage subdomains for external access to your services, as well as manage access lists to the subdomains.
The Nginx Proxy Manager dashboard is accessible at http://<server-ip>:81
- On the
Access Lists
screen, clickAdd Access List
- In the "Detail" tab, set a name and enable
Pass Auth to Host
- In the "Authorization" tab, set at least one username/password that will be used to access Proxy Hosts
- In the "Access" tab, set
allow
toall
- Click
Save
- You can create multiple access lists, for example, one for admin only, and one that includes other users
DuckDNS will route any wildcard "sub-sub-domain" (i.e.
service1.my-alias.duckdns.org
) to your server, so Nginx Proxy Manager can then
handle routing sub-sub-domain requests to your individual services within your
network. If this seems confusing, this diagram may help:
flowchart LR
classDef redbox fill:#ff0063
C(Client) -->|Request\nservice1.my-alias.duckdns.org| D(DuckDNS)
D -->|Request| N[Nginx Proxy\n Manager]
subgraph Home Server
N --> S1[Service1]:::redbox
N --> S2[Service2]
N --> S3[Service3]
end
- On the
Proxy Hosts
screen, clickAdd Proxy Host
- In the
Domain Names
box, create a subdomain for your service using the DuckDNS alias for your server. Example:radarr.my-alias.duckdns.org
. - Set the IP of your server and exposed port of your service
- Enable
Block Common Exploits
- Set the Access List to the one created above, or else your service will publicly available (relies only on the service login, if any, for security)
- In the "SSL" tab, select "Request a new SSL Certificate".
- Enable "Force SSL" and create a new certificate
In order to reach the server from the internet, configure your router to forward ports 80 (HTTP) and 443 (HTTPS) to the server/ports where Nginx Proxy Manager service is listening. See the Nginx Proxy Manager documentation for more details.
You can now test if external access is working by visiting one of your subdomains from outside the local network.
# Start services in the background (all by default, can specify individual service(s))
docker compose up [service-names] -d
# Stop services (all by default, can specify individual service(s))
docker compose down [service-names]
docker compose logs <service-name>
docker-compose up --renew-anon-volumes|-V
docker compose down
docker compose pull
docker compose up -d
docker image prune
I was able to restore access by running this command after starting services:
sudo iptables -t mangle -F
- Mounting an external USB disk on host and Docker containers
- Enable USB hard drive idle mode
- Mounting a network share on host and Docker containers
- Disable laptop suspend when lid is closed
- Restart host on a schedule
- Disable Wi-Fi radio
- Useful packages
- SSH without password
In this example, I have an NTFS-formatted external USB hard drive connected to my host PC.
- On the host PC, create a directory for the mount point.
sudo mkdir /mnt/usb
- Get the UUID of the USB drive. Look for an entry that matches your drive.
sudo blkid
# example output
# ...
# /dev/sdb1: LABEL="MY_DRIVE" BLOCK_SIZE="512" UUID="ABCD1234" TYPE="ntfs" PARTUUID="00075ff3-01"
# ...
- Edit the fstab file to automount the USB drive on boot. Use the UUID, mount point, and filesystem type found in the previous steps.
sudo vim /etc/fstab
# for NTFS
UUID=ABCD1234 /mnt/usb ntfs defaults,noatime,nofail,umask=000 0 2
# for ext4
UUID=ABCD1234 /mnt/usb2 ext4 defaults,noatime,nofail 0 2
- Mount the drive and ensure it is available at the mount point.
sudo mount -a
ls /mnt/usb
- Set up download paths on the drive to be used by the services.
# set permissions if necessary
sudo chown -Rv ${USER}:${USER} /mnt/usb
# create destination directories on the drive
DATA_DIR=/mnt/usb
sudo mkdir -pv ${DATA_DIR}/{torrents,usenet,media}/{tv,movies}
sudo chmod -Rv 775 ${DATA_DIR}/
sudo chown -Rv ${USER}:${USER} ${DATA_DIR}/
If you are switching an internal drive to external storage for all media,
you can stop here. If you want to mount the external drive as additional mount
in the container (i.e. /usb
, continue with the steps below to update service
settings.
Settings > Downloads > Default Save Path
:/usb/torrents
Categories > movies > Save Path
:/usb/torrents/movies
Categories > tv > Save Path
:/usb/torrents/tv
Note: if using VueTorrent UI, you might have to switch back to the default UI to update the category paths
Config > Folders > Temporary Download Folder
:/usb/usenet/incomplete
Config > Folders > Completed Download Folder
:/usb/usenet
- Click
Save Changes
Settings > Manage > Libraries > Movies > Edit Library > Add Folders
:/usb/media/movies
Settings > Manage > Libraries > TV Shows > Edit Library > Add Folders
:/usb/media/tv
Note: you can remove any existing paths that are no longer needed
Home > Movies ... > Scan Library Files
to confirm changes took effectHome > TV Shows ... > Scan Library Files
to confirm changes took effect
Settings > Media Management > Root Folders
: Add/usb/media/movies
Settings > Lists > PlexImport > Root Folder
:/usb/media/movies
Movies > Edit Movies > Select All > Edit
: Change Root Folder to/usb/media/movies
, Apply, Allow moving files
Note: you can remove any existing paths that are no longer needed
Settings > Media Management > Root Folders
: Add/usb/media/tv
Settings > Import Lists > PlexImport > Root Folder
:/usb/media/tv
Series > Mass Editor > Select All
: Change Root Folder to/usb/media/tv
, Allow moving files
Note: you can remove any existing paths that are no longer needed
Some USB hard drives do not spin down after a period of time. This section describes how to enable the functionality manually.
- Download and install the
hd-idle
utility.
curl -L https://github.com/adelolmo/hd-idle/releases/download/v1.20/hd-idle_1.20_amd64.deb -o hd-idle.deb
sudo dpkg -i hd-idle.deb
- Configure
hd-idle
to set the idle timeout for your USB drive (in seconds). The UUID is found viasudo blkid
.
sudo vim /etc/default/hd-idle
# Uncomment and update this line to enable the utility
START_HD_IDLE=true
# Uncomment and update this line to configure the idle timeout value
HD_IDLE_OPTS="-i 0 -a /dev/disk/by-uuid/<DRIVE-UUID> -i 600 -c ata -l /var/log/hd-idle.log"
- Start the
hd-idle
service.
systemctl unmask hd-idle.service
systemctl start hd-idle
systemctl enable hd-idle
- Read the logs
sudo vim /var/log/hd-idle.log
Note: This will result in non-optimal copying/moving due to hardlinks not functioning across filesystems/shares. For this reason, I am using a USB hard drive directly connected to the host PC rather than this method, but leaving these steps here for reference.
This example assumes a USB hard drive is connected to the router's USB port, and is shared as an SMB share on the network.
- On the host, install
cifs
and create the directory to be used as the mount point
sudo apt install cifs-utils -y
sudo mkdir /mnt/smb-share # directory that will act as the mount point for the SMB share
- Edit the fstab file to automount the network share on boot (and after network is up)
sudo vim /etc/fstab
# <SHARE-IP>/<DIRECTORY> <MOUNT-POINT> <TYPE> <OPTIONS> <BACKUP> <FSCK>
//192.168.29.1/usb-drive /mnt/smb-share cifs _netdevuid=nate,vers=1.0 0 0
- In Plex, add the shared directory(s) to your library. In this example, I
mapped the shared directory to
/smb-share
in the container.
plex:
volumes:
- /mnt/smb-share:/smb-share
When using a laptop as a server, the system may suspend when the lid is closed. To prevent this, make the following modification and restart the computer.
sudo vim /etc/systemd/logind.conf
Uncomment and edit the following lines:
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
I set the host PC to restart every Sunday at 4 AM with a Cron job
sudo crontab -e
# add the following line, save, and quit the editor
0 4 * * SUN /sbin/reboot
# verify the rule was saved
sudo crontab -l
Find the wlan adapter name, then disable the radio:
sudo lshw -C network
# example output:
# logical name: <wireless adapter name>
sudo apt install net-tools
sudo ifconfig <wireless adapter name> down
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep -Po '"tag_name": "v\K[^"]*')
curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz"
tar xf lazygit.tar.gz lazygit
sudo install lazygit /usr/local/bin
sudo apt install -y
avahi-daemon
unzip
ripgrip
fd-find
net-tools
tree
curl -L https://bit.ly/glances | /bin/bash
Configure SSH keys to connect to the server without a password.
Create a key pair on the client machine. Press <Enter>
at all prompts:
ssh-keygen
You now have a public and private key that you can use to authenticate. The next step is to place the public key on your server so that you can use SSH-key-based authentication to log in:
ssh-copy-id username@remote_host
Type yes
and enter your password when prompted.
This can be useful for making clones/backups or moving to a new drive.
# --archive, -a archive mode is -rlptgoD (no -A,-X,-U,-N,-H)
# --human-readable, -h output numbers in a human-readable format
# --verbose, -v increase verbosity
# --one-file-system, -x don't cross filesystem boundaries
# --acls, -A preserve ACLs (implies --perms)
# --hard-links, -H preserve hard links
# --whole-file, -W copy files whole (w/o delta-xfer algorithm)
# --xattrs, -X preserve extended attributes
rsync -ahvxAHWX --progress [--dry-run] /mnt/usb/ /mnt/usb2/