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.gitThen I added the original origin so I can pull changes from the original project:
git remote add orig git@github.com:davestephens/ansible-nas.gitSince 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 workhorseNext 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-nasThe 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.cfgand remove the options you donāt need, or tweak them to your liking.
Now I can run the playbook:
ansible-playbook nas.ymlExcept 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: trueto 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: trueNow 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 workhorseMedia
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: trueThe 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!