{"id":19724372,"url":"https://github.com/jungerm2/webservices","last_synced_at":"2026-06-11T12:31:23.157Z","repository":{"id":83530282,"uuid":"468944804","full_name":"jungerm2/webservices","owner":"jungerm2","description":"Self-hosted services setup scripts and helpers/guides","archived":false,"fork":false,"pushed_at":"2024-04-21T18:05:29.000Z","size":73133,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-28T01:13:51.890Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jungerm2.png","metadata":{"files":{"readme":"README-Template.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2022-03-12T01:05:29.000Z","updated_at":"2024-12-30T22:26:46.000Z","dependencies_parsed_at":"2024-04-21T20:11:08.278Z","dependency_job_id":null,"html_url":"https://github.com/jungerm2/webservices","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jungerm2/webservices","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungerm2%2Fwebservices","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungerm2%2Fwebservices/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungerm2%2Fwebservices/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungerm2%2Fwebservices/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jungerm2","download_url":"https://codeload.github.com/jungerm2/webservices/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jungerm2%2Fwebservices/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34199516,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-11T23:25:37.355Z","updated_at":"2026-06-11T12:31:23.151Z","avatar_url":"https://github.com/jungerm2.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"{% macro details(title) -%}\n\n\u003cdetails\u003e\n    \u003csummary\u003e{{ title }}\u003c/summary\u003e\n{{ caller() }}\n\u003c/details\u003e\n\n{%- endmacro -%}\n\n# Home Media Server\n\nThis repo contains tools to setup a home media server remotely via [docker-compose](https://docs.docker.com/compose/) and [fabric](https://www.fabfile.org/). It is meant to be a good starting point, not a comprehensive solution. \n\nThe services currently supported are: \n{%- for service_name in service_names %}\n- [{{service_name | title}}]({{ services[service_name].link }}): {{ services[service_name].description }}\n{%- endfor %}\n\n\nDocker-compose is used to manage containerized services and fabric is used to deploy/update and configure the remote host by running commands through SSH.\n\n\u003e :warning: This project was only tested on a debian/ubuntu distro, but others might work too.\n\n## Requirements\n\nOn local machine you'll need python (\u003e= 3.6) and the following packages: \n\n```\npip install -r requirements.txt\n```\n\nBetter yet, create a venv:\n```shell\nconda create --name webserver python=3.12 --file requirements.txt\nconda activate webserver\n```\n\nThe remote is assumed to be a linux machine which can be accessed via SSH. \n\n## TL;DR\n\n\u003e :warning: Only run these scripts if you trust the numerous sources they use. While most code is ran in docker (so is relatively sandboxed) and comes from well-established, trusted sources (such as [linuxserver](https://www.linuxserver.io/)), some things are installed by piping to bash (notably docker itself). You should always analyse the source for yourself!\n\nTo deploy the default services to your host just run (locally):\n```\nfab misc.deploy -H \u003cuser\u003e@\u003caddr\u003e --prompt-for-login-password --prompt-for-sudo-password\n```\n\nThen you should be able to simply launch the services by running (on the remote host):\n```\ndcp up -d\n```\n\nThe above will pull in the newest images, and run all services in containers. After a few minutes (once everything is initialized), you should be able to see the homer dashboard by visiting `http://\u003cremote-ip\u003e`. Which should look like the following:\n\n\u003cp align=\"center\"\u003e \n  \u003cimg width=\"600\" src=\"screenshots/dashboard.png\"\u003e\n\u003c/p\u003e\n\nThere are a few other tasks that help you configure services (all `config-*` tasks below), but most services will require some further configuration through their webUI. \n\nSome useful monitoring tools can also be installed via the tasks `install-lzd`.\n\nAnd of course, *everything* is customizable!\n\n## Project Structure\n\n### Running Tasks\n\nThe main setup script lives inside [`fabfile.py`](fabfile.py). You can view all available tasks like so:\n\n```\n\u003e fab --list\n{{ fabric.tasks }}\n```\n\nTo run an above task on your remote machine you can run:\n\n```\nfab \u003ctask\u003e [task-args] -H \u003cuser\u003e@\u003caddr\u003e --prompt-for-login-password --prompt-for-sudo-password\n```\n\nLocal commands, such as `render-readme`, need not the `-H` option or any other host related options.\n\nYou can also setup a `fabric.yml` config file to hold host information such as user, address and password. See [here](https://docs.fabfile.org/en/latest/concepts/configuration.html) for more information on fabric's config options.\n\n### Service Configuration\n\nThe main configuration file is `services.yml`. Inside you'll find a list of services and associated data. If a service enabled, then it will be included in the docker-compose file. This file is templated via [jinja](https://palletsprojects.com/p/jinja/).\n\n*Note:* A service that is marked as `true` is enabled (i.e: `service: true` is equivalent to `service: enabled: true`).\n\n\u003cdetails\u003e\n    \u003csummary\u003eContents of \u003ccode\u003eservices.yml\u003c/code\u003e\u003c/summary\u003e\n\n```yaml\n{{ services_raw }}\n```\n\n\u003c/details\u003e\n\n### Secret Management\n\nTo not have passwords written in plain text in any config files we use [keyring](https://keyring.readthedocs.io/en/latest/). \n\nOn the command line you need to run:\n```\n\u003e keyring set system username\n```\n\nTo set any passwords/secrets you might need. You can then retreive them by using the following syntax in a template: {% raw %}`{{ secrets_get(\"system\", \"username\") }}`{% endraw %}.\n\n### Docker-compose file\n\nAll services run through docker compose. The compose file itself it jinja-templated and uses YAML anchors to reduce config duplication.\n\nIndividual services can be enabled/disabled in `services.yml`.\n\n### Profile (bash aliases)\n\nThe `.profile` file contains a few useful bash aliases. Feel free to modify.\n\n### Working Directories\n\nBy default, all services are configured to be in `/srv/\u003cservice name\u003e`, and the media is located at `/vault/media/`. These defaults can be edited in `defaults.py`. \n\n## Mounting an external disk\n\nSee [here](https://pimylifeup.com/raspberry-pi-mount-usb-drive/) for a more in-depth tutorial. The TL;DR is below:\n```\n# Find disk, get info, make mount dir\nlsblk\nsudo blkid /dev/sda1\nsudo apt install ntfs-3g\nsudo mkdir -p /mnt/mybook\n```\n\nThen, if in debian (raspi-os), in `/etc/fstab` add the following line:\n```\nUUID=[UUID] /mnt/mybook [TYPE] defaults,auto,users,rw,nofail,noatime 0 0\n```\n\nIn ubuntu, you'll want to add the following instead:\n```\nUUID=\u003cuuid\u003e /mnt/mybook ntfs uid=\u003cuserid\u003e,gid=\u003cgroupid\u003e,umask=0022,sync,auto,rw 0 0\n```\n\n## Default docker-compose settings per service\n\nHere we show the snippet of the docker compose file that is responsible for each service. \n\n{%- for service_name in service_names %}\n{% call details('Compose for %s' % (service_name | title)) %}\n```yaml\n{{ services[service_name].compose }}\n```\n{% endcall %}\n{%- endfor %}\n  \n\n## Troubleshooting \u0026 FAQ\n\n{% call details(\"\u003ci\u003ePiHole not working on Ubuntu/Fedora.\u003c/i\u003e\") %}\nSee [here](https://github.com/pi-hole/docker-pi-hole#installing-on-ubuntu-or-fedora).\n{% endcall %}\n\n{% call details(\"\u003ci\u003eConnected to wgeasy but no internet.\u003c/i\u003e\") %}\nMake sure to open the correct port on your network. By default, you need to port-forward port 51820. \n{% endcall %}\n\n{% call details(\"\u003ci\u003eRaspberry pi can be pinged but does not respond to ssh/http requests.\u003c/i\u003e\") %}\nThis is likely due to the PI running out of RAM (i.e: it can't allocate pages for new processes). This can be \"fixed\" by resizing the swap partition. Try rebooting and running the `resize-swap` task with a larger size (maybe 2048 MB).\n{% endcall %}\n\n{% call details(\"\u003ci\u003eIf not needed wifi/bluetooth can be disabled on the PI to save power. This might be required if you have a limited power supply.\u003c/i\u003e\") %}\nIn `/boot/config.txt` add the following two lines and reboot:\n```\ndtoverlay=disable-wifi\ndtoverlay=disable-bt\n```\n{% endcall %}\n\n{% call details(\"\u003ci\u003eHow to add a new service?\u003c/i\u003e\") %}\nYou'll need to create an entry in `services.yml` with all the associated fields and add an entry in the docker file and optionally in homer's config. Make sure to wrap these in a jinja if enabled conditional to be able to easily enable/disable the service. \n{% endcall %}\n\n{% call details(\"\u003ci\u003eI can't see a service's memory consumption!\u003c/i\u003e\") %}\nIf `lazy-docker` or `docker stats --no-stream` doesn't show memory consumption, you'll probably need to enable the cgroup memory manager by adding `cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1` to your `/boot/cmdline.txt` file. See [here](https://github.com/docker/for-linux/issues/1112) for more info.\n{% endcall %}\n\n{% call details(\"\u003ci\u003eIf running on a laptop: Closing the lid/screen shutsdown the server.\u003c/i\u003e\") %}\nThis will depend on which distro you use. For ubuntu, [see here](https://askubuntu.com/questions/141866/keep-ubuntu-server-running-on-a-laptop-with-the-lid-closed).\n{% endcall %}\n\n{% call details(\"\u003ci\u003eGraphics card not found!\u003c/i\u003e\") %}\nThis is likely a driver issue. Check if the card is accessible with `sudo lshw -c video`. If it's there, you [can try this](https://linuxconfig.org/how-to-install-the-nvidia-drivers-on-ubuntu-19-04-disco-dingo-linux).\n{% endcall %}\n\n{% call details(\"\u003ci\u003eMy headless install now has a GUI\u003c/i\u003e\") %}\nInstalling GPU drivers on ubuntu can cause this. See [here](https://askubuntu.com/questions/1250026) for a fix. \n{% endcall %}\n\n## Changelog\n\nMost recent on top:\n\n- Add duckdns, and mealie services.\n\n- Add wgeasy vpn service.\n\n- Add Home assistant service (and mosquitto broker) as well as link to octoprint in homer.\n\n- Tweak compose file to allow `pihole` to receive traffic. Add battery/power monitoring tasks. \n\n- Removed fabfile.helpers in favor of importing tasks via their namespace (i.e: `from fabfile import x` and doing `x.y` instead of `from fabfile.x import y`).\n\n- Fix precommit hooks, split fabfile.misc into misc and status. Make `Ombi` use host networking to help it find all Arrs. Refactor install tasks.\n\n- Refactor all fabric code into a package, tasks are spread across multiple files for easy maintenance. Add a few tasks such as speedtest (and required dockerfile).\n\n- Add backup tasks for all services. Rename `code-server` volume.\n\n- Fix (G)UID for transmission. Add container name field for `gluetun`, `watchtower`, and cronjob for updating containers with `watchtower`. Switch WebUI to flood for transmission (*much* better). \n\n- Add transmission configuration task and associated files. Now all *arrs can see the directory transmission downloads to as it's in `/media/downloads`.\n\n- Change volumes for *arr stack to enable hardlinks. Removed all references to individual media folders, i.e:`{% raw %}{{ MEDIA_REMOTE_ROOT }}/tv:/tv{% endraw %}` for tv, movies, music, and downloads and replaced them with one volume:`{% raw %}{{ MEDIA_REMOTE_ROOT }}:/media{% endraw %}`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjungerm2%2Fwebservices","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjungerm2%2Fwebservices","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjungerm2%2Fwebservices/lists"}