feat: initial
This commit is contained in:
commit
bba9ceff39
18 changed files with 750 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
users/
|
||||
ssh_keys/
|
||||
results
|
||||
108
configuration.nix
Normal file
108
configuration.nix
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
nixosHardwareVersion = "7f1836531b126cfcf584e7d7d71bf8758bb58969";
|
||||
|
||||
timeZone = "Europe/Berlin";
|
||||
defaultLocale = "en_US.UTF-8";
|
||||
storageConfig = import ./data/storage.nix;
|
||||
fileSystemDefinition = lib.mapAttrs' (
|
||||
name: value: {
|
||||
name = storageConfig.${name}.path;
|
||||
value = {
|
||||
device = storageConfig.${name}.source;
|
||||
fsType = storageConfig.${name}.type;
|
||||
options = storageConfig.${name}.options;
|
||||
};
|
||||
}) storageConfig;
|
||||
in {
|
||||
imports = [
|
||||
"${fetchTarball "https://github.com/NixOS/nixos-hardware/archive/${nixosHardwareVersion}.tar.gz"}/raspberry-pi/4"
|
||||
./network/static-ip.nix
|
||||
./services/openssh.nix
|
||||
#./services/blocky.nix #dns
|
||||
./services/unbound.nix #dns
|
||||
./services/kea.nix #dhcp
|
||||
./services/nginx.nix #reverse proxy
|
||||
./services/qbittorrent.nix #torrent
|
||||
./services/kiwix.nix #wiki mirror
|
||||
./services/kiwix-updater.nix #wiki mirror update
|
||||
./users
|
||||
./programs
|
||||
];
|
||||
|
||||
fileSystems = fileSystemDefinition;
|
||||
|
||||
networking.hostName = "raspberry";
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
docker-compose
|
||||
docker-client
|
||||
podman
|
||||
podman-compose
|
||||
];
|
||||
|
||||
time.timeZone = timeZone;
|
||||
|
||||
virtualisation.docker = {
|
||||
enable = true;
|
||||
autoPrune.enable = true;
|
||||
daemon.settings = {
|
||||
"log-driver" = "json-file";
|
||||
"log-opts" = {
|
||||
"max-size" = "10m";
|
||||
"max-file" = "3";
|
||||
};
|
||||
};
|
||||
};
|
||||
virtualisation.podman = {
|
||||
enable = true;
|
||||
defaultNetwork.settings.dns_enabled = false;
|
||||
};
|
||||
|
||||
i18n = {
|
||||
defaultLocale = defaultLocale;
|
||||
extraLocaleSettings = {
|
||||
LC_ADDRESS = defaultLocale;
|
||||
LC_IDENTIFICATION = defaultLocale;
|
||||
LC_MEASUREMENT = defaultLocale;
|
||||
LC_MONETARY = defaultLocale;
|
||||
LC_NAME = defaultLocale;
|
||||
LC_NUMERIC = defaultLocale;
|
||||
LC_PAPER = defaultLocale;
|
||||
LC_TELEPHONE = defaultLocale;
|
||||
LC_TIME = defaultLocale;
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
mutableUsers = false;
|
||||
};
|
||||
|
||||
# Enable passwordless sudo.
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
users = ["nudelerde"];
|
||||
commands = [
|
||||
{
|
||||
command = "ALL";
|
||||
options = ["NOPASSWD"];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
dates = "weekly";
|
||||
options = "--delete-older-than +5"; # Keep last 5 generations
|
||||
};
|
||||
|
||||
# Enable GPU acceleration
|
||||
hardware.raspberry-pi."4".fkms-3d.enable = true;
|
||||
|
||||
system.stateVersion = "23.11";
|
||||
}
|
||||
67
data/network.nix
Normal file
67
data/network.nix
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
let
|
||||
lib = import <nixpkgs/lib>;
|
||||
in
|
||||
rec {
|
||||
network = {
|
||||
subnet = "192.168.2.0/24";
|
||||
subnet_base = "192.168.2.0";
|
||||
gateway = ips.router;
|
||||
cidr = 24;
|
||||
};
|
||||
|
||||
ips = {
|
||||
pi = "192.168.2.100";
|
||||
desktop = "192.168.2.101";
|
||||
router = "192.168.2.1";
|
||||
};
|
||||
|
||||
dhcp = {
|
||||
pool_start = "192.168.2.50";
|
||||
pool_end = "192.168.2.90";
|
||||
default_lease = 3600;
|
||||
max_lease = 86400;
|
||||
reservations = [{
|
||||
ip-address = ips.desktop;
|
||||
hw-address = "30:9c:23:81:91:ea";
|
||||
hostname = "desktop";
|
||||
}];
|
||||
};
|
||||
|
||||
fallback_dns_servers = [
|
||||
"1.1.1.1"
|
||||
"8.8.8.8"
|
||||
];
|
||||
|
||||
local_domain = "home";
|
||||
|
||||
services = {
|
||||
"pi" = {
|
||||
ip = ips.pi;
|
||||
};
|
||||
"desktop" = {
|
||||
ip = ips.desktop;
|
||||
};
|
||||
"torrent" = {
|
||||
ip = ips.pi;
|
||||
reverse_proxy = {
|
||||
port = 8085;
|
||||
};
|
||||
};
|
||||
"wiki" = {
|
||||
ip = ips.pi;
|
||||
reverse_proxy = {
|
||||
port = 8086;
|
||||
};
|
||||
};
|
||||
"router" = {
|
||||
ip = ips.router;
|
||||
};
|
||||
};
|
||||
|
||||
dnsMappings = builtins.listToAttrs (map (name: {
|
||||
name = "${name}.${local_domain}";
|
||||
value = services.${name}.ip;
|
||||
}) (builtins.attrNames services));
|
||||
|
||||
reverse_proxy = lib.filterAttrs (name: value: value ? reverse_proxy) services;
|
||||
}
|
||||
41
data/services.nix
Normal file
41
data/services.nix
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
let
|
||||
lib = import <nixpkgs/lib>;
|
||||
storage_data = import ./storage.nix;
|
||||
in
|
||||
rec {
|
||||
qbittorrent = {
|
||||
root_dir = "${storage_data.ssd.path}/qbittorrent";
|
||||
vpn = {
|
||||
username = "KNLdup50RYT1911K";
|
||||
password = "FQCd6rfszoze0BJGgBhMHa3pIzpUdtyt";
|
||||
};
|
||||
};
|
||||
kiwix = {
|
||||
root_dir = "${storage_data.ssd.path}/kiwix";
|
||||
urls = [
|
||||
"https://ftp.fau.de/kiwix/zim/wikipedia/wikipedia_en_all_nopic_2025-08.zim"
|
||||
"https://download.kiwix.org/zim/wikipedia/wikipedia_de_all_nopic_2026-01.zim"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
37
data/ssh.nix
Normal file
37
data/ssh.nix
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
let
|
||||
allKeyDir = "/etc/nixos/ssh_keys";
|
||||
readKeyFile = filePath:
|
||||
let
|
||||
content = builtins.readFile filePath;
|
||||
# Split on newlines and filter out empty strings
|
||||
lines = builtins.filter (line: line != "") (
|
||||
builtins.filter builtins.isString (
|
||||
builtins.split "\n" content
|
||||
)
|
||||
);
|
||||
in lines;
|
||||
|
||||
# Get all keys for a user
|
||||
getUserKeys = username:
|
||||
let
|
||||
userDir = "${allKeyDir}/${username}";
|
||||
in
|
||||
if builtins.pathExists userDir then
|
||||
let
|
||||
files = builtins.attrNames (builtins.readDir userDir);
|
||||
# Read all key files and flatten the list
|
||||
allKeys = builtins.concatMap (file:
|
||||
readKeyFile "${userDir}/${file}"
|
||||
) files;
|
||||
in allKeys
|
||||
else [];
|
||||
users = builtins.attrNames (builtins.readDir allKeyDir);
|
||||
in
|
||||
rec {
|
||||
keys = builtins.listToAttrs (map (user: {
|
||||
name = user;
|
||||
value = getUserKeys user;
|
||||
}) users);
|
||||
ssh_users = users;
|
||||
getKeys = getUserKeys;
|
||||
}
|
||||
14
data/storage.nix
Normal file
14
data/storage.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
rec {
|
||||
sdcard = {
|
||||
path = "/";
|
||||
type = "ext4";
|
||||
source = "/dev/disk/by-label/NIXOS_SD";
|
||||
options = ["noatime"];
|
||||
};
|
||||
ssd = {
|
||||
path = "/mnt/ssd";
|
||||
type = "ext4";
|
||||
source = "/dev/disk/by-uuid/a3ffb02e-fe9f-4bce-bd94-af0294ebff8f";
|
||||
options = ["noatime"];
|
||||
};
|
||||
}
|
||||
18
network/static-ip.nix
Normal file
18
network/static-ip.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
in
|
||||
{
|
||||
# Set a static IP address
|
||||
networking.interfaces.eth0.ipv4.addresses = [{
|
||||
address = net.ips.pi;
|
||||
prefixLength = net.network.cidr;
|
||||
}];
|
||||
|
||||
# Set default gateway (your router's IP)
|
||||
networking.defaultGateway = net.ips.router;
|
||||
|
||||
# Set DNS servers (fallback when Blocky isn't working)
|
||||
networking.nameservers = net.fallback_dns_servers;
|
||||
}
|
||||
3
programs/default.nix
Normal file
3
programs/default.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{...}: {
|
||||
imports = [./git.nix];
|
||||
}
|
||||
16
programs/git.nix
Normal file
16
programs/git.nix
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
{
|
||||
programs.git = {
|
||||
enable = true;
|
||||
config = {
|
||||
user = {
|
||||
name = "Katharina Heidenreich";
|
||||
email = "katharina.heidenreich02@gmail.com";
|
||||
};
|
||||
init.defaultBranch = "main";
|
||||
pull.rebase = false;
|
||||
core.editor = "nano";
|
||||
safe.directory = ["/etc/nixos"];
|
||||
};
|
||||
};
|
||||
}
|
||||
13
services/README.md
Normal file
13
services/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Services
|
||||
|
||||
## List
|
||||
- DHCP
|
||||
- Kea
|
||||
- DNS
|
||||
- Blocky
|
||||
- Reverse Proxy
|
||||
- nginx
|
||||
- Torrent
|
||||
- qbittorrent
|
||||
- Wiki
|
||||
- kiwix
|
||||
61
services/blocky.nix
Normal file
61
services/blocky.nix
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
in
|
||||
{
|
||||
# Enable Blocky
|
||||
services.blocky = {
|
||||
enable = true;
|
||||
settings = {
|
||||
# Listen on port 53 (standard DNS port)
|
||||
ports.dns = 53;
|
||||
|
||||
# Custom DNS entries for your local services
|
||||
customDNS = {
|
||||
# This maps your domains to your Pi's IP
|
||||
mapping = net.dnsMappings;
|
||||
# mapping = dnsMappings;
|
||||
};
|
||||
|
||||
conditional = {
|
||||
fallbackUpstream = false;
|
||||
mapping = builtins.mapAttrs (name: value: net.ips.router) net.dnsMappings;
|
||||
};
|
||||
|
||||
# Upstream DNS servers (with fallback)
|
||||
upstreams = {
|
||||
groups = {
|
||||
default =
|
||||
["https://cloudflare-dns.com/dns-query"] ++ net.fallback_dns_servers;
|
||||
};
|
||||
};
|
||||
|
||||
# Bootstrap DNS (for initially resolving DoH servers)
|
||||
bootstrapDns = {
|
||||
upstream = "https://1.1.1.1/dns-query";
|
||||
ips = ["1.1.1.1" "1.0.0.1"];
|
||||
};
|
||||
|
||||
# Enable caching for better performance
|
||||
caching = {
|
||||
minTime = "5m";
|
||||
maxTime = "30m";
|
||||
prefetching = true;
|
||||
};
|
||||
|
||||
# blocking = {
|
||||
# denylists = {
|
||||
# ads = ["https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"];
|
||||
# };
|
||||
# clientGroupsBlock = {
|
||||
# default = ["ads"];
|
||||
# };
|
||||
# };
|
||||
};
|
||||
};
|
||||
|
||||
# Allow DNS through the firewall
|
||||
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||
networking.firewall.allowedUDPPorts = [ 53 ];
|
||||
}
|
||||
56
services/kea.nix
Normal file
56
services/kea.nix
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
in
|
||||
{
|
||||
services.kea.dhcp4 = {
|
||||
enable = true;
|
||||
settings = {
|
||||
interfaces-config = {
|
||||
interfaces = [ "eth0" ];
|
||||
};
|
||||
lease-database = {
|
||||
name = "/var/lib/kea/dhcp4.leases";
|
||||
type = "memfile";
|
||||
};
|
||||
subnet4 = [{
|
||||
id = 1;
|
||||
subnet = net.network.subnet;
|
||||
pools = [{
|
||||
pool = "${net.dhcp.pool_start} - ${net.dhcp.pool_end}";
|
||||
}];
|
||||
option-data = [
|
||||
{
|
||||
name = "routers";
|
||||
data = net.ips.router;
|
||||
}
|
||||
{
|
||||
name = "domain-name-servers";
|
||||
data = builtins.concatStringsSep ", " ([net.ips.pi] ++ net.fallback_dns_servers);
|
||||
}
|
||||
{
|
||||
name = "domain-name";
|
||||
data = net.local_domain;
|
||||
}
|
||||
{
|
||||
name = "domain-search";
|
||||
data = net.local_domain;
|
||||
}
|
||||
];
|
||||
|
||||
reservations = net.dhcp.reservations;
|
||||
}];
|
||||
|
||||
valid-lifetime = net.dhcp.default_lease;
|
||||
renew-timer = net.dhcp.default_lease / 2;
|
||||
rebind-timer = net.dhcp.default_lease * 3 / 4;
|
||||
};
|
||||
};
|
||||
|
||||
# Firewall rules for DHCP
|
||||
networking.firewall = {
|
||||
allowedUDPPorts = [ 67 68 ]; # DHCP ports
|
||||
checkReversePath = false; # Sometimes needed for DHCP
|
||||
};
|
||||
}
|
||||
87
services/kiwix-updater.nix
Normal file
87
services/kiwix-updater.nix
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
# Import service data (make sure this path is correct)
|
||||
service_data = import ../data/services.nix;
|
||||
kiwix = service_data.kiwix;
|
||||
zimUrls = kiwix.urls;
|
||||
updater = pkgs.writeShellScriptBin "kiwix-updater" ''
|
||||
set -e
|
||||
|
||||
URLS=(
|
||||
${builtins.concatStringsSep " " zimUrls}
|
||||
)
|
||||
|
||||
download() {
|
||||
local url=''$1
|
||||
local filename=''$(basename "''$url")
|
||||
local filepath="${kiwix.root_dir}"/''$filename
|
||||
|
||||
if [ -f "''$filepath" ]; then
|
||||
echo "''$filepath exists!"
|
||||
return 0
|
||||
fi
|
||||
cd ${kiwix.root_dir}
|
||||
${pkgs.wget}/bin/wget --continue --quiet "''$url" -O "''$filename.tmp"
|
||||
mv ''$filename.tmp ''$filename
|
||||
}
|
||||
|
||||
build_lib() {
|
||||
{
|
||||
echo '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
echo '<library>'
|
||||
for zim in "${kiwix.root_dir}"/*.zim; do
|
||||
if [ -f "''$zim" ]; then
|
||||
filename=''$(basename "''$zim")
|
||||
size=''$(stat -c%s "''$zim")
|
||||
case "''$filename" in
|
||||
*_en_*)
|
||||
title="English Wikipedia (Text Only)"
|
||||
lang="eng"
|
||||
;;
|
||||
*_de_*)
|
||||
title="German Wikipedia (Text Only)"
|
||||
lang="deu"
|
||||
;;
|
||||
*)
|
||||
title="''$filename"
|
||||
lang="unknown"
|
||||
;;
|
||||
esac
|
||||
cat << EOF
|
||||
<book id="''$filename" path="/data/''$filename" title="''$title" language="''$lang">
|
||||
<title>''$title</title>
|
||||
<language>''$lang</language>
|
||||
<path>/data/''$filename</path>
|
||||
<size>''$size</size>
|
||||
</book>
|
||||
EOF
|
||||
fi
|
||||
done
|
||||
echo '</library>'
|
||||
} > "${kiwix.root_dir}/library.xml.tmp"
|
||||
mv "${kiwix.root_dir}/library.xml.tmp" "${kiwix.root_dir}/library.xml"
|
||||
}
|
||||
|
||||
for url in "''${URLS[@]}"; do
|
||||
download "''$url"
|
||||
done
|
||||
|
||||
build_lib
|
||||
|
||||
${pkgs.systemd}/bin/systemctl restart podman-kiwix-serve.service
|
||||
'';
|
||||
in {
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
wget
|
||||
curl
|
||||
];
|
||||
|
||||
services.cron = {
|
||||
enable = true;
|
||||
systemCronJobs = [
|
||||
"0 3 * * * root ${updater}/bin/kiwix-updater >/dev/null 2>&1"
|
||||
];
|
||||
};
|
||||
}
|
||||
36
services/kiwix.nix
Normal file
36
services/kiwix.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
service_data = import ../data/services.nix;
|
||||
kiwix = service_data.kiwix;
|
||||
in {
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${kiwix.root_dir} 0755 root root - -"
|
||||
"d ${kiwix.root_dir}/data 0755 root root - -"
|
||||
];
|
||||
|
||||
virtualisation.oci-containers.containers = {
|
||||
kiwix-serve = {
|
||||
image = "ghcr.io/kiwix/kiwix-serve:3.8.2";
|
||||
ports = ["8086:8080"];
|
||||
volumes = ["${kiwix.root_dir}/:/data:ro"];
|
||||
cmd = [
|
||||
"--monitorLibrary"
|
||||
"--library" "/data/library.xml"
|
||||
];
|
||||
environment = {
|
||||
TZ = "Europe/Berlin";
|
||||
};
|
||||
extraOptions = [
|
||||
"--memory=512m" # Limit container to 512MB RAM
|
||||
"--memory-swap=512m" # Disable swap usage
|
||||
"--cpus=1" # Limit to 1 CPU core
|
||||
];
|
||||
autoStart = true;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [8086];
|
||||
};
|
||||
}
|
||||
47
services/nginx.nix
Normal file
47
services/nginx.nix
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
network = import ../data/network.nix;
|
||||
rproxyServices = builtins.mapAttrs (name: service: {
|
||||
serverName = "${name}.${network.local_domain}";
|
||||
listen = [ {addr = "0.0.0.0"; port = 80;} ];
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = "http://127.0.0.1:${builtins.toString service.reverse_proxy.port}/";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
extraConfig = ''
|
||||
allow ${network.network.subnet};
|
||||
deny all;
|
||||
'';
|
||||
}) network.reverse_proxy;
|
||||
serviceNamesMessage = builtins.toString (builtins.attrNames network.reverse_proxy);
|
||||
fallback = {
|
||||
serverName = "_";
|
||||
listen = [ {addr = "0.0.0.0"; port = 80;} ];
|
||||
locations."/" = {
|
||||
return = "404";
|
||||
extraConfig = ''
|
||||
add_header Content-Type text/plain;
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = ''
|
||||
return 404 "This domain is not configured. Available services: ${serviceNamesMessage}";
|
||||
'';
|
||||
};
|
||||
in {
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
|
||||
virtualHosts = rproxyServices // {fallback = fallback;};
|
||||
};
|
||||
|
||||
# TODO add 443 for https
|
||||
networking.firewall.allowedTCPPorts = [80];
|
||||
}
|
||||
17
services/openssh.nix
Normal file
17
services/openssh.nix
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#{ config, pkgs, lib, ... }:
|
||||
let
|
||||
ssh_data = import ../data/ssh.nix;
|
||||
in {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PasswordAuthentication = true;
|
||||
PermitRootLogin = "no";
|
||||
AllowUsers = ssh_data.ssh_users;
|
||||
};
|
||||
};
|
||||
|
||||
users.users = builtins.mapAttrs (username: value: {
|
||||
openssh.authorizedKeys.keys = ssh_data.keys.${username};
|
||||
}) ssh_data.keys;
|
||||
}
|
||||
92
services/qbittorrent.nix
Normal file
92
services/qbittorrent.nix
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
serviceData = import ../data/services.nix;
|
||||
qbt = serviceData.qbittorrent;
|
||||
in {
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${qbt.root_dir} 0755 root root - -"
|
||||
"d ${qbt.root_dir}/gluetun 0755 root root - -"
|
||||
"d ${qbt.root_dir}/downloads 0755 root root - -"
|
||||
"d ${qbt.root_dir}/config 0755 root root - -"
|
||||
];
|
||||
|
||||
environment.etc."qbittorrent-compose/docker-compose.yml" = {
|
||||
mode = "0444";
|
||||
text = ''
|
||||
services:
|
||||
gluetun:
|
||||
image: docker.io/qmcgaw/gluetun:latest
|
||||
pull_policy: always
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
network_mode: bridge
|
||||
ports:
|
||||
- 127.0.0.1:8085:8085 # qBittorrent
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ${qbt.root_dir}/gluetun/:/gluetun
|
||||
environment:
|
||||
- VPN_SERVICE_PROVIDER=protonvpn
|
||||
- SERVER_HOSTNAME=node-nl-28.protonvpn.net,node-ch-06.protonvpn.net,node-nl-13.protonvpn.net,node-ch-06.protonvpn.net,node-es-04.protonvpn.net
|
||||
- UPDATER_PERIOD=24h
|
||||
|
||||
- OPENVPN_USER=${qbt.vpn.username}
|
||||
- OPENVPN_PASSWORD=${qbt.vpn.password}
|
||||
|
||||
- DOT_PROVIDERS=cloudflare,google
|
||||
- BLOCK_ADS=off
|
||||
- BLOCK_MALICIOUS=off
|
||||
- BLOCK_SURVEILLANCE=off
|
||||
|
||||
- TZ=Europe/Berlin
|
||||
|
||||
qbittorrent:
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
pull_policy: always
|
||||
network_mode: 'service:gluetun'
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- WEBUI_PORT=8085
|
||||
volumes:
|
||||
- ${qbt.root_dir}/config/:/config
|
||||
- ${qbt.root_dir}/downloads/:/downloads
|
||||
'';
|
||||
};
|
||||
systemd.services.qbittorrent-stack = {
|
||||
description = "qbittorrent stack";
|
||||
after = ["docker.service" "network.target"];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
WorkingDirectory = qbt.root_dir;
|
||||
ExecStart = "${pkgs.writeShellScript "torrent-start" ''
|
||||
set -e
|
||||
# Copy compose file to working directory
|
||||
cp /etc/qbittorrent-compose/docker-compose.yml ${qbt.root_dir}/
|
||||
cd ${qbt.root_dir}
|
||||
${pkgs.docker-compose}/bin/docker-compose up -d
|
||||
''}";
|
||||
ExecStop = "${pkgs.writeShellScript "torrent-stop" ''
|
||||
cd ${qbt.root_dir}
|
||||
${pkgs.docker-compose}/bin/docker-compose down
|
||||
''}";
|
||||
ExecReload = "${pkgs.writeShellScript "torrent-reload" ''
|
||||
cd ${qbt.root_dir}
|
||||
${pkgs.docker-compose}/bin/docker-compose restart
|
||||
''}";
|
||||
|
||||
Restart = "on-failure";
|
||||
RestartSec = 10;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [8085];
|
||||
};
|
||||
}
|
||||
34
services/unbound.nix
Normal file
34
services/unbound.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
in
|
||||
{
|
||||
services.unbound = {
|
||||
enable = true;
|
||||
settings = {
|
||||
|
||||
server = {
|
||||
interface = ["0.0.0.0" "::0"];
|
||||
|
||||
access-control = ["127.0.0.1 allow" "${net.network.subnet} allow"];
|
||||
|
||||
local-zone = "\"${net.local_domain}.\" static";
|
||||
local-data =
|
||||
(map (name:
|
||||
let ip = net.dnsMappings.${name}; in
|
||||
"\"${name}. IN A ${ip}\""
|
||||
) (builtins.attrNames net.dnsMappings));
|
||||
};
|
||||
|
||||
forward-zone = {
|
||||
name = ".";
|
||||
forward-addr = net.fallback_dns_servers;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Allow DNS through the firewall
|
||||
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||
networking.firewall.allowedUDPPorts = [ 53 ];
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue