mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 04:19:19 -08:00
feat: home-assistant + tewi
This commit is contained in:
parent
57e48cd9a8
commit
ec7571171b
15 changed files with 322 additions and 113 deletions
|
|
@ -116,6 +116,7 @@ in
|
|||
connection = tf.resources."${config.networking.hostName}".connection.set;
|
||||
};
|
||||
connection = {
|
||||
|
||||
port = lib.head config.services.openssh.ports;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
6
home/gui/nextcloud.nix
Normal file
6
home/gui/nextcloud.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{ config, ... }: {
|
||||
services = {
|
||||
nextcloud-client.enable = true;
|
||||
gnome-keyring.enable = true;
|
||||
};
|
||||
}
|
||||
44
meta.nix
44
meta.nix
|
|
@ -1,4 +1,45 @@
|
|||
{ config, pkgs, lib, root, ... }: {
|
||||
{ config, pkgs, lib, root, ... }: with lib; let
|
||||
home = config.deploy.targets.home.tf;
|
||||
in {
|
||||
options = {
|
||||
tailnet_uri = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
tailnet = mkOption {
|
||||
type = types.attrsOf (types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
addresses = {
|
||||
ipv4 = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
ipv6 = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
tags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
};
|
||||
config = {
|
||||
|
||||
tailnet_uri = "inskip.me";
|
||||
tailnet = let
|
||||
raw = home.resources.tailnet_devices.importAttr "devices";
|
||||
devices = mapListToAttrs (elet: nameValuePair (removeSuffix ".${config.tailnet_uri}" elet.name) {
|
||||
tags = elet.tags;
|
||||
addresses = let
|
||||
addresses = elet.addresses;
|
||||
ipv4 = head (filter (e: hasInfix "." e) addresses);
|
||||
ipv6 = head (filter (e: hasInfix ":" e) addresses);
|
||||
in {
|
||||
inherit ipv4 ipv6;
|
||||
};
|
||||
}) raw;
|
||||
in devices;
|
||||
|
||||
runners = {
|
||||
lazy = {
|
||||
file = ./default.nix;
|
||||
|
|
@ -14,4 +55,5 @@
|
|||
|
||||
deploy.targets.dummy.enable = false;
|
||||
_module.args.pkgs = lib.mkDefault pkgs;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
7
nixos/gui/nextcloud.nix
Normal file
7
nixos/gui/nextcloud.nix
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{ config, ... }: {
|
||||
services.gnome = {
|
||||
gnome-keyring.enable = true;
|
||||
};
|
||||
security.pam.services.lightdm.enableGnomeKeyring = true;
|
||||
programs.seahorse.enable = true;
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
{ config, lib, tf, pkgs, meta, ... }: with lib;
|
||||
|
||||
{
|
||||
options.network = with lib; {
|
||||
routeDefault = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
{ config, lib, tf, pkgs, meta, ... }: with lib; let
|
||||
in {
|
||||
options = with lib; {
|
||||
network = {
|
||||
routeDefault = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -31,12 +32,29 @@
|
|||
};
|
||||
};
|
||||
|
||||
kw.secrets.variables.tailscale-authkey = {
|
||||
path = "secrets/tailscale";
|
||||
field = "password";
|
||||
deploy.tf = {
|
||||
variables.tailscale-apikey = {
|
||||
value.shellCommand = "${meta.kw.secrets.command} secrets/tailscale -f api_key";
|
||||
sensitive = true;
|
||||
export = true;
|
||||
};
|
||||
providers.tailscale = {
|
||||
inputs = {
|
||||
api_key = tf.variables.tailscale-apikey.ref;
|
||||
tailnet = "inskip.me";
|
||||
};
|
||||
};
|
||||
variables.tailscale-authkey.export = true;
|
||||
resources.tailnet_key = {
|
||||
provider = "tailscale";
|
||||
type = "tailnet_key";
|
||||
inputs = {
|
||||
reusable = false;
|
||||
ephemeral = false;
|
||||
preauthorized = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
deploy.tf.variables.tailscale-authkey.export = true;
|
||||
|
||||
networking.firewall = {
|
||||
trustedInterfaces = [ "tailscale0" ];
|
||||
|
|
@ -71,7 +89,7 @@
|
|||
fi
|
||||
|
||||
# otherwise authenticate with tailscale
|
||||
${tailscale}/bin/tailscale up -authkey ${tf.variables.tailscale-authkey.get}
|
||||
${tailscale}/bin/tailscale up -authkey ${tf.resources.tailnet_key.getAttr "key"}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,107 +1,83 @@
|
|||
{ config, lib, ... }: {
|
||||
{ config, lib, tf, ... }: {
|
||||
kw.secrets.variables.ha-integration = {
|
||||
path = "secrets/home-assistant";
|
||||
field = "notes";
|
||||
};
|
||||
|
||||
secrets.files.ha-integration = {
|
||||
text = tf.variables.ha-integration.ref;
|
||||
owner = "hass";
|
||||
group = "hass";
|
||||
};
|
||||
|
||||
systemd.services.home-assistant = {
|
||||
preStart = lib.mkBefore ''
|
||||
rm ${config.services.home-assistant.configDir}/integration.json
|
||||
cp --no-preserve=mode ${config.secrets.files.ha-integration.path} ${config.services.home-assistant.configDir}/integration.json
|
||||
'';
|
||||
};
|
||||
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
config = {
|
||||
automation = "automations.yaml";
|
||||
config = null;
|
||||
counter = null;
|
||||
device_tracker = null;
|
||||
dhcp = null;
|
||||
energy = null;
|
||||
frontend = { themes = "themes"; };
|
||||
google_assistant = null;
|
||||
group = "groups.yaml";
|
||||
history = null;
|
||||
homeassistant = {
|
||||
external_url = "https://home.gensokyo.zone";
|
||||
packages = "packages";
|
||||
default_config = {};
|
||||
google_assistant = {
|
||||
project_id = "gensokyo-5cfaf";
|
||||
service_account = "!include integration.json";
|
||||
};
|
||||
http = {
|
||||
cors_allowed_origins = [
|
||||
"https://google.com"
|
||||
"https://www.home-assistant.io"
|
||||
];
|
||||
use_x_forwarded_for = "true";
|
||||
trusted_proxies = [
|
||||
"127.0.0.0/24"
|
||||
"200::/7"
|
||||
"100.64.0.0/10"
|
||||
"fd7a:115c:a1e0:ab12::/64"
|
||||
];
|
||||
use_x_forwarded_for = true;
|
||||
};
|
||||
image = null;
|
||||
input_boolean = null;
|
||||
input_datetime = null;
|
||||
input_number = null;
|
||||
input_select = null;
|
||||
input_text = null;
|
||||
logbook = null;
|
||||
|
||||
homeassistant = {
|
||||
name = "Gensokyo";
|
||||
unit_system = "metric";
|
||||
external_url = "https://home.gensokyo.zone";
|
||||
};
|
||||
logger = {
|
||||
default = "info";
|
||||
};
|
||||
device_tracker = null;
|
||||
map = null;
|
||||
media_source = null;
|
||||
mobile_app = null;
|
||||
my = null;
|
||||
person = null;
|
||||
recorder = {
|
||||
auto_purge = true;
|
||||
commit_interval = 1;
|
||||
exclude = {
|
||||
domains = [
|
||||
"automation"
|
||||
"updater"
|
||||
];
|
||||
entities = [
|
||||
"sun.sun"
|
||||
"sensor.last_boot"
|
||||
"sensor.date"
|
||||
"sensor.time"
|
||||
];
|
||||
entity_globs = [
|
||||
"sensor.weather_*"
|
||||
"sensor.date_*"
|
||||
];
|
||||
event_types = [
|
||||
"call_service"
|
||||
];
|
||||
};
|
||||
purge_keep_days = 14;
|
||||
db_url = "postgresql://@/hass";
|
||||
|
||||
};
|
||||
homekit = {
|
||||
name = "Tewi";
|
||||
port = 21063;
|
||||
ip_address = "10.1.1.38";
|
||||
};
|
||||
scene = "scenes.yaml";
|
||||
script = "scripts.yaml";
|
||||
ssdp = null;
|
||||
stream = null;
|
||||
sun = null;
|
||||
switch = null;
|
||||
system_health = null;
|
||||
tag = null;
|
||||
template = null;
|
||||
timer = null;
|
||||
tts = [{
|
||||
platform = "google_translate";
|
||||
service_name = "google_say";
|
||||
}];
|
||||
wake_on_lan = null;
|
||||
webhook = null;
|
||||
zeroconf = null;
|
||||
zone = null;
|
||||
};
|
||||
extraPackages = python3Packages: with python3Packages; [
|
||||
psycopg2
|
||||
securetar
|
||||
];
|
||||
extraComponents = [
|
||||
"zha"
|
||||
"esphome"
|
||||
"apple_tv"
|
||||
"spotify"
|
||||
"default_config"
|
||||
"cast"
|
||||
"plex"
|
||||
"google"
|
||||
"google_assistant"
|
||||
"google_cloud"
|
||||
"google_translate"
|
||||
"homekit"
|
||||
"mqtt"
|
||||
"wake_on_lan"
|
||||
"zeroconf"
|
||||
"esphome"
|
||||
"apple_tv"
|
||||
"spotify"
|
||||
"default_config"
|
||||
"cast"
|
||||
"plex"
|
||||
"met"
|
||||
"google"
|
||||
"google_assistant"
|
||||
"google_cloud"
|
||||
"google_translate"
|
||||
"homekit"
|
||||
"mqtt"
|
||||
"wake_on_lan"
|
||||
"zeroconf"
|
||||
];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,23 @@
|
|||
field = "z2m";
|
||||
};
|
||||
|
||||
kw.secrets.variables.hass-pass = {
|
||||
path = "secrets/mosquitto";
|
||||
field = "hass";
|
||||
};
|
||||
|
||||
secrets.files.z2m-pass = {
|
||||
text = tf.variables.z2m-pass.ref;
|
||||
owner = "mosquitto";
|
||||
group = "mosquitto";
|
||||
};
|
||||
|
||||
secrets.files.hass-pass = {
|
||||
text = tf.variables.hass-pass.ref;
|
||||
owner = "mosquitto";
|
||||
group = "mosquitto";
|
||||
};
|
||||
|
||||
services.mosquitto = {
|
||||
enable = true;
|
||||
persistence = true;
|
||||
|
|
@ -18,10 +29,16 @@
|
|||
"pattern readwrite #"
|
||||
];
|
||||
users = {
|
||||
hass = {
|
||||
passwordFile = config.secrets.files.hass-pass.path;
|
||||
acl = [
|
||||
"readwrite #"
|
||||
];
|
||||
};
|
||||
z2m = {
|
||||
passwordFile = config.secrets.files.z2m-pass.path;
|
||||
acl = [
|
||||
"topic readwrite zigbee2mqtt/#"
|
||||
"readwrite #"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
|||
69
nixos/systems/tewi/nginx.nix
Normal file
69
nixos/systems/tewi/nginx.nix
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
{ config, lib, pkgs, tf, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
secrets.files.dns_creds = {
|
||||
text = ''
|
||||
RFC2136_NAMESERVER='${tf.variables.katdns-address.ref}'
|
||||
RFC2136_TSIG_ALGORITHM='hmac-sha512.'
|
||||
RFC2136_TSIG_KEY='${tf.variables.katdns-name.ref}'
|
||||
RFC2136_TSIG_SECRET='${tf.variables.katdns-key.ref}'
|
||||
'';
|
||||
};
|
||||
|
||||
network.firewall = {
|
||||
public.tcp.ports = [ 443 80 ];
|
||||
private.tcp.ports = [ 443 80 ];
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
commonHttpConfig = ''
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=31536000; includeSubdomains; preload";
|
||||
}
|
||||
add_header Strict-Transport-Security $hsts_header;
|
||||
#add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
|
||||
add_header 'Referrer-Policy' 'origin-when-cross-origin';
|
||||
#add_header X-Frame-Options DENY;
|
||||
#add_header X-Content-Type-Options nosniff;
|
||||
#add_header X-XSS-Protection "1; mode=block";
|
||||
#proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
|
||||
'';
|
||||
clientMaxBodySize = "512m";
|
||||
virtualHosts = {
|
||||
"gensokyo.zone" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
root = pkgs.gensokyoZone;
|
||||
};
|
||||
};
|
||||
"home.${config.network.dns.domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = "http://127.0.0.1:8123";
|
||||
extraConfig = ''
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
security.acme = {
|
||||
defaults.email = config.network.dns.email;
|
||||
#email = config.network.dns.email;
|
||||
acceptTerms = true;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
{ meta, config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
imports = with meta; [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
nixos.network
|
||||
./home-assistant.nix
|
||||
./zigbee2mqtt.nix
|
||||
./mosquitto.nix
|
||||
./postgres.nix
|
||||
];
|
||||
|
||||
deploy.tf = {
|
||||
|
|
@ -29,6 +31,9 @@
|
|||
};
|
||||
|
||||
network = {
|
||||
firewall = {
|
||||
public.interfaces = lib.singleton "eno1";
|
||||
};
|
||||
addresses = {
|
||||
private = {
|
||||
enable = true;
|
||||
|
|
|
|||
13
nixos/systems/tewi/postgres.nix
Normal file
13
nixos/systems/tewi/postgres.nix
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{ config, pkgs, ... }: {
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
package = pkgs.postgresql_14;
|
||||
ensureDatabases = [ "hass" ];
|
||||
ensureUsers = [{
|
||||
name = "hass";
|
||||
ensurePermissions = {
|
||||
"DATABASE hass" = "ALL PRIVILEGES";
|
||||
};
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
|
@ -6,8 +6,13 @@
|
|||
log_level = "info";
|
||||
network_key = "!secret network_key";
|
||||
};
|
||||
mqtt = {
|
||||
server = "mqtt://127.0.0.1:1883";
|
||||
user = "z2m";
|
||||
password = tf.variables.z2m-mqtt-password.ref;
|
||||
};
|
||||
homeassistant = true;
|
||||
permit_join = true;
|
||||
permit_join = false;
|
||||
frontend = {
|
||||
port = 8072;
|
||||
};
|
||||
|
|
@ -18,6 +23,11 @@
|
|||
};
|
||||
};
|
||||
|
||||
kw.secrets.variables.z2m-mqtt-password = {
|
||||
path = "secrets/mosquitto";
|
||||
field = "z2m";
|
||||
};
|
||||
|
||||
kw.secrets.variables.z2m-network-key = {
|
||||
path = "secrets/zigbee2mqtt";
|
||||
field = "password";
|
||||
|
|
@ -40,6 +50,6 @@
|
|||
cp --no-preserve=mode ${config.secrets.files.zigbee2mqtt-secret.path} "${cfg.dataDir}/secret.yaml"
|
||||
'';
|
||||
|
||||
network.firewall.public.tcp.ports = [ 8123 8072 1883 ];
|
||||
network.firewall.public.tcp.ports = [ 8123 8072 1883 21064 21063 ];
|
||||
network.firewall.private.tcp.ports = [ 8123 ];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,4 +14,15 @@ final: prev: {
|
|||
wezterm = final.callPackage ./wezterm {
|
||||
inherit (final.darwin.apple_sdk.frameworks) Cocoa CoreGraphics Foundation UserNotifications;
|
||||
};
|
||||
terraform-providers = prev.terraform-providers // {
|
||||
tailscale = final.terraform-providers.mkProvider rec {
|
||||
owner = "tailscale";
|
||||
provider-source-address = "registry.terraform.io/${owner}/${owner}";
|
||||
repo = "terraform-provider-tailscale";
|
||||
rev = "v${version}";
|
||||
sha256 = "sha256-/qC8TOtoVoBTWeAFpt2TYE8tlYBCCcn/mzVQ/DN51YQ=";
|
||||
vendorSha256 = "sha256-8EIxqKkVO706oejlvN79K8aEZAF5H2vZRdr5vbQa0l4=";
|
||||
version = "0.13.5";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
cname = { inherit (config.network.addresses.public) target; };
|
||||
};
|
||||
|
||||
|
||||
deploy.tf.dns.records.services_cloud = {
|
||||
inherit (config.network.dns) zone;
|
||||
domain = "cloud";
|
||||
|
|
@ -18,6 +17,12 @@
|
|||
cname = { inherit (config.network.addresses.public) target; };
|
||||
};
|
||||
|
||||
deploy.tf.dns.records.gensokyo_home = {
|
||||
zone = "gensokyo.zone.";
|
||||
domain = "home";
|
||||
cname = { inherit (config.network.addresses.public) target; };
|
||||
};
|
||||
|
||||
deploy.tf.dns.records.gensokyo_root_v4 = {
|
||||
zone = "gensokyo.zone.";
|
||||
a = { inherit (config.network.addresses.public.tf.ipv4) address; };
|
||||
|
|
@ -37,6 +42,20 @@
|
|||
root = pkgs.gensokyoZone;
|
||||
};
|
||||
};
|
||||
"home.gensokyo.zone" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = "http://${meta.tailnet.tewi.addresses.ipv4}:8123";
|
||||
extraConfig = ''
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
"home.${config.network.dns.domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,36 @@
|
|||
{ config, lib, ... }: with lib;
|
||||
|
||||
{
|
||||
deploy.targets.home = {
|
||||
deploy.targets.home = let meta = config; in {
|
||||
tf = { config, ... }: {
|
||||
imports = optional (builtins.pathExists ../services/irlmail.nix) ../services/irlmail.nix;
|
||||
|
||||
dns.records.ygg_grimoire = {
|
||||
zone = "kittywit.ch.";
|
||||
domain = "grimoire.ygg";
|
||||
aaaa.address = "200:c87d:7960:916:bf0e:a0e1:3da7:4fc6";
|
||||
};
|
||||
variables.tailscale-apikey = {
|
||||
value.shellCommand = "${meta.kw.secrets.command} secrets/tailscale -f api_key";
|
||||
sensitive = true;
|
||||
export = true;
|
||||
};
|
||||
|
||||
dns.records.ygg_boline = {
|
||||
zone = "kittywit.ch.";
|
||||
domain = "boline.ygg";
|
||||
aaaa.address = "200:474d:14f7:1d21:f171:4e85:a3fa:9393";
|
||||
providers.tailscale = {
|
||||
inputs = {
|
||||
api_key = config.variables.tailscale-apikey.ref;
|
||||
tailnet = "inskip.me";
|
||||
};
|
||||
};
|
||||
resources = {
|
||||
tailnet_devices = {
|
||||
type = "devices";
|
||||
provider = "tailscale";
|
||||
dataSource = true;
|
||||
};
|
||||
tailnet_nr = {
|
||||
provider = "null";
|
||||
type = "resource";
|
||||
inputs.triggers = {
|
||||
mew = config.resources.tailnet_devices.refAttr "id";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
2
tf
2
tf
|
|
@ -1 +1 @@
|
|||
Subproject commit 856827e23fd7f1ef1d07dea9c5be26c0a0f7dee8
|
||||
Subproject commit 58d25138fdd294512a311a0fe3c92007f8d55f7a
|
||||
Loading…
Add table
Add a link
Reference in a new issue