Compare commits
12 Commits
db25a0ea79
...
5d95773722
| Author | SHA1 | Date | |
|---|---|---|---|
|
5d95773722
|
|||
|
c59ee18d09
|
|||
|
72b006a7e4
|
|||
|
0b01f40ac8
|
|||
|
d17c8b1b34
|
|||
|
5ee891fe2b
|
|||
|
d1aae53fa6
|
|||
|
6c419454d8
|
|||
|
706cd8e919
|
|||
|
c0e0d74e4f
|
|||
|
74707a469c
|
|||
|
3b9a75c7ba
|
43
flake.lock
generated
43
flake.lock
generated
@@ -18,49 +18,13 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"krew2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716272275,
|
||||
"narHash": "sha256-JWDyPhAJp263EVVsGrKwrJU+xdDReHsDmSe7A190/Cg=",
|
||||
"owner": "eigengrau",
|
||||
"repo": "krew2nix",
|
||||
"rev": "0c1fecaab044dba1249c5d09366891ec467b4ad2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "eigengrau",
|
||||
"repo": "krew2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1761236834,
|
||||
"narHash": "sha256-+pthv6hrL5VLW2UqPdISGuLiUZ6SnAXdd2DdUE+fV2Q=",
|
||||
"lastModified": 1762943920,
|
||||
"narHash": "sha256-ITeH8GBpQTw9457ICZBddQEBjlXMmilML067q0e6vqY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d5faa84122bc0a1fd5d378492efce4e289f8eac1",
|
||||
"rev": "91c9a64ce2a84e648d0cf9671274bb9c2fb9ba60",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -73,7 +37,6 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"krew2nix": "krew2nix",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
|
||||
13
flake.nix
13
flake.nix
@@ -4,14 +4,9 @@
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
krew2nix = {
|
||||
url = "github:eigengrau/krew2nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, flake-utils, krew2nix, ... }: flake-utils.lib.eachDefaultSystem (system:
|
||||
outputs = { nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
lib = nixpkgs.lib;
|
||||
|
||||
@@ -24,16 +19,12 @@
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
kubectl = krew2nix.packages.${system}.kubectl;
|
||||
in {
|
||||
# Define the devShell for the current system
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
kubernetes-helm
|
||||
(kubectl.withKrewPlugins (plugins: with plugins; [
|
||||
cnpg
|
||||
]))
|
||||
kubectl-cnpg
|
||||
nil
|
||||
terraform
|
||||
tflint
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
global:
|
||||
storageClass: longhorn-crypto
|
||||
storageClass: longhorn
|
||||
image:
|
||||
rootless: false
|
||||
service:
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
global:
|
||||
nodeSelector:
|
||||
nodepool: worker
|
||||
defaultSettings:
|
||||
defaultReplicaCount: 3
|
||||
storageOverProvisioningPercentage: 100
|
||||
defaultReplicaCount: "3"
|
||||
storageOverProvisioningPercentage: "100"
|
||||
backupCompressionMethod: "gzip"
|
||||
replicaSoftAntiAffinity: "true"
|
||||
concurrentReplicaRebuildPerNodeLimit: "1"
|
||||
replicaReplenishmentWaitInterval: "600"
|
||||
disableSchdedulingOnCordonedNode: "true"
|
||||
defaultBackupStore:
|
||||
backupTarget: "s3://homelab@auto/longhorn"
|
||||
backupTarget: "s3://longhorn-backups@auto"
|
||||
backupTargetCredentialSecret: cloudflare-token
|
||||
metrics:
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
enabled: false
|
||||
ingress:
|
||||
enabled: true
|
||||
ingressClassName: nginx-internal
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
controller:
|
||||
replicaCount: 3
|
||||
nodeSelector:
|
||||
nodepool: worker
|
||||
ingressClassResource:
|
||||
name: nginx-internal
|
||||
enabled: true
|
||||
@@ -9,8 +12,31 @@ controller:
|
||||
service:
|
||||
annotations:
|
||||
external-dns.alpha.kubernetes.io/hostname: "dogar.dev"
|
||||
extraVolumes:
|
||||
- name: nix-cache
|
||||
persistentVolumeClaim:
|
||||
claimName: nix-cache
|
||||
extraVolumeMounts:
|
||||
- name: nix-cache
|
||||
mountPath: /var/cache/nginx/nix
|
||||
podSecurityContext:
|
||||
fsGroup: 101
|
||||
config:
|
||||
proxy-buffering: "on"
|
||||
proxy-ssl-server-name: "true"
|
||||
http-snippet: |
|
||||
# Persistent on-disk cache; lives on the PVC
|
||||
proxy_cache_path /var/cache/nginx/nix levels=1:2 keys_zone=cachecache:32m max_size=120g inactive=365d use_temp_path=off;
|
||||
|
||||
# Only advertise cacheability for 200/302
|
||||
map $status $cache_header {
|
||||
200 "public";
|
||||
302 "public";
|
||||
default "no-cache";
|
||||
}
|
||||
tcp:
|
||||
22: "homelab/gitea-ssh:22"
|
||||
25565: "minecraft/monifactory-server:25565"
|
||||
25566: "minecraft/gtnh-server:25565"
|
||||
25567: "minecraft/tfg-server:25565"
|
||||
25568: "minecraft/atm10-server:25565"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
commonLabels:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Kustomize
|
||||
resources:
|
||||
- ./metallb/pool.yaml
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: metallb.io/v1beta1
|
||||
kind: IPAddressPool
|
||||
metadata:
|
||||
name: pool
|
||||
namespace: homelab
|
||||
namespace: metallb-system
|
||||
spec:
|
||||
addresses:
|
||||
- 192.168.18.192/26
|
||||
@@ -12,7 +12,7 @@ apiVersion: metallb.io/v1beta1
|
||||
kind: L2Advertisement
|
||||
metadata:
|
||||
name: pool
|
||||
namespace: homelab
|
||||
namespace: metallb-system
|
||||
spec:
|
||||
ipAddressPools:
|
||||
- pool
|
||||
|
||||
@@ -11,7 +11,6 @@ type LonghornOptions = {
|
||||
helm: HelmProvider;
|
||||
};
|
||||
name: string;
|
||||
namespace: string;
|
||||
};
|
||||
|
||||
export class Longhorn extends Construct {
|
||||
@@ -19,15 +18,15 @@ export class Longhorn extends Construct {
|
||||
super(scope, id);
|
||||
|
||||
const { helm, kubernetes } = options.providers;
|
||||
const namespace = "longhorn-system";
|
||||
|
||||
new Release(this, id, {
|
||||
name: options.name,
|
||||
namespace: options.namespace,
|
||||
namespace,
|
||||
provider: helm,
|
||||
repository: "https://charts.longhorn.io",
|
||||
chart: "longhorn",
|
||||
createNamespace: true,
|
||||
upgradeInstall: true,
|
||||
values: [
|
||||
fs.readFileSync("helm/values/longhorn.values.yaml", {
|
||||
encoding: "utf8",
|
||||
@@ -38,44 +37,19 @@ export class Longhorn extends Construct {
|
||||
new Manifest(this, "recurring-backup-job", {
|
||||
provider: kubernetes,
|
||||
manifest: {
|
||||
apiVersion: "longhorn.io/v1beta1",
|
||||
apiVersion: "longhorn.io/v1beta2",
|
||||
kind: "RecurringJob",
|
||||
metadata: {
|
||||
name: "daily-backup",
|
||||
namespace: options.namespace,
|
||||
namespace,
|
||||
},
|
||||
spec: {
|
||||
cron: "0 0 * * *",
|
||||
task: "backup",
|
||||
retain: 30,
|
||||
groups: ["default"],
|
||||
retain: 7,
|
||||
concurrency: 3,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
new Manifest(this, "longhorn-crypto-storage-class", {
|
||||
provider: kubernetes,
|
||||
manifest: {
|
||||
kind: "StorageClass",
|
||||
apiVersion: "storage.k8s.io/v1",
|
||||
metadata: {
|
||||
name: "longhorn-crypto",
|
||||
},
|
||||
provisioner: "driver.longhorn.io",
|
||||
allowVolumeExpansion: true,
|
||||
parameters: {
|
||||
numberOfReplicas: "3",
|
||||
staleReplicaTimeout: "2880", // 48 hours in minutes
|
||||
encrypted: "true",
|
||||
"csi.storage.k8s.io/provisioner-secret-name": "longhorn-encryption",
|
||||
"csi.storage.k8s.io/provisioner-secret-namespace": options.namespace,
|
||||
"csi.storage.k8s.io/node-publish-secret-name": "longhorn-encryption",
|
||||
"csi.storage.k8s.io/node-publish-secret-namespace": options.namespace,
|
||||
"csi.storage.k8s.io/node-stage-secret-name": "longhorn-encryption",
|
||||
"csi.storage.k8s.io/node-stage-secret-namespace": options.namespace,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
34
main.ts
34
main.ts
@@ -1,9 +1,10 @@
|
||||
import * as dotenv from "dotenv";
|
||||
import { cleanEnv, str } from "envalid";
|
||||
import { Construct } from "constructs";
|
||||
import { App, TerraformStack, S3Backend } from "cdktf";
|
||||
import { App, TerraformStack, LocalBackend } from "cdktf";
|
||||
import { HelmProvider } from "@cdktf/provider-helm/lib/provider";
|
||||
import { KubernetesProvider } from "@cdktf/provider-kubernetes/lib/provider";
|
||||
import { NamespaceV1 } from "@cdktf/provider-kubernetes/lib/namespace-v1";
|
||||
|
||||
import { GiteaServer } from "./gitea";
|
||||
import { OnePassword } from "./1password";
|
||||
@@ -12,7 +13,6 @@ import { Longhorn } from "./longhorn";
|
||||
import { AuthentikServer } from "./authentik";
|
||||
import { ValkeyCluster } from "./valkey";
|
||||
import { CertManager } from "./cert-manager";
|
||||
import { Manifest } from "@cdktf/provider-kubernetes/lib/manifest";
|
||||
import { Nginx } from "./nginx";
|
||||
import { Prometheus } from "./prometheus";
|
||||
import { MetalLB } from "./metallb";
|
||||
@@ -45,16 +45,11 @@ class Homelab extends TerraformStack {
|
||||
|
||||
const namespace = "homelab";
|
||||
|
||||
const ns = new Manifest(this, "namespace", {
|
||||
new NamespaceV1(this, "namespace", {
|
||||
provider: kubernetes,
|
||||
manifest: {
|
||||
kind: "Namespace",
|
||||
apiVersion: "v1",
|
||||
metadata: {
|
||||
name: namespace,
|
||||
},
|
||||
spec: {},
|
||||
},
|
||||
});
|
||||
|
||||
new Longhorn(this, "longhorn", {
|
||||
@@ -65,12 +60,10 @@ class Homelab extends TerraformStack {
|
||||
},
|
||||
});
|
||||
|
||||
longhorn.node.addDependency(ns);
|
||||
|
||||
new MetalLB(this, "metallb", {
|
||||
provider: helm,
|
||||
name: "metallb",
|
||||
namespace,
|
||||
namespace: "metallb-system",
|
||||
});
|
||||
|
||||
new OnePassword(this, "one-password", {
|
||||
@@ -121,7 +114,6 @@ class Homelab extends TerraformStack {
|
||||
kubernetes,
|
||||
helm,
|
||||
},
|
||||
storageClass: "longhorn-crypto",
|
||||
users: ["shahab", "budget-tracker", "authentik", "gitea"],
|
||||
primaryUser: "shahab",
|
||||
initSecretName: "postgres-password",
|
||||
@@ -156,21 +148,9 @@ class Homelab extends TerraformStack {
|
||||
const app = new App();
|
||||
const stack = new Homelab(app, "homelab");
|
||||
|
||||
new S3Backend(stack, {
|
||||
encrypt: true,
|
||||
bucket: env.BUCKET,
|
||||
key: "terraform.tfstate",
|
||||
region: "auto",
|
||||
skipCredentialsValidation: true,
|
||||
skipMetadataApiCheck: true,
|
||||
skipRegionValidation: true,
|
||||
skipRequestingAccountId: true,
|
||||
skipS3Checksum: true,
|
||||
accessKey: env.R2_ACCESS_KEY_ID,
|
||||
secretKey: env.R2_SECRET_ACCESS_KEY,
|
||||
endpoints: {
|
||||
s3: `${r2Endpoint}/${env.BUCKET}`,
|
||||
},
|
||||
new LocalBackend(stack, {
|
||||
path: "terraform.tfstate",
|
||||
workspaceDir: ".",
|
||||
});
|
||||
|
||||
app.synth();
|
||||
|
||||
231
media/deployment.yaml
Normal file
231
media/deployment.yaml
Normal file
@@ -0,0 +1,231 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: server
|
||||
namespace: media
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: server
|
||||
spec:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: aamil-3
|
||||
containers:
|
||||
- name: server
|
||||
image: jellyfin/jellyfin:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 8096
|
||||
name: http
|
||||
env:
|
||||
- name: TZ
|
||||
value: "Asia/Karachi"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /config
|
||||
- name: cache
|
||||
mountPath: /cache
|
||||
- name: media
|
||||
mountPath: /media
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: jellyfin-config
|
||||
- name: cache
|
||||
emptyDir: {}
|
||||
- name: media
|
||||
persistentVolumeClaim:
|
||||
claimName: media
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: sonarr
|
||||
namespace: media
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: sonarr
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: sonarr
|
||||
spec:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: aamil-3
|
||||
containers:
|
||||
- name: sonarr
|
||||
image: lscr.io/linuxserver/sonarr:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 8989
|
||||
name: http
|
||||
env:
|
||||
- name: TZ
|
||||
value: "Asia/Karachi"
|
||||
- name: PUID
|
||||
value: "1000"
|
||||
- name: PGID
|
||||
value: "1000"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /config
|
||||
- name: media
|
||||
mountPath: /media
|
||||
- name: downloads
|
||||
mountPath: /downloads
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: sonarr-config
|
||||
- name: media
|
||||
persistentVolumeClaim:
|
||||
claimName: media
|
||||
- name: downloads
|
||||
persistentVolumeClaim:
|
||||
claimName: downloads
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: qbittorrent
|
||||
namespace: media
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: qbittorrent
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: qbittorrent
|
||||
spec:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: aamil-3
|
||||
containers:
|
||||
- name: qbittorrent
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
ports:
|
||||
- containerPort: 8080 # web UI
|
||||
name: http
|
||||
- containerPort: 6881
|
||||
name: bt
|
||||
- containerPort: 6881
|
||||
protocol: UDP
|
||||
name: bt-udp
|
||||
env:
|
||||
- name: TZ
|
||||
value: "Asia/Karachi"
|
||||
- name: PUID
|
||||
value: "1000"
|
||||
- name: PGID
|
||||
value: "1000"
|
||||
- name: WEBUI_PORT
|
||||
value: "8080"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /config
|
||||
- name: downloads
|
||||
mountPath: /downloads
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: qbittorrent-config
|
||||
- name: downloads
|
||||
persistentVolumeClaim:
|
||||
claimName: downloads
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: prowlarr
|
||||
namespace: media
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: prowlarr
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: prowlarr
|
||||
spec:
|
||||
nodeSelector:
|
||||
nodepool: worker
|
||||
containers:
|
||||
- name: prowlarr
|
||||
image: lscr.io/linuxserver/prowlarr:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 9696
|
||||
name: http
|
||||
env:
|
||||
- name: TZ
|
||||
value: "Asia/Karachi"
|
||||
- name: PUID
|
||||
value: "1000"
|
||||
- name: PGID
|
||||
value: "1000"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /config
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: prowlarr-config
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: radarr
|
||||
namespace: media
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: radarr
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: radarr
|
||||
spec:
|
||||
nodeSelector:
|
||||
kubernetes.io/hostname: aamil-3
|
||||
containers:
|
||||
- name: radarr
|
||||
image: lscr.io/linuxserver/radarr:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 7878
|
||||
name: http
|
||||
env:
|
||||
- name: TZ
|
||||
value: "Asia/Karachi"
|
||||
- name: PUID
|
||||
value: "1000"
|
||||
- name: PGID
|
||||
value: "1000"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /config
|
||||
- name: media
|
||||
mountPath: /media
|
||||
- name: downloads
|
||||
mountPath: /downloads
|
||||
volumes:
|
||||
- name: config
|
||||
persistentVolumeClaim:
|
||||
claimName: radarr-config
|
||||
- name: media
|
||||
persistentVolumeClaim:
|
||||
claimName: media
|
||||
- name: downloads
|
||||
persistentVolumeClaim:
|
||||
claimName: downloads
|
||||
76
media/ingress.yaml
Normal file
76
media/ingress.yaml
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: server
|
||||
namespace: media
|
||||
annotations:
|
||||
# cert-manager (Cloudflare DNS-01)
|
||||
cert-manager.io/cluster-issuer: cloudflare-issuer
|
||||
cert-manager.io/acme-challenge-type: dns01
|
||||
cert-manager.io/private-key-size: "4096"
|
||||
|
||||
# Jellyfin / streaming friendly nginx settings
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
nginx.ingress.kubernetes.io/proxy-buffering: "off"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
|
||||
nginx.ingress.kubernetes.io/use-proxy-protocol: "false"
|
||||
nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
|
||||
spec:
|
||||
ingressClassName: nginx-internal
|
||||
tls:
|
||||
- hosts:
|
||||
- media.dogar.dev
|
||||
secretName: media-tls
|
||||
- hosts:
|
||||
- sonarr.dogar.dev
|
||||
secretName: sonarr-tls
|
||||
- hosts:
|
||||
- radarr.dogar.dev
|
||||
secretName: radarr-tls
|
||||
- hosts:
|
||||
- torrent.dogar.dev
|
||||
secretName: torrent-tls
|
||||
rules:
|
||||
- host: media.dogar.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: server
|
||||
port:
|
||||
number: 80
|
||||
- host: sonarr.dogar.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: sonarr
|
||||
port:
|
||||
number: 80
|
||||
- host: radarr.dogar.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: radarr
|
||||
port:
|
||||
number: 80
|
||||
- host: torrent.dogar.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: qbittorrent
|
||||
port:
|
||||
number: 80
|
||||
5
media/namespace.yaml
Normal file
5
media/namespace.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: media
|
||||
106
media/pvc.yaml
Normal file
106
media/pvc.yaml
Normal file
@@ -0,0 +1,106 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: jellyfin-config
|
||||
namespace: media
|
||||
labels:
|
||||
recurring-job.longhorn.io/source: "enabled"
|
||||
recurring-job.longhorn.io/backup: "enabled"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: media
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 512Gi
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: sonarr-config
|
||||
namespace: media
|
||||
labels:
|
||||
recurring-job.longhorn.io/source: "enabled"
|
||||
recurring-job.longhorn.io/backup: "enabled"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 512Mi
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: qbittorrent-config
|
||||
namespace: media
|
||||
labels:
|
||||
recurring-job.longhorn.io/source: "enabled"
|
||||
recurring-job.longhorn.io/backup: "enabled"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 512Mi
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: downloads
|
||||
namespace: media
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 450Gi
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: prowlarr-config
|
||||
namespace: media
|
||||
labels:
|
||||
recurring-job.longhorn.io/source: "enabled"
|
||||
recurring-job.longhorn.io/backup: "enabled"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 512Mi
|
||||
storageClassName: longhorn
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: radarr-config
|
||||
namespace: media
|
||||
labels:
|
||||
recurring-job.longhorn.io/source: "enabled"
|
||||
recurring-job.longhorn.io/backup: "enabled"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 512Mi
|
||||
storageClassName: longhorn
|
||||
69
media/service.yaml
Normal file
69
media/service.yaml
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: server
|
||||
namespace: media
|
||||
spec:
|
||||
selector:
|
||||
app: server
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 8096
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: sonarr
|
||||
namespace: media
|
||||
spec:
|
||||
selector:
|
||||
app: sonarr
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 8989
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: qbittorrent
|
||||
namespace: media
|
||||
spec:
|
||||
selector:
|
||||
app: qbittorrent
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: prowlarr
|
||||
namespace: media
|
||||
spec:
|
||||
selector:
|
||||
app: prowlarr
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 9696
|
||||
type: ClusterIP
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: radarr
|
||||
namespace: media
|
||||
spec:
|
||||
selector:
|
||||
app: radarr
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 7878
|
||||
@@ -5,7 +5,6 @@ metadata:
|
||||
name: monifactory-data
|
||||
namespace: minecraft
|
||||
spec:
|
||||
storageClassName: longhorn-crypto
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
@@ -18,7 +17,6 @@ metadata:
|
||||
name: gtnh-data
|
||||
namespace: minecraft
|
||||
spec:
|
||||
storageClassName: longhorn-crypto
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
@@ -31,7 +29,21 @@ metadata:
|
||||
name: tfg-data
|
||||
namespace: minecraft
|
||||
spec:
|
||||
storageClassName: longhorn-crypto
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: atm10-data
|
||||
namespace: minecraft
|
||||
labels:
|
||||
recurring-job.longhorn.io/source: "enabled"
|
||||
recurring-job.longhorn.io/backup: "enabled"
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
|
||||
@@ -43,3 +43,18 @@ spec:
|
||||
port: 25565
|
||||
selector:
|
||||
app: tfg-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: atm10-server
|
||||
namespace: minecraft
|
||||
labels:
|
||||
app: atm10-server
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- name: atm10
|
||||
port: 25565
|
||||
selector:
|
||||
app: atm10-server
|
||||
|
||||
@@ -5,6 +5,7 @@ metadata:
|
||||
name: monifactory-server
|
||||
namespace: minecraft
|
||||
spec:
|
||||
serviceName: monifactory-server
|
||||
selector:
|
||||
matchLabels:
|
||||
app: monifactory-server
|
||||
@@ -13,6 +14,8 @@ spec:
|
||||
labels:
|
||||
app: monifactory-server
|
||||
spec:
|
||||
nodeSelector:
|
||||
nodepool: worker
|
||||
containers:
|
||||
- name: monifactory-server
|
||||
image: itzg/minecraft-server:java17
|
||||
@@ -37,7 +40,7 @@ spec:
|
||||
- name: INIT_MEMORY
|
||||
value: 4G
|
||||
- name: MAX_MEMORY
|
||||
value: 8G
|
||||
value: 12G
|
||||
- name: ALLOW_FLIGHT
|
||||
value: "TRUE"
|
||||
- name: ENABLE_ROLLING_LOGS
|
||||
@@ -53,7 +56,7 @@ spec:
|
||||
memory: "4Gi"
|
||||
limits:
|
||||
cpu: 8
|
||||
memory: "8Gi"
|
||||
memory: "12Gi"
|
||||
volumeMounts:
|
||||
- name: monifactory-data
|
||||
mountPath: /data
|
||||
@@ -68,6 +71,7 @@ metadata:
|
||||
name: gtnh-server
|
||||
namespace: minecraft
|
||||
spec:
|
||||
serviceName: gtnh-server
|
||||
selector:
|
||||
matchLabels:
|
||||
app: gtnh-server
|
||||
@@ -76,6 +80,8 @@ spec:
|
||||
labels:
|
||||
app: gtnh-server
|
||||
spec:
|
||||
nodeSelector:
|
||||
nodepool: worker
|
||||
containers:
|
||||
- name: gtnh-server
|
||||
image: itzg/minecraft-server:java25
|
||||
@@ -97,7 +103,7 @@ spec:
|
||||
- name: SKIP_GENERIC_PACK_UPDATE_CHECK
|
||||
value: "true"
|
||||
- name: MEMORY
|
||||
value: 6G
|
||||
value: 12G
|
||||
- name: JVM_OPTS
|
||||
value: "-Dfml.readTimeout=180 -Dfml.queryResult=confirm @java9args.txt"
|
||||
- name: CUSTOM_JAR_EXEC
|
||||
@@ -112,7 +118,7 @@ spec:
|
||||
resources:
|
||||
limits:
|
||||
cpu: 8
|
||||
memory: "8Gi"
|
||||
memory: "12Gi"
|
||||
volumeMounts:
|
||||
- name: gtnh-data
|
||||
mountPath: /data
|
||||
@@ -127,6 +133,7 @@ metadata:
|
||||
name: tfg-server
|
||||
namespace: minecraft
|
||||
spec:
|
||||
serviceName: tfg-server
|
||||
selector:
|
||||
matchLabels:
|
||||
app: tfg-server
|
||||
@@ -135,6 +142,8 @@ spec:
|
||||
labels:
|
||||
app: tfg-server
|
||||
spec:
|
||||
nodeSelector:
|
||||
nodepool: worker
|
||||
containers:
|
||||
- name: tfg-server
|
||||
image: itzg/minecraft-server:java17
|
||||
@@ -159,7 +168,7 @@ spec:
|
||||
- name: INIT_MEMORY
|
||||
value: 2G
|
||||
- name: MAX_MEMORY
|
||||
value: 8G
|
||||
value: 12G
|
||||
- name: ALLOW_FLIGHT
|
||||
value: "TRUE"
|
||||
- name: ENABLE_ROLLING_LOGS
|
||||
@@ -175,7 +184,7 @@ spec:
|
||||
memory: "2Gi"
|
||||
limits:
|
||||
cpu: 6
|
||||
memory: "9Gi"
|
||||
memory: "12Gi"
|
||||
volumeMounts:
|
||||
- name: tfg-data
|
||||
mountPath: /data
|
||||
@@ -183,3 +192,71 @@ spec:
|
||||
- name: tfg-data
|
||||
persistentVolumeClaim:
|
||||
claimName: tfg-data
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: atm10-server
|
||||
namespace: minecraft
|
||||
spec:
|
||||
serviceName: atm10-server
|
||||
selector:
|
||||
matchLabels:
|
||||
app: atm10-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: atm10-server
|
||||
spec:
|
||||
nodeSelector:
|
||||
nodepool: worker
|
||||
containers:
|
||||
- name: atm10-server
|
||||
image: itzg/minecraft-server:java21
|
||||
env:
|
||||
- name: EULA
|
||||
value: "TRUE"
|
||||
- name: MODE
|
||||
value: "survival"
|
||||
- name: MODPACK_PLATFORM
|
||||
value: "AUTO_CURSEFORGE"
|
||||
- name: CF_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: curseforge
|
||||
key: credential
|
||||
- name: CF_PAGE_URL
|
||||
value: "https://www.curseforge.com/minecraft/modpacks/all-the-mods-10/files/7121777"
|
||||
- name: VERSION
|
||||
value: "1.21.1"
|
||||
- name: INIT_MEMORY
|
||||
value: 2G
|
||||
- name: MAX_MEMORY
|
||||
value: 15G
|
||||
- name: ALLOW_FLIGHT
|
||||
value: "TRUE"
|
||||
- name: ENABLE_ROLLING_LOGS
|
||||
value: "TRUE"
|
||||
- name: USE_MEOWICE_FLAGS
|
||||
value: "TRUE"
|
||||
- name: CF_OVERRIDES_EXCLUSIONS
|
||||
value: |
|
||||
# Not applicable for server side
|
||||
shaderpacks/**
|
||||
ports:
|
||||
- name: minecraft
|
||||
containerPort: 25565
|
||||
resources:
|
||||
requests:
|
||||
cpu: 2
|
||||
memory: "2Gi"
|
||||
limits:
|
||||
cpu: 6
|
||||
memory: "16Gi"
|
||||
volumeMounts:
|
||||
- name: atm10-data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: atm10-data
|
||||
persistentVolumeClaim:
|
||||
claimName: atm10-data
|
||||
|
||||
@@ -3,6 +3,8 @@ import { HelmProvider } from "@cdktf/provider-helm/lib/provider";
|
||||
import { Release } from "@cdktf/provider-helm/lib/release";
|
||||
import { Construct } from "constructs";
|
||||
|
||||
import { NixCache } from "./nix-cache";
|
||||
|
||||
type NginxOptions = {
|
||||
provider: HelmProvider;
|
||||
name: string;
|
||||
@@ -24,5 +26,11 @@ export class Nginx extends Construct {
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
new NixCache(this, "nix-cache", {
|
||||
namespace: options.namespace,
|
||||
host: "nix.dogar.dev",
|
||||
ingressClassName: "nginx-internal",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
105
nginx/nix-cache.ts
Normal file
105
nginx/nix-cache.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { Construct } from "constructs";
|
||||
import { ServiceV1 } from "@cdktf/provider-kubernetes/lib/service-v1";
|
||||
import { IngressV1 } from "@cdktf/provider-kubernetes/lib/ingress-v1";
|
||||
import { PersistentVolumeClaimV1 } from "@cdktf/provider-kubernetes/lib/persistent-volume-claim-v1";
|
||||
|
||||
export interface NixCacheProps {
|
||||
namespace: string;
|
||||
host: string;
|
||||
ingressClassName?: string;
|
||||
externalName?: string;
|
||||
}
|
||||
|
||||
export class NixCache extends Construct {
|
||||
constructor(scope: Construct, id: string, props: NixCacheProps) {
|
||||
super(scope, id);
|
||||
|
||||
const {
|
||||
namespace,
|
||||
host,
|
||||
ingressClassName: ingressClass = "nginx-internal",
|
||||
externalName: upstreamHost = "cache.nixos.org",
|
||||
} = props;
|
||||
|
||||
// 1) ExternalName Service -> cache.nixos.org
|
||||
new ServiceV1(this, "nixcache-upstream-svc", {
|
||||
metadata: {
|
||||
name: "nixcache-upstream",
|
||||
namespace,
|
||||
},
|
||||
spec: {
|
||||
type: "ExternalName",
|
||||
externalName: upstreamHost,
|
||||
},
|
||||
});
|
||||
|
||||
// 2) Ingress that targets the ExternalName Service over HTTPS:443
|
||||
new IngressV1(this, "nixcache-ingress", {
|
||||
metadata: {
|
||||
name: "nix-cache",
|
||||
namespace,
|
||||
annotations: {
|
||||
// Use the cache zone defined in controller.config.http-snippet
|
||||
"nginx.ingress.kubernetes.io/proxy-cache": "cachecache",
|
||||
"nginx.ingress.kubernetes.io/proxy-cache-valid": "200 302 60d",
|
||||
"nginx.ingress.kubernetes.io/proxy-cache-lock": "true",
|
||||
"nginx.ingress.kubernetes.io/proxy-buffering": "on",
|
||||
|
||||
// Upstream is HTTPS with SNI and a fixed Host header
|
||||
"nginx.ingress.kubernetes.io/backend-protocol": "HTTPS",
|
||||
"nginx.ingress.kubernetes.io/proxy-ssl-server-name": "true",
|
||||
"nginx.ingress.kubernetes.io/upstream-vhost": upstreamHost,
|
||||
|
||||
// Use cert-manager to provision TLS certs via Cloudflare
|
||||
"cert-manager.io/cluster-issuer": "cloudflare-issuer",
|
||||
"cert-manager.io/acme-challenge-type": "dns01",
|
||||
"cert-manager.io/private-key-size": "4096",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
ingressClassName: ingressClass,
|
||||
rule: [
|
||||
{
|
||||
host,
|
||||
http: {
|
||||
path: [
|
||||
{
|
||||
path: "/",
|
||||
pathType: "Prefix",
|
||||
backend: {
|
||||
service: {
|
||||
name: "nixcache-upstream",
|
||||
port: { number: 443 },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
tls: [
|
||||
{
|
||||
hosts: [host],
|
||||
secretName: "nix-cache-tls",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// 3) PersistentVolumeClaim for caching
|
||||
new PersistentVolumeClaimV1(this, "nix-cache-pvc", {
|
||||
metadata: {
|
||||
name: "nix-cache",
|
||||
namespace,
|
||||
},
|
||||
spec: {
|
||||
accessModes: ["ReadWriteMany"],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: "128Gi",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page, on
|
||||
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
|
||||
|
||||
{ pkgs, meta, ... }:
|
||||
|
||||
{
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
require-sigs = false;
|
||||
experimental-features = [ "nix-command" "flakes" ];
|
||||
};
|
||||
};
|
||||
|
||||
# Use the systemd-boot EFI boot loader.
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
networking.hostName = meta.hostname; # Define your hostname.
|
||||
# Pick only one of the below networking options.
|
||||
networking.networkmanager.enable = true;
|
||||
networking.interfaces.enp1s0.ipv4.addresses = [
|
||||
{
|
||||
address = (
|
||||
if meta.hostname == "homelab-0" then "192.168.18.10"
|
||||
else if meta.hostname == "homelab-1" then "192.168.18.11"
|
||||
else if meta.hostname == "homelab-2" then "192.168.18.12"
|
||||
else throw "Unknown hostname"
|
||||
);
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
networking.defaultGateway = "192.168.18.1";
|
||||
networking.nameservers = [
|
||||
"192.168.18.250"
|
||||
"1.1.1.1"
|
||||
];
|
||||
|
||||
# Set your time zone.
|
||||
time.timeZone = "Asia/Karachi";
|
||||
|
||||
# Select internationalisation properties.
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
console = {
|
||||
font = "Lat2-Terminus16";
|
||||
keyMap = "us";
|
||||
};
|
||||
|
||||
# Fixes for longhorn
|
||||
systemd.tmpfiles.rules = [
|
||||
"L+ /usr/local/bin - - - - /run/current-system/sw/bin/"
|
||||
];
|
||||
virtualisation.docker.logDriver = "json-file";
|
||||
|
||||
services.k3s = {
|
||||
enable = true;
|
||||
role = "server";
|
||||
tokenFile = /var/lib/rancher/k3s/server/token;
|
||||
extraFlags = toString ([
|
||||
"--write-kubeconfig-mode \"0644\""
|
||||
"--cluster-init"
|
||||
"--disable servicelb"
|
||||
"--disable traefik"
|
||||
"--disable local-storage"
|
||||
] ++ (if meta.hostname == "homelab-0" then [] else [
|
||||
"--server https://192.168.18.10:6443"
|
||||
]));
|
||||
clusterInit = (meta.hostname == "homelab-0");
|
||||
};
|
||||
|
||||
services.openiscsi = {
|
||||
enable = true;
|
||||
name = "iqn.2016-04.com.open-iscsi:${meta.hostname}";
|
||||
};
|
||||
|
||||
# Define a user account. Don't forget to set a password with ‘passwd’.
|
||||
users.users.shahab = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
|
||||
packages = with pkgs; [
|
||||
tree
|
||||
cloudflared
|
||||
];
|
||||
# Created using mkpasswd
|
||||
hashedPassword = "$6$.ZlYnf2cZph4tCbM$E/JJUDirRV8MZrgX4Rh.Pi1q95tev1ZxcKjPA1I.uURv56qoWcC39MJWO9S2T5MlkPVbSLGiM8Ihfz9mERImo/";
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGD/V4jLpuk7uAovkbHFr6uulfBKZmsH+BqmXIR2aYD0"
|
||||
];
|
||||
};
|
||||
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
users = ["shahab"];
|
||||
commands = [
|
||||
{ command = "ALL"; options = ["NOPASSWD"]; }
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
# List packages installed in system profile. To search, run:
|
||||
# $ nix search wget
|
||||
environment.systemPackages = with pkgs; [
|
||||
neovim
|
||||
k3s
|
||||
cifs-utils
|
||||
nfs-utils
|
||||
git
|
||||
];
|
||||
|
||||
# List services that you want to enable:
|
||||
|
||||
# Enable the OpenSSH daemon.
|
||||
services.openssh.enable = true;
|
||||
|
||||
# Open ports in the firewall.
|
||||
# networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
# networking.firewall.allowedUDPPorts = [ ... ];
|
||||
# Or disable the firewall altogether.
|
||||
networking.firewall.enable = false;
|
||||
|
||||
# Copy the NixOS configuration file and link it from the resulting system
|
||||
# (/run/current-system/configuration.nix). This is useful in case you
|
||||
# accidentally delete configuration.nix.
|
||||
# system.copySystemConfiguration = true;
|
||||
|
||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||
#
|
||||
# Most users should NEVER change this value after the initial install, for any reason,
|
||||
# even if you've upgraded your system to a new NixOS release.
|
||||
#
|
||||
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
|
||||
# so changing it will NOT upgrade your system.
|
||||
#
|
||||
# This value being lower than the current NixOS release does NOT mean your system is
|
||||
# out of date, out of support, or vulnerable.
|
||||
#
|
||||
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
|
||||
# and migrated your data accordingly.
|
||||
#
|
||||
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
|
||||
system.stateVersion = "24.05"; # Did you read the comment?
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
vdb = {
|
||||
type = "disk";
|
||||
device = "/dev/nvme0n1";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
ESP = {
|
||||
priority = 1;
|
||||
name = "ESP";
|
||||
start = "1M";
|
||||
end = "128M";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
luks = {
|
||||
size = "100%";
|
||||
content = {
|
||||
name = "crypted";
|
||||
type = "luks";
|
||||
passwordFile = "/tmp/secret.key";
|
||||
settings = {
|
||||
allowDiscards = true;
|
||||
crypttabExtraOpts =
|
||||
[ "fido2-device=auto" "token-timeout=10" ];
|
||||
};
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
48
nixos/master/flake.lock
generated
48
nixos/master/flake.lock
generated
@@ -1,48 +0,0 @@
|
||||
{
|
||||
"nodes": {
|
||||
"disko": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1758287904,
|
||||
"narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "disko",
|
||||
"rev": "67ff9807dd148e704baadbd4fd783b54282ca627",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "disko",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1759994382,
|
||||
"narHash": "sha256-wSK+3UkalDZRVHGCRikZ//CyZUJWDJkBDTQX1+G77Ow=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5da4a26309e796daa7ffca72df93dbe53b8164c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"disko": "disko",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
description = "Homelab NixOS Flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||
# Disko
|
||||
disko = {
|
||||
url = "github:nix-community/disko";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, disko, ... }: let
|
||||
nodes = [
|
||||
"homelab-0"
|
||||
"homelab-1"
|
||||
"homelab-2"
|
||||
];
|
||||
in {
|
||||
nixosConfigurations = builtins.listToAttrs (map (name: {
|
||||
name = name;
|
||||
value = nixpkgs.lib.nixosSystem {
|
||||
specialArgs = {
|
||||
meta = { hostname = name; };
|
||||
};
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
# Modules
|
||||
disko.nixosModules.disko
|
||||
./hardware-configuration.nix
|
||||
./disko-config.nix
|
||||
./configuration.nix
|
||||
];
|
||||
};
|
||||
}) nodes);
|
||||
};
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [(modulesPath + "/installer/scan/not-detected.nix")];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault false;
|
||||
networking.interfaces.enp1s0.useDHCP = lib.mkDefault false;
|
||||
# networking.interfaces.wlo1.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
54
package-lock.json
generated
54
package-lock.json
generated
@@ -75,9 +75,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -121,13 +121,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz",
|
||||
"integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
|
||||
"version": "24.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
|
||||
"integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.8.0"
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
@@ -173,6 +174,7 @@
|
||||
"semver"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"archiver": "7.0.1",
|
||||
"json-stable-stringify": "1.2.1",
|
||||
@@ -1250,7 +1252,8 @@
|
||||
"version": "10.4.2",
|
||||
"resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.2.tgz",
|
||||
"integrity": "sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA==",
|
||||
"license": "Apache-2.0"
|
||||
"license": "Apache-2.0",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
@@ -1270,9 +1273,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.5.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz",
|
||||
"integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==",
|
||||
"version": "16.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -1282,15 +1285,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/envalid": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/envalid/-/envalid-8.0.0.tgz",
|
||||
"integrity": "sha512-PGeYJnJB5naN0ME6SH8nFcDj9HVbLpYIfg1p5lAyM9T4cH2lwtu2fLbozC/bq+HUUOIFxhX/LP0/GmlqPHT4tQ==",
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/envalid/-/envalid-8.1.0.tgz",
|
||||
"integrity": "sha512-OT6+qVhKVyCidaGoXflb2iK1tC8pd0OV2Q+v9n33wNhUJ+lus+rJobUj4vJaQBPxPZ0vYrPGuxdrenyCAIJcow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "2.6.2"
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
@@ -1345,17 +1348,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
|
||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -1365,9 +1369,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
|
||||
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
||||
@@ -11,7 +11,6 @@ type PostgresClusterOptions = {
|
||||
};
|
||||
name: string;
|
||||
namespace: string;
|
||||
storageClass: string;
|
||||
users: string[];
|
||||
primaryUser: string;
|
||||
initSecretName: string;
|
||||
@@ -31,11 +30,13 @@ export class PostgresCluster extends Construct {
|
||||
chart: "cloudnative-pg",
|
||||
name: "postgres-system",
|
||||
namespace: "cnpg-system",
|
||||
createNamespace: true,
|
||||
});
|
||||
|
||||
const destinationPath = "s3://homelab/";
|
||||
const destinationPath = "s3://postgres-backups/";
|
||||
const endpointURL = options.backupR2EndpointURL;
|
||||
const barmanStoreName = "r2-postgres-backup-store";
|
||||
const backupServerName = `${options.name}-backup`;
|
||||
|
||||
const barmanConfiguration = {
|
||||
destinationPath,
|
||||
@@ -49,6 +50,16 @@ export class PostgresCluster extends Construct {
|
||||
name: "cloudflare-token",
|
||||
key: "secret_access_key",
|
||||
},
|
||||
region: {
|
||||
name: "cloudflare-token",
|
||||
key: "AWS_REGION",
|
||||
},
|
||||
},
|
||||
wal: {
|
||||
compression: "gzip",
|
||||
},
|
||||
data: {
|
||||
compression: "gzip",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -62,11 +73,9 @@ export class PostgresCluster extends Construct {
|
||||
name: barmanStoreName,
|
||||
},
|
||||
spec: {
|
||||
retentionPolicy: "15d",
|
||||
configuration: {
|
||||
...barmanConfiguration,
|
||||
wal: {
|
||||
compression: "gzip",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -147,22 +156,6 @@ export class PostgresCluster extends Construct {
|
||||
},
|
||||
});
|
||||
|
||||
// Secret for server certificate
|
||||
new Manifest(this, "server-ca-cert-secret", {
|
||||
provider: kubernetes,
|
||||
manifest: {
|
||||
apiVersion: "v1",
|
||||
kind: "Secret",
|
||||
metadata: {
|
||||
name: certNames.server,
|
||||
namespace: options.namespace,
|
||||
labels: {
|
||||
"cnpg.io/reload": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Server certificate
|
||||
new Manifest(this, "server-cert", {
|
||||
provider: kubernetes,
|
||||
@@ -332,7 +325,7 @@ export class PostgresCluster extends Construct {
|
||||
postgresql: {
|
||||
parameters: {
|
||||
archive_mode: "on",
|
||||
archive_timeout: "5min",
|
||||
archive_timeout: "60min",
|
||||
checkpoint_timeout: "10min",
|
||||
checkpoint_completion_target: "0.7",
|
||||
dynamic_shared_memory_type: "posix",
|
||||
@@ -346,16 +339,17 @@ export class PostgresCluster extends Construct {
|
||||
logging_collector: "on",
|
||||
max_parallel_workers: "32",
|
||||
max_replication_slots: "32",
|
||||
max_wal_size: "768MB",
|
||||
max_worker_processes: "32",
|
||||
max_slot_wal_keep_size: "256MB",
|
||||
max_wal_size: "512MB",
|
||||
min_wal_size: "128MB",
|
||||
shared_memory_type: "mmap",
|
||||
shared_preload_libraries: "",
|
||||
ssl_max_protocol_version: "TLSv1.3",
|
||||
ssl_min_protocol_version: "TLSv1.3",
|
||||
wal_compression: "on",
|
||||
wal_keep_size: "128MB",
|
||||
wal_level: "logical",
|
||||
wal_level: "replica",
|
||||
wal_log_hints: "on",
|
||||
wal_receiver_timeout: "5s",
|
||||
wal_sender_timeout: "5s",
|
||||
@@ -368,31 +362,16 @@ export class PostgresCluster extends Construct {
|
||||
plugins: [
|
||||
{
|
||||
name: "barman-cloud.cloudnative-pg.io",
|
||||
enabled: true,
|
||||
isWALArchiver: true,
|
||||
parameters: {
|
||||
barmanObjectName: barmanStoreName,
|
||||
serverName: backupServerName,
|
||||
},
|
||||
},
|
||||
],
|
||||
enableSuperuserAccess: true,
|
||||
// bootstrap: {
|
||||
// recovery: {
|
||||
// source: "clusterBackup",
|
||||
// database: "postgres",
|
||||
// owner: options.primaryUser,
|
||||
// secret: {
|
||||
// name: options.initSecretName,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
bootstrap: {
|
||||
initdb: {
|
||||
database: "postgres",
|
||||
secret: {
|
||||
name: options.initSecretName,
|
||||
},
|
||||
postInitSQL: [`CREATE USER ${options.primaryUser} SUPERUSER;`],
|
||||
recovery: {
|
||||
source: "clusterBackup",
|
||||
},
|
||||
},
|
||||
externalClusters: [
|
||||
@@ -402,7 +381,8 @@ export class PostgresCluster extends Construct {
|
||||
name: "barman-cloud.cloudnative-pg.io",
|
||||
parameters: {
|
||||
barmanObjectName: barmanStoreName,
|
||||
serverName: "postgres-cluster",
|
||||
serverName: backupServerName,
|
||||
skipWalArchiveCheck: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -416,6 +396,7 @@ export class PostgresCluster extends Construct {
|
||||
serviceTemplate: {
|
||||
metadata: {
|
||||
name: "postgres-cluster",
|
||||
superuser: true,
|
||||
annotations: {
|
||||
"external-dns.alpha.kubernetes.io/hostname":
|
||||
"postgres.dogar.dev",
|
||||
@@ -428,14 +409,26 @@ export class PostgresCluster extends Construct {
|
||||
},
|
||||
],
|
||||
},
|
||||
roles: [
|
||||
{
|
||||
name: options.primaryUser,
|
||||
inRoles: ["postgres"],
|
||||
inherit: true,
|
||||
disablePassword: true,
|
||||
createdb: true,
|
||||
createrole: true,
|
||||
login: true,
|
||||
ensure: "present",
|
||||
},
|
||||
],
|
||||
},
|
||||
storage: {
|
||||
size: "10Gi",
|
||||
storageClass: options.storageClass,
|
||||
storageClass: "longhorn",
|
||||
},
|
||||
walStorage: {
|
||||
size: "1Gi",
|
||||
storageClass: options.storageClass,
|
||||
size: "2Gi",
|
||||
storageClass: "longhorn",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -451,8 +444,18 @@ export class PostgresCluster extends Construct {
|
||||
namespace: options.namespace,
|
||||
},
|
||||
spec: {
|
||||
schedule: "0 0 0 * * *", // daily at midnight
|
||||
immediate: true,
|
||||
// weekly midnight on Sunday
|
||||
schedule: "* 0 0 * * 0",
|
||||
backupOwnerReference: "self",
|
||||
method: "plugin",
|
||||
pluginConfiguration: {
|
||||
name: "barman-cloud.cloudnative-pg.io",
|
||||
parameters: {
|
||||
barmanObjectName: barmanStoreName,
|
||||
serverName: backupServerName,
|
||||
},
|
||||
},
|
||||
cluster: {
|
||||
name: options.name,
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ export class ValkeyCluster extends Construct {
|
||||
const labels = { app: "valkey" };
|
||||
const { provider, name, namespace } = options;
|
||||
|
||||
new DeploymentV1(this, "valkeyDeployment", {
|
||||
new DeploymentV1(this, "valkey-deployment", {
|
||||
provider,
|
||||
metadata: {
|
||||
name,
|
||||
@@ -93,7 +93,7 @@ export class ValkeyCluster extends Construct {
|
||||
},
|
||||
});
|
||||
|
||||
new ServiceV1(this, "valkeyService", {
|
||||
new ServiceV1(this, "valkey-service", {
|
||||
provider,
|
||||
metadata: {
|
||||
name,
|
||||
|
||||
Reference in New Issue
Block a user