In previous articles I described my hardware and software setup for a DIY home server. In this article I will go over apps that I host on my server using ansible-nas.
I must make a quick remark here, - my apps are only available on my local network for now.
Maintaining a home server is a journey of constant tinkering whenever free time is available, and I have a HUGE problem with free time.
I will definitely either update this post or write a new article on the matter of exposing apps to the internet once I get my hands on it.
Setting up ansible-nas
First of all I forked the project (https://github.com/nemoden/ansible-nas) and cloned it to my local machine:
git clone git@github.com:Nemoden/ansible-nas.git
Then I added the original origin so I can pull changes from the original project:
git remote add orig git@github.com:davestephens/ansible-nas.git
Since I want main
to be clean of my local and be in sync with orig
, I created a new branch that would manage my workhorse:
git checkout -b workhorse
Next up I created my own inventory file and group vars overrides file for my inventory. cat inventories/workhorse/inventory
:
[all]ansible-nas ansible_host=192.168.100.200
[nas]ansible-nas
The overrides file is located under inventories/workhorse/group_vars/nas.yml
, and a few things I’ve added there from the get go were the things specific to my setup:
ansible_nas_hostname: workhorseansible_nas_timezone: Etc/UTC
# spinning rust rootrust_root: "/rust"
# docker persistent datadocker_root: "{{ rust_root }}/docker"
# find the relevant name and environment variables for your DNS provider at https://go-acme.github.io/lego/dns/traefik_dns_provider: netlifytraefik_environment_variables: NETLIFY_TOKEN: "nfp_r3dact3dN3t1ifyT0k3n"
# Will be added to the docker group to give user command line access to dockeransible_nas_user: nemoden
# Your email and domain, used for Let's Encrypt SSL certsansible_nas_email: myemail@example.com
# Applications will have subdomain SSL certificates created if Traefik is enabled, e.g. ansible-nas.<your-domain>, nextcloud.<your-domain>ansible_nas_domain: home.nas
# What version of python ansible should use on target system (path to spesific binary)ansible_python_interpreter: /usr/bin/python3
# db files (mysql, postgres, etc)db_root: "{{ rust_root }}/db/data"db_logs: "{{ rust_root }}/db/logs"
media_root: "{{ rust_root }}/media"encrypted_root: "{{ rust_root }}/encrypted"downloads_root: "{{ rust_root }}/downloads"documents_root: "{{ rust_root }}/documents"
# etc...
Traefik and Netly token has been covered in the previous blog post - Choosing Home Server OS and setting up ansible-nas
Next thing is to configure the ansible.cfg
:
[defaults]
inventory = inventories/workhorse/inventory
retry_files_enabled = False
remote_user = nemoden
host_key_checking = False
listhosts = all
# fact caching
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/facts_cache
# two hours timeout
fact_caching_timeout = 7200
nocows=1
[privilege_escalation]
become_method = sudo
become_user = root
become = True
All the options seem to be fairly self-explanatory. You can read more about them in the ansible documentation. In addition, you can generate ansible.cfg
file with all the options using
ansible-config init --disabled > ansible.cfg
and remove the options you don’t need, or tweak them to your liking.
Now I can run the playbook:
ansible-playbook nas.yml
Except for it will do nothing for now, because none of the apps are enabled 😄. So let’s enable some apps, shall we?
Enabling apps
ansible-nas ships with quite a library of apps of all sorts all managed by the communite that emerged around the project. Configuring and enabling the apps is as easy as adding a few lines to the group_vars/nas.yml
file.
In my case, since I want my docker home to be /rust/docker
, I typically add one more like like <app_name>_data_dir="{{ docker_root }}/<app_name>"
, so enabling something like wallabag would look like this:
wallabag_enabled: truewallabag_available_externally: truewallabag_data_directory: "{{ docker_root }}/wallabag"wallabag_hostname: "save" # I want to access wallabag at https://save.home.nas/ instead of https://wallabag.home.nas/
wallabag_available_externally: true
in my case means only on local netowrk. I think the variable name isn’t the best, but it is what it is. All it does is enables apps to be accessed via traefik which configures a nice domain name for the app.
By default wallabag will not download images. If the article will get deleted from the original source, you will lose the images.
I prefer to have everything locally. If you are with me, go to My Account
-> Internal settings
-> Misc
and change “Download images locally” to 1 and hit save. Thank me later now! xD
Custom apps
There are some apps which are not in the ansible-nas library, and some of those are really specific to my setup. I simply add a role for them using ansible-galaxy role init <app_name>
and add the necessary stuff (and get rid of the rest) in the tasks/main.yml
file while maintaing the same structure as the other apps in the library.
My first app that I’ve added that is specific to my setup was wireguard
which, in my case, a VPN client. And some of the apps use the wireguard network rather than the host network. A simple example of this is when I’d like to route a youtube downloader via a VPN that points to a different country.
I’ll definitely write a whole blog post about how to route apps running inside docker containers via a VPN-client container, but for now I’ll just leave it at that.
Some of the apps that I’ve added are:
- immich - I just slightly tweaked the unmerged immich PR
- mysql
- postgres
- valkey
- Already mentioned wireguard
Basically what I achieve with all the databases is being able to develop apps on my laptop while the databases are running on the home server so I don’t need to run docker on my MacOS laptop, which is a huge resource hog (because docker runs on a VM inside MacOS and hypervisor just chewing up all the CPU and RAM even on the top of the shelf MacBooks).
With the custom stuff discussed, let’s see what I used from the box.
Apps I’m running
First thing, I want to route via traefik
, which is as easy as adding
traefik_enabled: true
to the group_vars/nas.yml
file.
Monitoring
Monitoring apps were the first apps I enabled. Specifically, glances
and grafana
. Relevant entries from the group vars file:
glances_available_externally: trueglances_enabled: truestats_enabled: truestats_grafana_available_externally: truestats_internet_speed_test_enabled: truestats_prometheus_available_externally: true
Now I can access glances
at https://glances.home.nas/
and grafana
at https://grafana.home.nas/
and get a nice overview of the server’s health.
Development
My private git
server? Yes, please! I’m using gitea
for that:
gitea_available_externally: truegitea_enabled: truegitea_hostname: "git"
Now I can create ansible-nas
repo on my fresh install of gitea and push my own changes after adding new remote:
git remote add horse https://git.home.nas/nemoden/ansible-nas.gitgit push horse workhorse
Media
Jellyfin
Jellyfin seemed like a good choice for a media server. It’s good enough and it’s FOSS enough for me to look into any other solution. Again, very straightforward to setup with ansible-nas:
jellyfin_available_externally: truejellyfin_enabled: true
The only gripe I have is not being able to cast (I’m using Google Chromecast) to my TV from the Jellyfin iOS app. Casting from the browser on my laptop works fine, but I pretty much never use jellyfin on my laptop. The Chromecast Jellyfin app works fine though, it’s a little less convenient than casting, but I can live with this.
Immich
My entire home server has been built for the primary reason of unlocking myself (and my wife) from using iCloud. Or at least only relying on iCloud for syncing things like calendars and notes. I want my private photos in my private chamber. And this is what immich is for.
Immich has multi-user support, BUT I’m running 2 instances of immich - one for me and one for my wife. It just separates our collections completely, and thus can be managed separately.
I took this unmerged PR as the base and tweaked it a little.
Syncing phone images onto a home server IS NOT A BACKUP. If your server catches fire, short circuits, or gets stolen, you lose all your photos.
For properly backing up your valuable stuff you can not risk to lose use the 3-2-1 strategy.
I must admit that as per the time of writing, I have not implmeneted it myself, so I’m still relying on iCloud, but I’m working on it, and in the next article I’ll share my experience setting up proper backups and testing them.
Immich has a fairly good iOS app:
Be mindful that immich is still in BETA and under very active development. So as per the moment of writing (11th of Nov, 2024) it’s still not stable.
Paperless-ngx
Now let’s talk about documents. Receipts for taxation office, marriage and birth certificates, paid utility bills, driver licensed, etc. I want to keep all of that in one place, and I want it to be private. Paperless-ngx does a fantastic job in this department.
It has a very capable OCR (Optical Character Recognition), and it’s very easy to use. Each document has a few attributes like title, archive serial number (I don’t really know what it is tbh xD), created date, correspondent, document type, and tags. Corresponded, doucment type, and tags allow for easy filtering and searching. If I want to find only my documents, I can filter by correspondent. Would I require to fetch all electricity bills, I can filter by document type. You can come up with your own taxonomy.
There are quite a few moving parts to paperless-ngx, but ansible-nas makes installing it a breeze:
paperless_ng_available_externally: truepaperless_ng_enabled: truepaperless_ng_hostname: "paperless"
I’d love to provide a screenshot, but I don’t like pixelating half of the screen, sorry :) I’m sure quick google search will provide you with a few screenshots and some youtube videos…
Oh, youtube videos! Let’s talk about that next.
YouTube downloader
I’m using youtubedl-material, a self-hosted youtube downloader that uses youtube-dl under the hood. Basically it can download videos from a lot of websites, not just youtube (yes, and those sites too). The list is massive and can be found here
Should I continue providing snippets from the group_vars/nas.yml
file? I think you get the idea by now. Maybe last one time:
youtubedlmaterial_available_externally: trueyoutubedlmaterial_enabled: trueyoutubedlmaterial_hostname: "ydl"
I have a huge problem with youtubedl-material though.
It can not download youtube playlists
So, I’m looking to replace it with tubearchivist which isn’t supported by ansible-nas yet. Hopefully I’ll get to it soon, I promise I’ll create PR to add it back to ansible-nas project.
News, Reading, and Recipes
Miniflux
I’m using miniflux as a minimalistic RSS reader and pretty happy with it.
If you like to follow any subreddits, you can add them to miniflux as well. Just add https://www.reddit.com/r/<subreddit>.rss
to the feed list.
For example, the RSS feed for the r/selfhosted
subreddit is https://www.reddit.com/r/selfhosted.rss
.
Wallabag
Just like youtube videos, I want to preserve some articles for reading later. Wallabag is what ansible-nas provides out of the box. I wouldn’t say I’m totally happy with it, in most cases it does the job very well, in some cases it messes up formatting/css/layout of the page. But it’s good enough for me to keep using it for now.
The usage is simple - just feed in the URL and Wabbabag will save the article for you to read later.
Books and PDFs
I’m not a fan of reading anything from the screen, and I’d rather have a physical book in my hands. If I don’t have physical book, or I’m traveling, I have my trusty Kindle Paperwhite. In super rare cases I have some PDFs that I primarily use as reference material on my laptop and in even more rare cases, on my phone. For this I’m using calibre-web. I’m infitefy unhappy with it and can’t recommend it to anyone to be completely honest. But this is what I use sometimes.
Recipes
If I wasn’t a software engineer I’d probably be a cook. Maybe even a chef :) Over many years I perfected pasta carbonara to the point I wouldn’t be embarassed to host a dinner for any Italian :) And my egg fried rice is so good I wouldn’t be ashamed to serve it to Uncle Roger.
Unlike my gigantic reading list, my recipe list is quite short, but I want to keep it in one place. Mealie is what I’m using for that.
Just like wallabag, you copy the recipe URL and Mealie will fetch the recipe for you. And unlike wallabag it works every single time because recipe websites (at least popular ones) are using special markup for recipes. Mealie doesn’t need to parse HTML, it reads only the structured data. And of course it skips all the preambles like “I remember when I was a little my mother used to make this dish for me and I loved it so much that I decided to share it with you today” followed by several pages of ads and popups.
The only downside is it doesn’t download the images to each preparation stage even if they are available in the original recipe. Those can be added manually. I presume this is because these images are not part of the structured data. Having only bare bones recipe free of images but also free of fat and detrimental additives like ads and “my mother used to make it for me when I was a little” nonesense is a fair trade off for me.
It also has some other nice features like meal planning, shopping list, etc. I don’t use those, but I can see how they can be useful for others.
Wind-up
Hosting your own apps is fun, and it’s a great way to learn new things. Once you set your foot on this path you want more of it. Just like this I have a few more apps in my pipeline that I want to host on my home server. The downside of self-hosted apps, and thus not managed is maintenance cost. I’m looking to (at least partly) mitigate it by setting up watchtower to automatically update the docker containers. But, of course, gotta lookout for breaking changes in the apps themselves.
That’s it for now. In the next article I’ll cover backups and testing them. Happy self-hosting if you do!