From dddb37e97970ba02217a0c05e18988154e3fde8c Mon Sep 17 00:00:00 2001 From: Elara Musayelyan Date: Fri, 9 Sep 2022 16:37:09 -0700 Subject: [PATCH] Initial Commit --- LICENSE | 21 ++++ README.md | 17 +++ authelia/README.md | 11 ++ authelia/authelia.nomad | 54 +++++++++ gitea/README.md | 7 ++ gitea/gitea.nomad | 74 ++++++++++++ go-import-redirector/README.md | 7 ++ .../go-import-redirector.nomad | 46 ++++++++ homer/README.md | 5 + homer/config.yml | 84 ++++++++++++++ homer/homer.nomad | 46 ++++++++ lms/README.md | 7 ++ lms/lms.nomad | 59 ++++++++++ minio/README.md | 5 + minio/minio.nomad | 75 ++++++++++++ nextcloud-onlyoffice/README.md | 15 +++ .../nextcloud-onlyoffice.nomad | 106 +++++++++++++++++ searxng/README.md | 7 ++ searxng/searxng.nomad | 50 ++++++++ traefik/README.md | 21 ++++ traefik/traefik.nomad | 109 ++++++++++++++++++ 21 files changed, 826 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 authelia/README.md create mode 100644 authelia/authelia.nomad create mode 100644 gitea/README.md create mode 100644 gitea/gitea.nomad create mode 100644 go-import-redirector/README.md create mode 100644 go-import-redirector/go-import-redirector.nomad create mode 100644 homer/README.md create mode 100644 homer/config.yml create mode 100644 homer/homer.nomad create mode 100644 lms/README.md create mode 100644 lms/lms.nomad create mode 100644 minio/README.md create mode 100644 minio/minio.nomad create mode 100644 nextcloud-onlyoffice/README.md create mode 100644 nextcloud-onlyoffice/nextcloud-onlyoffice.nomad create mode 100644 searxng/README.md create mode 100644 searxng/searxng.nomad create mode 100644 traefik/README.md create mode 100644 traefik/traefik.nomad diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..123a8b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Arsen Musayelyan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0b41b31 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Nomad + +This repository contains my [Nomad](https://github.com/hashicorp/nomad) and [Consul](https://github.com/hashicorp/consul) configurations that I am using for my servers. + +Nomad is an orchestrator. It orchestrates a cluster of multiple computers to perform a certain task. Consul is a service discovery solution as well as a key/value store. Nomad seamlessly integrates with Consul to provide a cohesive solution that works really well. + +I have a cluster of 8 [Raspberry Pi 4s](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) (4x 1GB, 4x 2GB RAM), 2 2GB [Pine H64s](https://www.pine64.org/pine-h64-ver-b/), 1 2GB [RockPro64](https://www.pine64.org/rockpro64/), and a 2012 Mac Mini with an i7 that I've upgraded with a 1TB SSD and 16GB of RAM. I've also pre-ordered a 16GB [Radxa Rock 5 Model B](https://wiki.radxa.com/Rock5/5b). + +I'd originally planned to use Kubernetes on this cluster, but due to the low power and especially low RAM of many of my nodes, Kubernetes would either take up nearly all the resources or freeze the nodes entirely, forcing a hard reboot. Recently, I found Nomad, which is far more lightweight, while providing more features. In my opinion, the only downside is the fact that Kubernetes has a much bigger community. + +Using Nomad is great, and much better than my previous strategy of "stick everything somewhere and hope you remember where". All I do is create one of these nomad files, using the very good documentation for Nomad, and then submit it to Nomad. Nomad then automatically decides where to put the service, installs it, configures it, runs it, and publishes it to Consul, from where Traefik picks it up and reconfigures itself automatically to point to the newly-created service. If the service is stateless, like a few of mine are, then Nomad can seamlessly migrate the service to another node, and Traefik will reconfigure itself automatically to point to the new node. + +The way I have my cluster set up is: My mac mini acts as the only Nomad and Consul server in the cluster because it has the most resources. Each node in the cluster has a Nomad client running on it, as well as a Consul client. They are simply services installed by the package manager and run by systemd. + +A couple of my services are running outside of Nomad because they have a complex config, or because they're Home Assistant, which has a supervisor docker container that launches other docker containers, etc. and I don't know how to express that in a nomad job file. For these, I use a simple systemd service that runs `consul register` with the service's information. This causes Traefik to pick them up and automatically reconfigure itself the same as it does for Nomad servces. + +Before using any files in this repo, read through them and make sure to replace anything that is mentioned on the individual READMEs, as well as things like domain names. My domain is `arsenm.dev`, so change anything that has that to your domain instead, \ No newline at end of file diff --git a/authelia/README.md b/authelia/README.md new file mode 100644 index 0000000..eee9f44 --- /dev/null +++ b/authelia/README.md @@ -0,0 +1,11 @@ +# Authelia + +This job file runs [Authelia](https://www.authelia.com/), which allows users to protect services that prpvide no authentication mechanism with a password and 2fa. It can also be used to log in to other self-hosted services, similar to how "Log in to Google" buttons work. + +IMPORTANT NOTE: Some services in this repo are protected by Authelia. You can find out which by doing Ctrl+F in their nomad files and searching for "authelia". If you are not running Authelia, those services will be available WITHOUT A PASSWORD, so do not expose them to the internet without Authelia protecting them. + +This job requires one volume for Authelia's config and secrets. This volume should be named `authelia-config`, and be read/write, not readonly. + +There is one thing you will want to change in this file. In the `env` stanza, the timezone, or `TZ`, is set to "CHANGE ME". Set this to your timezone as it is used when generating TOTP codes for 2fa. + +Since configuration for Authelia is complex and heavily dependent on your environment and what you want it to do, I will leave my authelia config out and instead direct you to the documentation: https://www.authelia.com/configuration/prologue/introduction/, and this blog post that I used when configuring authelia: https://spad.uk/configure-authelia-to-work-with-traefik/. \ No newline at end of file diff --git a/authelia/authelia.nomad b/authelia/authelia.nomad new file mode 100644 index 0000000..82a7b1d --- /dev/null +++ b/authelia/authelia.nomad @@ -0,0 +1,54 @@ +job "authelia" { + region = "global" + datacenters = ["dc1"] + type = "service" + + group "authelia" { + count = 1 + + volume "authelia-config" { + type = "host" + source = "authelia-config" + read_only = false + } + + network { + port "authelia" { + to = 9091 + static = 9091 + } + } + + task "authelia" { + driver = "docker" + + volume_mount { + volume = "authelia-config" + destination = "/config" + read_only = false + } + + env { + TZ = "CHANGE ME" + AUTHELIA_JWT_SECRET_FILE = "/config/secrets/jwt" + AUTHELIA_SESSION_SECRET_FILE = "/config/secrets/session" + } + + config { + image = "authelia/authelia:latest" + ports = ["authelia"] + } + + service { + name = "authelia" + port = "authelia" + + tags = [ + "traefik.enable=true", + "traefik.http.routers.authelia.rule=Host(`auth.arsenm.dev`)", + "traefik.http.routers.authelia.tls.certResolver=letsencrypt", + ] + } + } + } +} diff --git a/gitea/README.md b/gitea/README.md new file mode 100644 index 0000000..f2a0660 --- /dev/null +++ b/gitea/README.md @@ -0,0 +1,7 @@ +# Gitea + +This is the nomad file for [Gitea](https://github.com/go-gitea/gitea), a git web interface. + +This job requires one volume for Gitea's data. This volume should be called `gitea-data` and should be read/write, not readonly. Set the owner of the directory bound to the volume as `1002`. The command that would be used for this is `sudo chown 1002:1002 `. + +In the `env` stanza, there is an SSH domain. Set that to the local IP of your server so that you can use it to upload to git via SSH. \ No newline at end of file diff --git a/gitea/gitea.nomad b/gitea/gitea.nomad new file mode 100644 index 0000000..2ff0380 --- /dev/null +++ b/gitea/gitea.nomad @@ -0,0 +1,74 @@ +job "gitea" { + region = "global" + datacenters = [ + "dc1", + ] + type = "service" + + group "gitea" { + count = 1 + + network { + port "http" { + to = 3000 + } + + port "ssh" { + static = 2222 + to = 22 + } + } + + volume "gitea-data" { + type = "host" + source = "gitea-data" + read_only = false + } + + restart { + attempts = 5 + delay = "30s" + } + + task "app" { + driver = "docker" + volume_mount { + volume = "gitea-data" + destination = "/data" + read_only = false + } + + config { + image = "gitea/gitea:latest" + ports = ["ssh", "http"] + } + + env { + APP_NAME = "Gitea: Git with a cup of tea" + RUN_MODE = "prod" + SSH_DOMAIN = "CHANGE ME" + SSH_PORT = "$NOMAD_PORT_ssh" + ROOT_URL = "https://gitea.arsenm.dev/" + USER_UID = "1002" + USER_GID = "1002" + GITEA__server__START_SSH_SERVER = "true" + } + + resources { + cpu = 200 + memory = 512 + } + + service { + name = "gitea" + port = "http" + + tags = [ + "traefik.enable=true", + "traefik.http.routers.gitea.rule=Host(`gitea.arsenm.dev`)", + "traefik.http.routers.gitea.tls.certResolver=letsencrypt" + ] + } + } + } +} diff --git a/go-import-redirector/README.md b/go-import-redirector/README.md new file mode 100644 index 0000000..e69991d --- /dev/null +++ b/go-import-redirector/README.md @@ -0,0 +1,7 @@ +# Go Import Redirector + +This is the nomad job file I use for rsc's [go-import-redirector](https://github.com/rsc/go-import-redirector), which redirects the Go programming language tool to the proper github repo. For example, if someone tries to install one of my projects, rather than having to type out `go install gitea.arsenm.dev/Arsen6331/itd@latest`, they can just use `go install go.arsenm.dev/itd@latest` and this service will redirect them. + +This job file downloads an archive containing `go-import-redirector` executables for `x86_64` and `aarch64`, as well as a script that runs the correct one, from my minio instance. + +I am running two instances of this, automatically load-balanced by Traefik. Since the configuration is done entirely in command-line arguments, this workload is completely stateless, and can therefore be moved around freely by Nomad. \ No newline at end of file diff --git a/go-import-redirector/go-import-redirector.nomad b/go-import-redirector/go-import-redirector.nomad new file mode 100644 index 0000000..a594cc4 --- /dev/null +++ b/go-import-redirector/go-import-redirector.nomad @@ -0,0 +1,46 @@ +job "go-import-redirector" { + region = "global" + datacenters = ["dc1"] + type = "service" + + group "go-import-redirector" { + count = 2 + + network { + port "http" {} + } + + task "go-import-redirector" { + driver = "exec" + + config { + command = "local/exec.sh" + args = [ + "-addr", ":${NOMAD_PORT_http}", + "go.arsenm.dev/*", + "https://gitea.arsenm.dev/Arsen6331/*" + ] + } + + artifact { + source = "https://api.minio.arsenm.dev/adl/go-import-redirector.tar.gz" + } + + resources { + cpu = 100 + memory = 20 + } + + service { + name = "go-import-redirector" + port = "http" + + tags = [ + "traefik.enable=true", + "traefik.http.routers.go-import-redirector.rule=Host(`go.arsenm.dev`)", + "traefik.http.routers.go-import-redirector.tls.certResolver=letsencrypt" + ] + } + } + } +} diff --git a/homer/README.md b/homer/README.md new file mode 100644 index 0000000..1d4fdd8 --- /dev/null +++ b/homer/README.md @@ -0,0 +1,5 @@ +# Homer + +This is the nomad job file I use for the [Homer](https://github.com/bastienwirtz/homer/) dashboard. It takes its config file from the Consul Key/Value store. This means that whenever the config is edited, Nomad automatically installs the new file and restarts the container. It also means that Homer is completely stateless, and therefore can be freely moved around by Nomad. + +This directory also contains the config I use for my dashboard at https://dashboard.arsenm.dev. This is placed into the Consul K/V store as `homer/config.yml`. \ No newline at end of file diff --git a/homer/config.yml b/homer/config.yml new file mode 100644 index 0000000..3ad32ae --- /dev/null +++ b/homer/config.yml @@ -0,0 +1,84 @@ +--- +# Homepage configuration +# See https://fontawesome.com/v5/search for icons options + +# externalConfig: https://example.com/server-luci/config.yaml + +title: "Dashboard" +subtitle: "Home" +documentTitle: "Dashboard" + +header: true +footer: false + +columns: "auto" +connectivityCheck: true + +defaults: + layout: list + colorTheme: dark + +theme: default + +colors: + dark: + highlight-primary: "#00aa0b" + highlight-secondary: "#00b918" + highlight-hover: "#47c447" + +links: [] + +services: + - name: "Self-hosted Services" + icon: "fa-solid fa-user" + items: + - name: "SearXNG" + icon: "fa-solid fa-magnifying-glass" + subtitle: "Metasearch engine" + url: "https://search.arsenm.dev/" + - name: "Nextcloud" + icon: "fa-solid fa-cloud" + subtitle: "Cloud file storage" + url: "https://nextcloud.arsenm.dev/" + - name: "Home Assistant" + icon: "fa-solid fa-house" + subtitle: "Home automation hub" + url: "https://hass.arsenm.dev/" + - name: "Gitea" + icon: "fa-solid fa-code-branch" + subtitle: "Web interface for Git" + url: "https://gitea.arsenm.dev/" + - name: "Minio" + icon: "fa-solid fa-box" + subtitle: "Open source S3 implementation" + url: "https://minio.arsenm.dev/" + - name: "LMS" + icon: "fa-solid fa-music" + subtitle: "Lightweight music server" + url: "https://music.arsenm.dev/" + - name: "Piracy" + icon: "fa-solid fa-skull-crossbones" + items: + - name: "LibGen" + icon: "fa-solid fa-book" + subtitle: "Database of pirated books" + url: "https://whereislibgen.now.sh/go" + - name: "Sci-Hub" + icon: "fa-solid fa-flask" + subtitle: "Database of pirated scientific papers" + url: "https://sci-hub.now.sh/" + - name: "Administration" + icon: "fa-solid fa-wrench" + items: + - name: "Traefik" + icon: "fa fa-globe" + subtitle: "Reverse proxy" + url: "https://traefik.arsenm.dev/" + - name: "Nomad" + icon: "fa-solid fa-circle-nodes" + subtitle: "Cluster orchestrator" + url: "https://nomad.arsenm.dev/" + - name: "Consul" + icon: "fa-solid fa-database" + subtitle: "Service discovery and K/V store" + url: "https://consul.arsenm.dev/" \ No newline at end of file diff --git a/homer/homer.nomad b/homer/homer.nomad new file mode 100644 index 0000000..5c114ec --- /dev/null +++ b/homer/homer.nomad @@ -0,0 +1,46 @@ +job "homer" { + region = "global" + datacenters = ["dc1"] + type = "service" + + group "homer" { + count = 1 + + network { + port "homer" {} + } + + task "homer" { + driver = "docker" + + env { + PORT = "${NOMAD_PORT_homer}" + } + + config { + image = "b4bz/homer:latest" + ports = ["homer"] + + volumes = [ + "local/config.yml:/www/assets/config.yml" + ] + } + + template { + data = "{{ key `homer/config.yml` }}" + destination = "local/config.yml" + } + + service { + name = "homer" + port = "homer" + + tags = [ + "traefik.enable=true", + "traefik.http.routers.homer.rule=Host(`dashboard.arsenm.dev`)", + "traefik.http.routers.homer.tls.certResolver=letsencrypt", + ] + } + } + } +} diff --git a/lms/README.md b/lms/README.md new file mode 100644 index 0000000..0284ee6 --- /dev/null +++ b/lms/README.md @@ -0,0 +1,7 @@ +# LMS + +This is the nomad job file for the [Lightweight Music Server](https://github.com/epoupon/lms). + +This job requires two volumes. One for data and one for media. These volumes should be named `lms-data` and `lms-media` respectively. The `lms-data` volume should be read/write, not readonly, while the `lms-media` volume can be readonly. + +LMS' user will not have permissions to write to the data directory. There are multiple ways to solve this. The easy way is to set the permissions of the directory to `777`. Since the directory won't contain any user data and the service will not be exposed directly to the internet, but rather go through a reverse proxy, this should be fine, but I still wouldn't recommend it. The more secure option is to enter the container's shell and chown the directory so that it is owned by the same user that's running LMS inside the container. \ No newline at end of file diff --git a/lms/lms.nomad b/lms/lms.nomad new file mode 100644 index 0000000..5c36c22 --- /dev/null +++ b/lms/lms.nomad @@ -0,0 +1,59 @@ +job "lms" { + region = "global" + datacenters = ["dc1"] + type = "service" + + group "lms" { + count = 1 + + volume "lms-media" { + type = "host" + source = "lms-media" + read_only = true + } + + volume "lms-data" { + type = "host" + source = "lms-data" + read_only = false + } + + network { + port "lms" { + to = 5082 + } + } + + task "lms" { + driver = "docker" + + volume_mount { + volume = "lms-media" + destination = "/media" + read_only = true + } + + volume_mount { + volume = "lms-data" + destination = "/var/lms" + read_only = false + } + + config { + image = "epoupon/lms:latest" + ports = ["lms"] + } + + service { + name = "lms" + port = "lms" + + tags = [ + "traefik.enable=true", + "traefik.http.routers.lms.rule=Host(`music.arsenm.dev`)", + "traefik.http.routers.lms.tls.certResolver=letsencrypt", + ] + } + } + } +} diff --git a/minio/README.md b/minio/README.md new file mode 100644 index 0000000..d7577a4 --- /dev/null +++ b/minio/README.md @@ -0,0 +1,5 @@ +# Minio + +This is a nomad file for [Minio](https://min.io/), which is an object storage service with an Amazon S3-compatible API. This nomad file exposes both the console and the API of minio. If you would like to not expose the API, remove the `service` stanza with the name `minio-api`. + +In the `env` stanza, there is a username and password set to "CHANGE ME". Set these to the username/password you want to login with. \ No newline at end of file diff --git a/minio/minio.nomad b/minio/minio.nomad new file mode 100644 index 0000000..556cceb --- /dev/null +++ b/minio/minio.nomad @@ -0,0 +1,75 @@ +job "minio" { + datacenters = ["dc1"] + + group "minio" { + + network { + port "minio" {} + port "minio-api" {} + } + + volume "minio-data" { + type = "host" + source = "minio-data" + read_only = false + } + + task "minio" { + driver = "docker" + + volume_mount { + volume = "minio-data" + destination = "/data" + read_only = false + } + + config { + image = "minio/minio" + + ports = ["minio", "minio-api"] + + args = [ + "server", + "/data", + "--address", "0.0.0.0:${NOMAD_PORT_minio_api}", + "--console-address", "0.0.0.0:${NOMAD_PORT_minio}" + ] + } + + env { + MINIO_ROOT_USER = "CHANGE ME" + MINIO_ROOT_PASSWORD = "CHANGE ME" + } + + service { + name = "minio" + tags = [ + "traefik.enable=true", + "traefik.http.routers.minio.rule=Host(`minio.arsenm.dev`)", + "traefik.http.routers.minio.tls.certResolver=letsencrypt" + ] + + port = "minio" + + check { + type = "http" + path = "/minio/login" + port = "minio" + interval = "10s" + timeout = "2s" + } + } + + service { + name = "minio-api" + port = "minio-api" + + tags = [ + "traefik.enable=true", + "traefik.http.routers.minio-api.rule=Host(`api.minio.arsenm.dev`)", + "traefik.http.routers.minio-api.tls.certResolver=letsencrypt" + ] + } + } + } +} diff --git a/nextcloud-onlyoffice/README.md b/nextcloud-onlyoffice/README.md new file mode 100644 index 0000000..a71218a --- /dev/null +++ b/nextcloud-onlyoffice/README.md @@ -0,0 +1,15 @@ +# Nextcloud with OnlyOffice + +This nomad job file is used to run [Nextcloud](https://github.com/nextcloud/server) with [OnlyOffice](https://github.com/ONLYOFFICE/DocumentServer). Since OnlyOffice requires a lot of RAM, this job file reserves 2GB of RAM, 1.5GB for OnlyOffice, and 0.5GB for Nextcloud. + +There are two things in this file you will want to change. In the `env` stanza of the `nextcloud` task, the admin username and password is set to "CHANGE ME". Set these to whatever username/password you prefer. + +This job requires two volumes. One for Nextcloud's `/var/www/html` directory, which contains all of Nextcloud's files, and one for OnlyOffice's data. These should be called `nextcloud-html` and `onlyoffice-data` respectively, and they should both be read/write, not readonly. + +Once Nextcloud is up and running, if you're using https, go to the `nextcloud-html` volume you created and edit `config/config.php`. There, you will want to add + +```php +'overwriteprotocol' => 'https', +``` + +right above the `trusted_domains`. This will tell Nextcloud to use https for its URLs. Once this is done, you can install the OnlyOffice connector app, and set the OnlyOffice URL in the settings to whatever domain you used for OnlyOffice. \ No newline at end of file diff --git a/nextcloud-onlyoffice/nextcloud-onlyoffice.nomad b/nextcloud-onlyoffice/nextcloud-onlyoffice.nomad new file mode 100644 index 0000000..b82d5c3 --- /dev/null +++ b/nextcloud-onlyoffice/nextcloud-onlyoffice.nomad @@ -0,0 +1,106 @@ +job "nextcloud" { + region = "global" + datacenters = ["dc1"] + type = "service" + + group "nextcloud" { + + network { + port "http" { + to = 80 + } + + port "onlyoffice-http" { + to = 8000 + } + } + + volume "nextcloud-html" { + type = "host" + source = "nextcloud-html" + read_only = false + } + + volume "onlyoffice-data" { + type = "host" + source = "onlyoffice-data" + read_only = false + } + + task "nextcloud" { + driver = "docker" + + env { + NEXTCLOUD_ADMIN_USER = "CHANGE ME" + NEXTCLOUD_ADMIN_PASSWORD = "CHANGE ME" + NEXTCLOUD_TRUSTED_DOMAINS = "nextcloud.arsenm.dev" + } + + volume_mount { + volume = "nextcloud-html" + destination = "/var/www/html" + read_only = false + } + + config { + image = "nextcloud" + ports = ["http"] + } + + service { + name = "nextcloud" + port = "http" + tags = [ + "traefik.enable=true", + "traefik.http.routers.nextcloud.rule=Host(`nextcloud.arsenm.dev`)", + "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt" + ] + + check { + type = "tcp" + port = "http" + interval = "30s" + timeout = "2s" + } + } + + resources { + cpu = 500 + memory = 512 + } + } + + task "onlyoffice" { + driver = "docker" + + volume_mount { + volume = "onlyoffice-data" + destination = "/var/www/onlyoffice/Data" + read_only = false + } + + config { + image = "onlyoffice/documentserver:latest" + ports = ["onlyoffice-http"] + } + + + service { + name = "onlyoffice" + port = "onlyoffice-http" + tags = [ + "traefik.enable=true", + "traefik.http.routers.onlyoffice.rule=Host(`onlyoffice.arsenm.dev`)", + "traefik.http.routers.onlyoffice.tls.certresolver=letsencrypt", + "traefik.http.routers.onlyoffice.middlewares=onlyoffice-headers", + "traefik.http.middlewares.onlyoffice-headers.headers.customrequestheaders.X-Forwarded-Proto=https" + ] + } + + resources { + cpu = 500 + memory = 1536 + } + } + } +} diff --git a/searxng/README.md b/searxng/README.md new file mode 100644 index 0000000..a410619 --- /dev/null +++ b/searxng/README.md @@ -0,0 +1,7 @@ +# SearXNG + +This nomad file runs the [SearXNG](https://docs.searxng.org/) metasearch engine. SearXNG is a search engine that takes its results from other search engines and aggregates all of them into one, also known as a metasearch engine. + +There is one thing you will want to change in this config. In the `env` stanza, there is a secret set to "CHANGE ME". Set this to a random string. If you're on Linux, most linux distros can generate a suitable string using `openssl rand -base64 25`. + +This job is stateless, so it can be moved around freely by Nomad. \ No newline at end of file diff --git a/searxng/searxng.nomad b/searxng/searxng.nomad new file mode 100644 index 0000000..05643f7 --- /dev/null +++ b/searxng/searxng.nomad @@ -0,0 +1,50 @@ +job "searxng" { + region = "global" + datacenters = ["dc1"] + type = "service" + + group "searxng" { + count = 1 + + network { + port "searx" {} + } + + task "searxng" { + driver = "docker" + + env { + BIND_ADDRESS = "0.0.0.0:${NOMAD_PORT_searx}" + SEARXNG_BASE_URL = "https://search.arsenm.dev" + SEARXNG_SECRET = "CHANGE ME" + } + + config { + image = "searxng/searxng:latest" + + ports = ["searx"] + + cap_drop = ["all"] + cap_add = [ + "chown", + "setgid", + "setuid", + "dac_override" + ] + } + + service { + name = "searxng" + port = "searx" + + tags = [ + "traefik.enable=true", + "traefik.http.routers.searxng.rule=Host(`search.arsenm.dev`)", + "traefik.http.routers.searxng.tls.certResolver=letsencrypt", + "traefik.http.routers.searxng.middlewares=searxng-headers", + "traefik.http.middlewares.searxng-headers.headers.customrequestheaders.X-Robots-Tag=noindex, noarchive, nofollow" + ] + } + } + } +} diff --git a/traefik/README.md b/traefik/README.md new file mode 100644 index 0000000..e21344f --- /dev/null +++ b/traefik/README.md @@ -0,0 +1,21 @@ +# Traefik + +This job file is for the [Traefik](https://github.com/traefik/traefik) reverse proxy, which serves as the entry point for all requests to the cluster, and is the only way to access any services on it from outside the local network. + +This nomad job file also contains Traefik's own config embedded within it as part of a template stanza. + +In Traefik's config file is a variable called `email`. Set this to your email for Let's Encrypt to use when creating new TLS certificates for your domain. In the `tags` variable, there is a URL. In it, replace `` with the address of your Authelia server if you're running one. + +If you would like to constrain the reverse proxy to only run on a specific node in order to ensure that its IP stays constant, you can place the following inside of `task "traefik"`: + +```hcl +constraint { + attribute = "${attr.unique.hostname}" + operator = "==" + value = "" +} +``` + +replacing `` with the hostname of the node you want this to run on. + +In the `service` stanza, there is a `tags` variable. Inside it, there is a section configuring Authelia. If not using Authelia, remove this section and the one under it. There should be comments above them stating the same thing. \ No newline at end of file diff --git a/traefik/traefik.nomad b/traefik/traefik.nomad new file mode 100644 index 0000000..5604d43 --- /dev/null +++ b/traefik/traefik.nomad @@ -0,0 +1,109 @@ +job "traefik" { + region = "global" + datacenters = ["dc1"] + type = "service" + + group "traefik" { + count = 1 + + network { + port "http" { + static = 80 + } + + port "https" { + static = 443 + } + + port "api" { + static = 8081 + } + } + + service { + name = "traefik" + port = "api" + + check { + name = "alive" + type = "tcp" + port = "http" + interval = "10s" + timeout = "2s" + } + + tags = [ + "traefik.enable=true", + + // Redirect all http requests to HTTPS + "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true", + "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https", + "traefik.http.routers.http-catchall.entrypoints=http", + "traefik.http.routers.http-catchall.rule=HostRegexp(`{any:.+}`)", + "traefik.http.routers.http-catchall.middlewares=https-redirect", + + // Forward requests to protected services to Authelia. Remove this if not running Authelia. + "traefik.http.middlewares.authelia.forwardauth.address=http:///api/verify?rd=https://auth.arsenm.dev/", + "traefik.http.middlewares.authelia.forwardauth.trustforwardheader=true", + "traefik.http.middlewares.authelia.forwardauth.authresponseheaders=Remote-User, Remote-Groups", + + // Expose Traefik API with authentication. Remove this if not running Authelia. + "traefik.http.routers.traefik.rule=Host(`traefik.arsenm.dev`)", + "traefik.http.routers.traefik.tls.certResolver=letsencrypt", + "traefik.http.routers.traefik.middlewares=authelia", + ] + } + + task "traefik" { + driver = "docker" + + config { + image = "traefik:v2.2" + network_mode = "host" + + volumes = [ + "/opt/traefik/acme.json:/acme.json", + "local/traefik.toml:/etc/traefik/traefik.toml", + ] + } + + template { + data = <