Compare commits

3 Commits

Author SHA1 Message Date
marcio.fernandes 064baa08a4 Update README.md
/ deploy-to-homesrv01 (push) Successful in 8s
2025-07-27 15:45:14 +00:00
marcio.fernandes a0ff8a03b5 Update README.md
/ deploy-to-homesrv01 (push) Successful in 6s
2025-07-27 15:29:47 +00:00
marcio.fernandes 6030e44a99 Update README.md
/ deploy-to-homesrv01 (push) Successful in 8s
2025-07-27 15:28:49 +00:00
147 changed files with 1036 additions and 7923 deletions
+109
View File
@@ -0,0 +1,109 @@
# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH
# Path to your Oh My Zsh installation.
export ZSH="$HOME/.oh-my-zsh"
# Set name of the theme to load --- if set to "random", it will
# load a random theme each time Oh My Zsh is loaded, in which case,
# to know which specific one was loaded, run: echo $RANDOM_THEME
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
ZSH_THEME="gnzh"
# Set list of themes to pick from when loading at random
# Setting this variable when ZSH_THEME="devcontainers"
# a theme from this variable instead of looking in $ZSH/themes/
# If set to an empty array, this variable will have no effect.
# ZSH_THEME_RANDOM_CANDIDATES=( "robbyrussell" "agnoster" )
# Uncomment the following line to use case-sensitive completion.
# CASE_SENSITIVE="true"
# Uncomment the following line to use hyphen-insensitive completion.
# Case-sensitive completion must be off. _ and - will be interchangeable.
# HYPHEN_INSENSITIVE="true"
# Uncomment one of the following lines to change the auto-update behavior
# zstyle ':omz:update' mode disabled # disable automatic updates
# zstyle ':omz:update' mode auto # update automatically without asking
# zstyle ':omz:update' mode reminder # just remind me to update when it's time
# Uncomment the following line to change how often to auto-update (in days).
# zstyle ':omz:update' frequency 13
# Uncomment the following line if pasting URLs and other text is messed up.
# DISABLE_MAGIC_FUNCTIONS="true"
# Uncomment the following line to disable colors in ls.
# DISABLE_LS_COLORS="true"
# Uncomment the following line to disable auto-setting terminal title.
# DISABLE_AUTO_TITLE="true"
# Uncomment the following line to enable command auto-correction.
# ENABLE_CORRECTION="true"
# Uncomment the following line to display red dots whilst waiting for completion.
# You can also set it to another string to have that shown instead of the default red dots.
# e.g. COMPLETION_WAITING_DOTS="%F{yellow}waiting...%f"
# Caution: this setting can cause issues with multiline prompts in zsh < 5.7.1 (see #5765)
# COMPLETION_WAITING_DOTS="true"
# Uncomment the following line if you want to disable marking untracked files
# under VCS as dirty. This makes repository status check for large repositories
# much, much faster.
# DISABLE_UNTRACKED_FILES_DIRTY="true"
# Uncomment the following line if you want to change the command execution time
# stamp shown in the history command output.
# You can set one of the optional three formats:
# "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd"
# or set a custom format using the strftime function format specifications,
# see 'man strftime' for details.
# HIST_STAMPS="mm/dd/yyyy"
# Would you like to use another custom folder than $ZSH/custom?
# ZSH_CUSTOM=/path/to/new-custom-folder
# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(git timer web-search ssh kubectl helm colorize zsh-autosuggestions rclone ansible)
ZSH_COLORIZE_TOOL=chroma
source $ZSH/oh-my-zsh.sh
# User configuration
# export MANPATH="/usr/local/man:$MANPATH"
# You may need to manually set your language environment
# export LANG=en_US.UTF-8
# Preferred editor for local and remote sessions
# if [[ -n $SSH_CONNECTION ]]; then
# export EDITOR='vim'
# else
# export EDITOR='nvim'
# fi
# Compilation flags
# export ARCHFLAGS="-arch $(uname -m)"
# Set personal aliases, overriding those provided by Oh My Zsh libs,
# plugins, and themes. Aliases can be placed here, though Oh My Zsh
# users are encouraged to define aliases within a top-level file in
# the $ZSH_CUSTOM folder, with .zsh extension. Examples:
# - $ZSH_CUSTOM/aliases.zsh
# - $ZSH_CUSTOM/macos.zsh
# For a full list of active aliases, run `alias`.
#
# Example aliases
# alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh"
DISABLE_AUTO_UPDATE=true
DISABLE_UPDATE_PROMPT=true
export PATH=$PATH:/home/vscode/lib
+23 -13
View File
@@ -1,20 +1,32 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
{ {
"name": "casa-dev", "name": "casa-dev",
"image": "oci.limbosolutions.com/public/devcontainers/devops:latest", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"remoteUser": "vscode", "image": "mcr.microsoft.com/devcontainers/base:jammy",
"runArgs": [ "features": {
"--hostname=casa-dev" "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {},
], "ghcr.io/devcontainers-extra/features/ansible": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker": {},
},
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Configure tool-specific properties.
// "customizations": {},
"mounts": [ "mounts": [
"source=${localWorkspaceFolder}/.devcontainer/.zshrc,target=/home/vscode/.zshrc,type=bind",
"source=${localWorkspaceFolder}/../lms,target=/workspaces/lms,type=bind", "source=${localWorkspaceFolder}/../lms,target=/workspaces/lms,type=bind",
"source=${localWorkspaceFolder}/../homeAssistant,target=/workspaces/homeAssistant,type=bind", "source=${localWorkspaceFolder}/../homeAssistant,target=/workspaces/homeAssistant,type=bind",
"source=${localWorkspaceFolder}/../mosquitto,target=/workspaces/mosquitto,type=bind", "source=${localWorkspaceFolder}/../mosquitto,target=/workspaces/mosquitto,type=bind",
"source=${localWorkspaceFolder}/../kb,target=/workspaces/kb,type=bind", "source=${localWorkspaceFolder}/../kb,target=/workspaces/kb,type=bind",
"source=${localWorkspaceFolder}/../pi.bluetooth.speaker,target=/workspaces/pi.bluetooth.speaker,type=bind",
"source=${localWorkspaceFolder}/.env.d/kube,target=/home/vscode/.kube,type=bind", "source=${localWorkspaceFolder}/.env.d/kube,target=/home/vscode/.kube,type=bind",
"source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached", "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached",
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached" "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
], ],
"postCreateCommand": "bash .devcontainer/scripts/postCreate.sh",
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": [ "extensions": [
@@ -25,13 +37,11 @@
"yzhang.markdown-all-in-one", "yzhang.markdown-all-in-one",
"davidanson.vscode-markdownlint", "davidanson.vscode-markdownlint",
"eamodio.gitlens", "eamodio.gitlens",
"m4ns0ur.base64", "m4ns0ur.base64"
"rogalmic.bash-debug", ],
"streetsidesoftware.code-spell-checker", "settings": {
"ms-azuretools.vscode-containers", "terminal.integrated.defaultProfile.linux": "zsh"
"sanjulaganepola.github-local-actions", }
"eamodio.gitlens"
]
} }
} }
} }
+7
View File
@@ -0,0 +1,7 @@
#setup chroma for zsh colorize
chmod +x /home/vscode/lib/chroma
curl https://rclone.org/install.sh | sudo bash
docker context create casa-prod --description "casa prod context" --docker host=ssh://admin@homesrv01.dev.lan
docker context use casa-prod
@@ -0,0 +1,21 @@
on:
push:
schedule:
- cron: '0 16 * * *' # Every day at 16:00
jobs:
deploy-to-homesrv01:
runs-on: "myLimbo-casa-gitea-act-runner"
steps:
- name: Checkout code
uses: actions/checkout@v2
# all certs and key are base64 encoded
- name: docker compose up
env:
KUBERNETES_SERVER: ${{ secrets.KUBERNETES_SERVER }}
KUBERNETES_CLIENT_CRT_DATA: ${{ secrets.KUBERNETES_CLIENT_CRT_DATA }}
KUBERNETES_CLIENT_KEY_DATA: ${{ secrets.KUBERNETES_CLIENT_KEY_DATA }}
KUBERNETES_CRT_AUTHORITY_DATA: ${{ secrets.KUBERNETES_CRT_AUTHORITY_DATA }}
run: |
docker compose -f ./casa-limbosolutions-com/sync-certs-job/docker-compose.yaml up -d --pull always
+13
View File
@@ -0,0 +1,13 @@
on:
push:
schedule:
- cron: '0 5 * * SUN' # Every Sunday at 05:00
jobs:
deploy-to-homesrv01:
runs-on: "myLimbo-casa-gitea-act-runner"
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: docker compose up
run: docker compose -f ./services/wyoming/docker-compose.yaml up -d --pull always
-3
View File
@@ -11,6 +11,3 @@ gitignore/*
.secrets .secrets
ansible/inventory.yml ansible/inventory.yml
.env.d/* .env.d/*
.tmp/**
storage-limbosolutions-com/deploy/helm/values.private.yaml
**.dec.**
+7
View File
@@ -0,0 +1,7 @@
{
"folders": [
{
"path": "../../homeAssistant"
}
]
}
+176 -43
View File
@@ -1,38 +1,89 @@
# casa # casa
Welcome to my casa repository, where Home Assistant and other services are hosted. Welcome to my home server repository, where Home Assistant and other services are hosted.
This repository is dedicated to documenting and maintaining the server configuration and workflows. This repository is dedicated to documenting and maintaining the server configuration and workflows.
The primary goal is to establish an k3s cluster capable of isolating services and communications related to home automation at the network level. The primary goal is to establish a Docker-based server capable of isolating services and communications related to home automation at the network level.
The server operates within its own VLAN (`casa`) but requires controlled communication with other VLANs, such as `IOT Vlan` The server operates within its own VLAN (`homesrv`) but requires controlled communication with other VLANs, such as `IOT Vlan`
For more information about k3s cluster/nodes setup check [readme](./docs/k3s-cluster.md). <!-- omit in toc -->
## Table of Contents
**Table of Contents:**
- [Services](#services)
- [myInfra stack](#myinfra-stack)
- [docker](#docker)
- [rclone plugin](#rclone-plugin)
- [nginx](#nginx)
- [Home Assistant](#home-assistant) - [Home Assistant](#home-assistant)
- [Lyrion Music Server (LMS)](#lyrion-music-server-lms) - [Lyrion Music Server (LMS)](#lyrion-music-server-lms)
- [Mosquitto](#mosquitto) - [Mosquitto](#mosquitto)
- [Wyoming](#wyoming) - [Wyoming](#wyoming)
- [Zigbee2mqtt](#zigbee2mqtt) - [Zigbee2mqtt](#zigbee2mqtt)
- [node-red](#node-red) - [Host](#host)
- [core-dns](#core-dns) - [Proxmox - container](#proxmox---container)
- [OS](#os)
- [logs](#logs)
- [Development, Maintenance and Deployment](#development-maintenance-and-deployment)
- [Docker context](#docker-context)
## Home Assistant ## Services
### myInfra stack
docker, promtail and telegraf configuration [maintained on myInfra repo](/:root/marcio.fernandes/myInfrastructure).
### docker
#### rclone plugin
[https://rclone.org/docker/](https://rclone.org/docker/)
```bash
# execute on server
sudo apt-get -y install fuse
docker plugin install rclone/docker-volume-rclone:amd64 args="-v" --alias rclone --grant-all-permissions
docker plugin list
```
if error when enabling plugin.
*"rclone.sock: connect: no such file or directory"*
remove existing cache.
```bash
rm -r /var/lib/docker-plugins/rclone/cache
mkdir -p /var/lib/docker-plugins/rclone/cache
```
[ansible role for plugin configuration](./rclone.docker-plugin.playbook.yaml)
### nginx
[Docker Compose](./services/nginx/docker-compose.yaml)
All sites configurations set during docker build.
### Home Assistant
[Git Repo](/:root/marcio.fernandes/homeAssistant) [Git Repo](/:root/marcio.fernandes/homeAssistant)
## Lyrion Music Server (LMS) ### Lyrion Music Server (LMS)
For instructions on setting up the Lyrion Music Server on kubernetes, refer to the [LMS Git Repository](/:root/marcio.fernandes/lms). For instructions on setting up the Lyrion Music Server Docker container, refer to the [LMS Git Repository](/:root/marcio.fernandes/lms).
For information on integrating Lyrion Music Server with Home Assistant, visit the [Home Assistant Git Repository](/:root/marcio.fernandes/homeassistant#squeezebox-lyrion-music-server). For information on integrating Lyrion Music Server with Home Assistant, visit the [Home Assistant Git Repository](/:root/marcio.fernandes/homeassistant#squeezebox-lyrion-music-server).
## Mosquitto Using [Docker Rclone plugin](https://rclone.org/docker/) for accessing the bucket where music is stored. Configuration is managed via [Ansible playbook](./rclone.docker-plugin.playbook.yml).
```sh
#configure access to s3 bucket
ansible-playbook ./rclone.docker-plugin.playbook.yml
```
### Mosquitto
[Git Repo](/:root/marcio.fernandes/mosquitto) [Git Repo](/:root/marcio.fernandes/mosquitto)
## Wyoming ### Wyoming
A peer-to-peer protocol for voice assistants (basically JSONL + PCM audio) A peer-to-peer protocol for voice assistants (basically JSONL + PCM audio)
@@ -48,8 +99,11 @@ This is an open standard of the Open Home Foundation.
For more information about home assistant integration [check home assistant repo](/:root/marcio.fernandes/homeassistant#wyoming). For more information about home assistant integration [check home assistant repo](/:root/marcio.fernandes/homeassistant#wyoming).
Deployments and scripts on services/wyoming repo folder. [Docker compose file](./services/wyoming/docker-compose.yaml).
Continuous deploy [gitea action](.gitea/workflows/deploy-wyoming.yml).
Because of performance wyoming whisper is currently hosted on chimera kubernetes cluster [deployment](./services/wyoming/whisper.kubernetes-deployment.yaml)
Links: Links:
@@ -58,39 +112,118 @@ Links:
- [https://exitcode0.net/posts/wyoming-whisper-docker-compose/](https://exitcode0.net/posts/wyoming-whisper-docker-compose/) - [https://exitcode0.net/posts/wyoming-whisper-docker-compose/](https://exitcode0.net/posts/wyoming-whisper-docker-compose/)
- [https://exitcode0.net/posts/wyoming-piper-docker-compose/](https://exitcode0.net/posts/wyoming-piper-docker-compose/) - [https://exitcode0.net/posts/wyoming-piper-docker-compose/](https://exitcode0.net/posts/wyoming-piper-docker-compose/)
## Zigbee2mqtt ### Zigbee2mqtt
Zigbee to MQTT bridge, get rid of your proprietary Zigbee bridges Zigbee to MQTT bridge, get rid of your proprietary Zigbee bridges
Attached SONOFF Universal Zigbee 3.0 USB Dongle Plus to the Proxmox node and configure USB passthrough so the VM can use it. SONOFF Universal Zigbee 3.0 USB Dongle Plus attached on [proxmox host](#proxmox---lxc-container).
Deployments and scripts on services/Zigbee2mqtt repo folder. Patch security on [proxmox host](#proxmox---lxc-container).
(usb passthrough to [lxc container](#proxmox---lxc-container))
## node-red
check [readme](./services/node-red/README.md) for more information on setup and configuration.
## core-dns
Remove warning from logs.
```log
[WARNING] No files matching import glob pattern: /etc/coredns/custom/*.server
[WARNING] No files matching import glob pattern: /etc/coredns/custom/*.override
```
1. Apply on kubernetes
```yaml ```yaml
apiVersion: v1 #on proxmox hosting server
kind: ConfigMap chown 100000:100020 /dev/ttyUSB0
metadata: chown 100000:100020 /dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_c0e8eeb4b38ded118e7c06f6b86ce6f8-if00-port0
name: coredns-custom ```
namespace: kube-system
data: [docker compose](./services/zigbee2mqtt/docker-compose.yaml)
log.override: |
# Links
stub.server: |
# - [https://www.zigbee2mqtt.io/](https://www.zigbee2mqtt.io/)
- [Home assistant integration](/:root/marcio.fernandes/homeassistant#Zigbee2mqtt)
- [Continuos Deploy - git action](./.gitea/workflows/services.zigbee2mqtt.yml)
## Host
### Proxmox - container
Currently hosted on a proxmox ubuntu container.
```bash
# cat /etc/pve/lxc/105.conf
arch: amd64
cmode: shell
cores: 2
features: fuse=1,keyctl=1,nesting=1
hostname: homesrv01
memory: 1500
net0: name=eth0,bridge=vmbr0,firewall=1,ip6=dhcp,...,type=veth
onboot: 1
ostype: ubuntu
protection: 1
rootfs: local-lvm:vm-105-disk-0,size=32G
swap: 1500
unprivileged: 1
lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_c0e8eeb4b38ded118e7c06f6b86ce6f8-if00-port0 dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_c0e8eeb4b38ded118e7c06f6b86ce6f8-if00-port0 none bind,optional,create=file
lxc.cgroup2.devices.allow: c 188:* rwm
lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file
```
lxc.cgroup2.devices.allow and lxc.mount.entry identification
```bash
# identify usb pen
lsusb
# example
# Bus 001 Device 008: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
#replace with bus and device id
ls -l /dev/bus/usb/001/008
#example result
# crw-rw-r-- 1 root root 189, 7 May 17 15:56 /dev/bus/usb/001/008
# so
#lxc.cgroup2.devices.allow: c 189:* rwm
#lxc.mount.entry: usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_c0e8eeb4b38ded118e7c06f6b86ce6f8-if00-port0 dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_c0e8eeb4b38ded118e7c06f6b86ce6f8-if00-port0 none bind,optional,create=file
ls -l /dev/serial/by-id/
# example result
#lrwxrwxrwx 1 root root 13 May 17 15:56 usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_c0e8eeb4b38ded118e7c06f6b86ce6f8-if00-port0 -> ../../ttyUSB0
ls -l /dev/ttyUSB0
#example result
#crw-rw---- 1 root dialout 188, 0 May 17 15:56 /dev/ttyUSB0
#so
#lxc.cgroup2.devices.allow: c 188:* rwm
#lxc.mount.entry: /dev/ttyUSB0 dev/ttyUSB0 none bind,optional,create=file
```
### OS
```bash
# lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 24.04 LTS
Release: 24.04
Codename: noble
# uname -r
6.8.4-3-pve
```
### logs
```bash
# check auto update scripts logs
journalctl -r -t auto-update
```
## Development, Maintenance and Deployment
Using visual studio code, docker, ansible and gitea actions.
### Docker context
```bash
# create context to homesrv01 docker on development devices
docker context create homesrv01 --docker host=ssh://admin@homesrv01.dev.lan
``` ```
+2
View File
@@ -0,0 +1,2 @@
[defaults]
inventory = ansible/inventory.yml
-13
View File
@@ -1,13 +0,0 @@
# casa-limbosolutions-com
## sync cert
``` bash
kubectl annotate secret casa-limbosolutions-com-tls \
-n casa-limbosolutions-com \
replicator.v1.mittwald.de/replicate-to="home-assistant,node-red,lyrionmusicserver"
```
``` bash
kubectl kustomize deploy/flux | kubectl apply -f -
```
@@ -1,2 +0,0 @@
**
!.gitignore
@@ -1,11 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: casa
spec:
interval: 1m0s
url: ssh://git@git.limbosolutions.com:2222/myLimbo/casa.git
ref:
branch: main
secretRef:
name: flux-repo-ssh-credentials
@@ -1,18 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: casa-limbosolutions-com
resources:
- git-repo.yaml
secretGenerator:
- name: flux-repo-ssh-credentials
namespace: casa-limbosolutions-com
files:
- "identity=./.env.d/flux-repo-ssh-key"
- "known_hosts=./.env.d/flux-repo-ssh-known_hosts"
- "pubkey=./.env.d/flux-repo-ssh-key.pub"
- name: flux-sops-age
namespace: casa-limbosolutions-com
files:
- "age.agekey=./.env.d/age.agekey"
generatorOptions:
disableNameSuffixHash: true
+29
View File
@@ -0,0 +1,29 @@
# casa.limbosolutions.com at icarus
Use icarus cluster context to all documentation and scrips on this folder. [Check Instructions](#icarus-cluster---access) for how to setup required user and roles on icurus and client kubeconfig.
## certificates (wildcard)
```bash
kubectl apply -f ./certs.yaml
```
```bash
#check certificates
kubectl get cert -n casa-limbosolutions-com
```
## Icarus cluster - access
On user computer.
*Access to k3s context not required.*
```bash
# create private key
openssl genrsa -out ../../.env.d/kube/casa@icarus-user.key 2048
# create csr
openssl req -new -key ../../.env.d/kube/casa@icarus-user.key -out ../../.env.d/kube/casa@icarus-user.csr -subj "/CN=casa/O=limbosolutions"
```
Follow instructions to [setup user and roles on icarus k3s cluster](./k3s-admin.md), and setup kubectl config [kube config](./k3s-kubctl-config.md).
@@ -0,0 +1,95 @@
# casa on Icarus - admin
Requires kubernetes admin user access to icarus. All documentation and scripts must be executed on icarus context with an admin account.
Currently using an symbolic on icarus project on my dev device to this file.
## kubernetes Namespace
```bash
# delete namespace
kubectl create namespace casa-limbosolutions-com
```
```bash
# delete namespace
kubectl delete namespace casa-limbosolutions-com
```
## Roles and Bindings
``` yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
namespace: casa-limbosolutions-com
name: casa-limbosolutions-com
rules:
- apiGroups:
- ""
- cert-manager.io # to access deployments certs from cert-manager
- apps # to access deployments
- networking.k8s.io # to access ingresses
resources:
- pods
- services
- secrets
- certificates
- deployments
- configmaps
- ingresses
- persistentvolumeclaims
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- deletecollection
```
``` yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: casa-limbosolutions-com-rb # Replace with your role binding name
namespace: casa-limbosolutions-com # Replace with your namespace
subjects:
- kind: User # or "ServiceAccount" for service accounts
name: casa # Replace with the username or service account name
apiGroup: rbac.authorization.k8s.io
namespace: casa-limbosolutions-com
roleRef:
kind: ClusterRole
name: casa-limbosolutions-com # The name of the role you created
apiGroup: rbac.authorization.k8s.io
```
### kubernetes User
```bash
#Deploy csr to k3s
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: casa-user-csr
spec:
request: $(cat ../.env.d/.kube/casa@icarus-user.csr | base64 | tr -d '\n')
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
EOF
```
```bash
# Approve csr
kubectl certificate approve casa-user-csr
```
```bash
# Download kubernet user crt
kubectl get csr casa-user-csr -o jsonpath='{.status.certificate}' | base64 --decode > ./.env.d/casa@icarus-user.crt
```
@@ -0,0 +1 @@
@@ -0,0 +1,78 @@
configs:
sync-certs-sh:
content: |
#!/bin/bash
##############################################################################################################################
# notes:
# --certificate-authority="$${KUBERNETES_CRT_AUTHORITY}" not working, dont hnow why, so using --insecure-skip-tls-verify
##############################################################################################################################
set -e
mkdir -p /tmp/.kube
echo "Trace: Setup kube"
echo "Trace: Processing KUBERNETES_CRT_AUTHORITY_DATA"
base64 -d <<< "${KUBERNETES_CRT_AUTHORITY_DATA}" > "$${KUBERNETES_CRT_AUTHORITY}"
echo "Trace: Processing KUBERNETES_CRT_AUTHORITY_DATA"
base64 -d <<< "${KUBERNETES_CLIENT_CRT_DATA}" > "$${KUBERNETES_CLIENT_CRT}"
echo "Trace: Processing KUBERNETES_CLIENT_KEY_DATA"
base64 -d <<< "${KUBERNETES_CLIENT_KEY_DATA}" > "$${KUBERNETES_CLIENT_KEY}"
# while true ; do
# sleep 5
# done
echo "Trace: Fetching secrets"
CERT_NAMES=$(kubectl get secrets \
-n casa-limbosolutions-com \
--server="$${KUBERNETES_SERVER}" \
--client-key="$${KUBERNETES_CLIENT_KEY}" \
--client-certificate="$${KUBERNETES_CLIENT_CRT}" \
--insecure-skip-tls-verify \
-o json | jq -r '.items[].metadata.name')
for CERT_NAME in $$CERT_NAMES; do
echo "Trace: Syncing certificate: $$CERT_NAME"
kubectl get secret "$$CERT_NAME" \
-n casa-limbosolutions-com \
--server="$${KUBERNETES_SERVER}" \
--client-key="$${KUBERNETES_CLIENT_KEY}" \
--client-certificate="$${KUBERNETES_CLIENT_CRT}" \
--insecure-skip-tls-verify \
-o json | \
jq -r '.data | to_entries[] | "\(.key) \(.value)"' | \
while IFS=' ' read -r KEY VALUE; do
echo "Processing key: $$KEY"
# Decode the base64 value and save it to the appropriate file
echo "Trace: Saving key: $$KEY"
echo "$$VALUE" | base64 -d > "/etc/ssl/certs/casa-limbosolutions-com-certs/$${CERT_NAME}_$${KEY}"
done
done
echo "Info: Certificates synced successfully."
services:
kubectl:
image: bitnami/kubectl:latest
environment:
KUBERNETES_SERVER: ${KUBERNETES_SERVER}
KUBERNETES_CRT_AUTHORITY: /tmp/.kube/ca.crt
KUBERNETES_CLIENT_CRT: /tmp/.kube/client.crt
KUBERNETES_CLIENT_KEY: /tmp/.kube/client.key
container_name: sync-certs-job
entrypoint: bash -c /app/sync-certs.sh
configs:
- source: sync-certs-sh
target: /app/sync-certs.sh
mode: 0755
volumes:
- casa-certs:/etc/ssl/certs/casa-limbosolutions-com-certs:rw
volumes:
casa-certs:
name: casa-limbosolutions-com-certs
external: true # Atention permission must be set to 1001:1001 (using chown on nginx container command)
-101
View File
@@ -1,101 +0,0 @@
{
"folders": [
{
"path": "./",
"name": "casa"
},
{
"path": "../homeAssistant"
},
{
"path": "../lms"
},
{
"path": "../mosquitto"
},
{
"name": "kb",
"path": "../kb"
},
{
"name": "pi.bluetooth.speaker",
"path": "../pi.bluetooth.speaker"
},
],
"settings": {
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"kb": true,
"runme.taskProvider.enabled": false,
"runme.scanMode": "off"
},
"ansible.python.interpreterPath": "/bin/python",
"cSpell.words": [
"davidanson",
"eamodio",
"envsubst",
"lmscommunity",
"localtime",
"LOGLEVEL",
"lyrionmusicserver",
"mtxr",
"rclone",
"reverseproxy",
"rogalmic",
"runme",
"sqltools",
"yzhang"
],
"githubLocalActions.workflowsDirectory": ".gitea/workflows"
},
"tasks": {
"version": "2.0.0",
"tasks": [
{
"label": "Run current shell file - relative",
"type": "shell",
"command": "bash",
"args": [
"${file}"
],
"options": {
"cwd": "${fileDirname}"
},
"group": {
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
}
},
{
"label": "Run current shell file",
"type": "shell",
"command": "bash",
"args": [
"${file}"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
}
}
]
}
}
+49
View File
@@ -0,0 +1,49 @@
{
"folders": [
{
"path": "./",
"name": "homesrv01"
},
{
"path": "../homeAssistant"
},
{
"path": "../lms"
},
{
"path": "../mosquitto"
},
{
"name": "kb",
"path": "../kb"
},
// {
// "name": "kb/kb",
// "path": "../../kb/kb"
// }
],
"settings": {
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/Thumbs.db": true,
"kb": true,
},
"ansible.python.interpreterPath": "/bin/python",
"cSpell.words": [
"lmscommunity",
"localtime",
"lyrionmusicserver",
"rclone",
"reverseproxy"
]
}
}
-260
View File
@@ -1,260 +0,0 @@
# Casa k3s cluster
**k3s version:** v1.35.2+k3s1
**Table of Contents:**
- [Common](#common)
- [OCI Mirrors Cache](#oci-mirrors-cache)
- [Master Node](#master-node)
- [Master Node - proxmox vm](#master-node---proxmox-vm)
- [Master Node - network configuration](#master-node---network-configuration)
- [Master Node - k3s setup](#master-node---k3s-setup)
- [minion01 - worker node](#minion01---worker-node)
- [Minion01 - proxmox vm](#minion01---proxmox-vm)
- [casa-minion-01 - k3s - setup](#casa-minion-01---k3s---setup)
## Common
**Disable swap:**
``` bash
swapoff -a
Edit /etc/fstab and comment out any swap entries:
# /swapfile none swap sw 0 0
```
**Other Packages:**
``` bash
sudo apt update -y && \
sudo apt install -y \
curl \
btop
```
**Update system:**
``` bash
sudo apt update -y && \
sudo apt upgrade -y && \
sudo apt auto-remove -y
```
**name servers:**
``` bash
cat <<EOF > /etc/resolv.conf
domain dev.lan
search dev.lan. lan.
nameserver 192.168.14.254
EOF
```
### OCI Mirrors Cache
``` bash
# /etc/rancher/k3s/registries.yaml
mirrors:
# --- Docker Hub (all aliases → docker-mirror) ---
docker.io:
endpoint:
- https://oci.limbosolutions.com/v2/docker-mirror
registry-1.docker.io:
endpoint:
- https://oci.limbosolutions.com/v2/docker-mirror
index.docker.io:
endpoint:
- https://oci.limbosolutions.com/v2/docker-mirror
# --- GHCR ---
ghcr.io:
endpoint:
- https://oci.limbosolutions.com/v2/ghcr-mirror
# --- Quay.io ---
quay.io:
endpoint:
- https://oci.limbosolutions.com/v2/quay-mirror
# --- Kubernetes official registry ---
registry.k8s.io:
endpoint:
- https://oci.limbosolutions.com/v2/k8s-mirror
# --- Google Container Registry (your "grc-mirror") ---
gcr.io:
endpoint:
- https://oci.limbosolutions.com/v2/grc-mirror
# --- AWS Public ECR ---
public.ecr.aws:
endpoint:
- https://oci.limbosolutions.com/v2/aws-mirror
# --- Microsoft Container Registry ---
mcr.microsoft.com:
endpoint:
- https://oci.limbosolutions.com/v2/mcr-proxy
# --- GitLab Container Registry ---
registry.gitlab.com:
endpoint:
- https://oci.limbosolutions.com/v2/gitlab-mirror
# --- Bitnami (namespace under Docker Hub) ---
docker.io/bitnami:
endpoint:
- https://oci.limbosolutions.com/v2/bitnami-mirror
# --- Red Hat registry ---
registry.redhat.io:
endpoint:
- https://oci.limbosolutions.com/v2/readheat-mirror
configs:
oci.limbosolutions.com:
auth:
username: <username>
password: <password>
tls:
insecure_skip_verify: false
```
## Master Node
| Name | Value |
| --- | --- |
| **NAME** | casa.dev.lan |
| **VLAN** | casa |
| **IP** | 192.168.14.9 |
| **OS** | Debian GNU/Linux 12 (bookworm) |
### Master Node - proxmox vm
*hosted on surfacepro.*
``` yaml
agent: 1
balloon: 0
boot: order=scsi0;ide2;net0
cores: 2
cpu: host
ide2: none,media=cdrom
memory: 2355
meta: creation-qemu=10.1.2,ctime=1762626497
name: casa
net0: virtio=BXX:XX:XX:XX:XX:XX,bridge=vmbr0,tag=xx
numa: 0
onboot: 1
ostype: l26
scsi0: local-lvm:vm-XXX-disk-0,iothread=1,size=24G,ssd=1
scsihw: virtio-scsi-single
smbios1: uuid=cxxxx-xxxx-xxxx-xxxx-xxxx
sockets: 1
usb0: host=1-1.1
```
### Master Node - network configuration
``` bash
ip a # check ethernet name
# removes automatic configuration as dhcp client
sed -i '/ens18/d' /etc/network/interfaces
cat <<EOF > /etc/network/interfaces.d/ens18
# my network configuration
auto ens18
iface ens18 inet static
address 192.168.14.9/24
gateway 192.168.0.1
EOF
```
### Master Node - k3s setup
``` bash
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.35.2+k3s1 sh -
```
**Taint NoSchedule on master node:**
kubectl taint nodes <master-node-name> node-role.kubernetes.io/control-plane=:NoSchedule
``` bash
kubectl taint nodes casa node-role.kubernetes.io/control-plane=:NoSchedule
```
## minion01 - worker node
### Minion01 - proxmox vm
*hosted on gaia.*
```yaml
agent: 1
balloon: 0
boot: order=scsi0;ide2;net0
cores: 4
cpu: host
ide2: none,media=cdrom
memory: 4096
meta: creation-qemu=10.1.2,ctime=1763219351
name: casa-minion-01
net0: virtio=BXX:XX:XX:XX:XX:XX,bridge=vmbr0,tag=xx
numa: 0
onboot: 1
ostype: l26
scsi0: fastcore:vm-XXX-disk-0,iothread=1,size=8G,ssd=1
scsi1: fastcore:vm-XXX-disk-1,iothread=1,size=16G,ssd=1
scsihw: virtio-scsi-single
smbios1: xxxx-xxxx-xxxx-xxxx-xxxx
sockets: 1
```
| Name | Value |
| --- | --- |
| **NAME** | minion01 |
| **VLAN** | casa |
| **IP** | 192.168.14.10 |
| **OS** | Debian GNU/Linux 12 (bookworm) |
### casa-minion-01 - k3s - setup
``` bash
# install k3s as agent / worker node
# execute on server to get token
# cat /var/lib/rancher/k3s/server/node-token
K3S_TOKEN="???"
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.35.2+k3s1 INSTALL_K3S_EXEC="agent --data-dir /dataDisk/k3s --server https://casa.dev.lan:6443 --token ${K3S_TOKEN}" sh -s -
```
Change kubectl -n kube-system edit configmap local-path-config on kube-system to set path to provisioner.
``` yaml
config.json: |-
{
"nodePathMap":[
{
"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
"paths":["/var/lib/rancher/k3s/storage"]
},
{
"node":"casa-minion-01",
"paths":["/dataDisk/k3s/storage"]
}
]
}
```
**Set node labels:**
``` bash
kubectl label node casa-minion-01 role=worker-node
```
+40
View File
@@ -0,0 +1,40 @@
- name: Setup rclone docker plugin
become: true
vars:
# rclone_docker_plugin_config: |
# [s3-limbo-storage]
# type = s3
# provider = SeaweedFS
# access_key_id = !!! SET ON INVENTORY !!!
# secret_access_key = !!! SET ON INVENTORY !!!
# endpoint = !!! SET ON INVENTORY !!!
hosts:
- homesrv01
tasks:
- name: Enforce folders
ansible.builtin.file:
path: /var/lib/docker-plugins/rclone/config
state: directory
owner: root
group: root
mode: u=rwx,g=r,o-rwx
recurse: true
- name: Enforce folders
ansible.builtin.file:
path: /var/lib/docker-plugins/rclone/cache
state: directory
owner: root
group: root
mode: u=rwx,g=r,o-rwx
recurse: true
- name: Setup rclone s3
ansible.builtin.copy:
dest: /var/lib/docker-plugins/rclone/config/rclone.conf
owner: root
group: root
mode: u=rwx,g-rwx,o-rwx
content: "{{ rclone_docker_plugin_config }}"
@@ -1,11 +0,0 @@
creation_rules:
# encrypt all values from file
- path_regex: \.private\.dec\.yaml$
encrypted_regex: '^(.*)$'
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
# encrypt secrets files
- path_regex: .*.yaml
encrypted_regex: ^(data|stringData)$
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
-15
View File
@@ -1,15 +0,0 @@
# act-runners
## Setup
Using flux for reconciliation.
``` bash
./ops-scripts/apply-flux.sh
```
**Encrypt secrets:**
``` bash
sops -e deploy/app/secret.dec.yaml > deploy/app/secret.yaml
```
@@ -1,25 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: act-runner
data:
config.yaml: |
log:
level: info
runner:
capacity: 4
labels:
- kubectl
- helm
- ansible
- ubuntu
- network-utils
- deploy
- amd64
- casa-vlan-cicd
cache:
enabled: false
host:
workdir: "/data/runner"
@@ -1,103 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: casa-vlan-cicd-runners
labels:
app: casa-vlan-cicd-runners
spec:
replicas: 1
selector:
matchLabels:
app: casa-vlan-cicd-runners
template:
metadata:
labels:
app: casa-vlan-cicd-runners
spec:
nodeSelector:
role: worker-node
containers:
- name: mylimbo-casa-vlan-cicd-runner
image: oci.limbosolutions.com/public/gitea-act_runner:fatboy-0.6
imagePullPolicy: IfNotPresent
env:
- name: LOG_LEVEL
value: "trace"
- name: CONFIG_FILE
value: /config.yaml
- name: GITEA_INSTANCE_URL
valueFrom:
secretKeyRef:
name: casa-vlan-cicd-runners
key: GITEA_INSTANCE_URL
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: casa-vlan-cicd-runners
key: GITEA_MYLIMBO_RUNNER_REGISTRATION_TOKEN
- name: GITEA_RUNNER_NAME
valueFrom:
secretKeyRef:
name: casa-vlan-cicd-runners
key: GITEA_MYLIMBO_RUNNER_NAME
- name: GITEA_RUNNER_EPHEMERAL
value: "0"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "400m"
volumeMounts:
- name: config-map
mountPath: /config.yaml
subPath: config.yaml
- name: mf-casa-vlan-cicd-runner
image: oci.limbosolutions.com/public/gitea-act_runner:fatboy-0.6
imagePullPolicy: Always
env:
- name: LOG_LEVEL
value: "trace"
- name: CONFIG_FILE
value: /config.yaml
- name: GITEA_INSTANCE_URL
valueFrom:
secretKeyRef:
name: casa-vlan-cicd-runners
key: GITEA_INSTANCE_URL
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: casa-vlan-cicd-runners
key: GITEA_MF_RUNNER_REGISTRATION_TOKEN
- name: GITEA_RUNNER_NAME
valueFrom:
secretKeyRef:
name: casa-vlan-cicd-runners
key: GITEA_MF_RUNNER_NAME
- name: GITEA_RUNNER_EPHEMERAL
value: "0"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: " 512Mi"
cpu: "400m"
volumeMounts:
- name: config-map
mountPath: /config.yaml
subPath: config.yaml
volumes:
- name: config-map
configMap:
name: act-runner
@@ -1,7 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: casa-vlan-cicd
resources:
- configmap.yaml
- deployment.yaml
- secret.yaml
@@ -1,26 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: act-runner
type: Opaque
data:
GITEA_INSTANCE_URL: ENC[AES256_GCM,data:DFI/mFprPbTjBNbpASIzfxkQYOxEDVAanWWNqWTEIHzNuR5SD/bv8w==,iv:kAYTWAna344hy4oZ+MH/fiPoE4bZCt92niVg6S/PgsM=,tag:g5T6R2wEzjIiy2762N/H7A==,type:str]
GITEA_MYLIMBO_RUNNER_NAME: ENC[AES256_GCM,data:gW/DOukYZHrFzbc78Roi70kk9p7vUcHyl1w/bAB7q7M=,iv:Ip3aTsh73bM9GoNaSScvFaYmoiUz2iuGuVu2K5yHyrI=,tag:32w120l0xRU38NghfRx02A==,type:str]
GITEA_MYLIMBO_RUNNER_REGISTRATION_TOKEN: ENC[AES256_GCM,data:JJyMTbnjEoufj6c4KT3ssGm2c91eh7mY+fuYt4YY8bBfozhGlytoHgGEm5u1u3Dq1TNCx+lhIBI=,iv:T/IvhkBMFtU/1Mgtn3sHMsgGIk/7GVA7m/QSSSHkDgo=,tag:r3ON2jjlkA2j0AQfGwFg3A==,type:str]
GITEA_MF_RUNNER_NAME: ENC[AES256_GCM,data:QRjb2g6hTGHGjjC8T8s9rvP+y55qqRCFjeUz2Cb/fps=,iv:RRB6Gw1y2bRucIoae7oyz796u8KXnLylqwmxDSzsjc0=,tag:Y03ndziszoo1LepOibfEdQ==,type:str]
GITEA_MF_RUNNER_REGISTRATION_TOKEN: ENC[AES256_GCM,data:zXJjCwzEn9647VPiZqMaPKuwDxVf95g+df4dOnOj1Fj4TrND94SfsEjB5AaTbJquO7GDB6n9Ziw=,iv:JzCr0tbalWcwnP4AzF6UXIeIJMm5GFE9iPcjwGlc4+k=,tag:VBuSw0gRIhpyDU1DK505dA==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyK0RDL2pQTFoyN0cxd1ZM
TGZ0UitKbGh4QW1qQTQ2aDJ1a04yR0NzQ0RNCld1K3ovbmxCejhJTGlPZ01YZWtK
YXhvQjFBdFBQcUM5RDk1NERNYTd2dFkKLS0tIG5TVVpDY1M5OE4vdUYwNXYyUVVB
dS9CRDQzbGhKSzRBR2lKSEhIVVBKeFUKN4MK71sU1Tm4rxKq7xq1Qux23KaEAIzO
Aw6TMCE7li6PDhojderS8Ctp8fLEoE5PuaVOjeejGZtsjZcY4jcT1A==
-----END AGE ENCRYPTED FILE-----
recipient: age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-06-06T04:03:55Z"
mac: ENC[AES256_GCM,data:w5aSmw0vxMC7cnnwUl0MUFAoYZdxEWS5jO20lgwzR8co837gVXZbEzig8D8e0Q5ACRum0DEwKCymUVufPt34bgNV/QilW6mP3hh10oIo9NSktLH7u6VgCI4hdHaUsYbHNhkA9Tl8LK7FajjzrCv0Ha908HZ49grbPg1CTVAioF4=,iv:3+6shBcadgY32xmiDKsAqPGmHBYL7GIODR30BZ3qHNk=,tag:6YmQtL77ynfjv8/zgBBFBA==,type:str]
version: 3.13.1
@@ -1,2 +0,0 @@
**
!.gitignore
@@ -1,16 +0,0 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: act-runners
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: casa
namespace: casa-limbosolutions-com
path: services/casa-vlan-cicd-runners/deploy/app
prune: true
decryption:
provider: sops
secretRef:
name: flux-sops-age
@@ -1,11 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: casa-vlan-cicd
resources:
- app-sync.yaml
secretGenerator:
- name: flux-sops-age
files:
- "age.agekey=./.env.d/age.agekey"
generatorOptions:
disableNameSuffixHash: true
@@ -1,2 +0,0 @@
#!/bin/bash
kubectl kustomize deploy/flux | kubectl apply -f -
-2
View File
@@ -1,2 +0,0 @@
.env.d/**
.env
-91
View File
@@ -1,91 +0,0 @@
# cert-manager
- [cloudflare](#cloudflare)
- [api secrets](#api-secrets)
- [Cluster Issuer](#cluster-issuer)
- [Staging](#staging)
- [Deploy](#deploy)
- [Describe](#describe)
- [Production](#production)
- [Deploy (Production)](#deploy-production)
- [Describe (Production)](#describe-production)
- [helm chart](#helm-chart)
## cloudflare
## api secrets
[cloudflare-api-token.yaml](./cloudflare-api-token.yaml).
```bash
set -a
source ./.env
set +a
envsubst < ./cloudflare-api-token.yaml \
| kubectl apply -n kube-system -f -
```
## Cluster Issuer
### Staging
#### Deploy
[letsencrypt-clusterissuer-staging.yaml](./letsencrypt-clusterissuer-staging.yaml).
```bash
set -a
source ./.env
set +a
envsubst < ./letsencrypt-clusterissuer-staging.yaml \
| kubectl apply -n kube-system -f -
```
#### Describe
```bash
kubectl describe clusterissuer letsencrypt-staging
```
### Production
#### Deploy (Production)
[letsencrypt-clusterissuer-prod.yaml](./letsencrypt-clusterissuer-prod.yaml).
```bash
set -a
source ./.env
set +a
envsubst < ./letsencrypt-clusterissuer-prod.yaml \
| kubectl apply -n kube-system -f -
```
```bash
set -a
source ./.env
set +a
envsubst < ./letsencrypt-clusterissuer-staging.yaml \
| kubectl apply -n kube-system -f -
```
#### Describe (Production)
```bash
kubectl describe clusterissuer letsencrypt-prod
```
**Force cert refresh:**
``` bash
kubectl delete certificaterequest -l cert-manager.io/certificate-name=monitoring-limbosolutions-com-tls
kubectl delete order -l cert-manager.io/certificate-name=monitoring-limbosolutions-com-tls
```
## helm chart
Using flux for reconciliation.
``` bash
kubectl kustomize deploy/flux | kubectl apply -f -
```
@@ -1,15 +0,0 @@
#########################################################################
# requires ./.env
# ./.env example:
# EMAIL="myemail@example.com"
# check README.md for more information
##########################################################################
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token
namespace: kube-system
type: Opaque
stringData:
api-token: ${CLOUDFLARE_API_TOKEN}
@@ -1,17 +0,0 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
spec:
releaseName: cert-manager
interval: 40h
chart:
spec:
chart: cert-manager
version: 1.x.x
sourceRef:
kind: HelmRepository
name: cert-manager
interval: 40h
values:
crds.enabled: true
@@ -1,7 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: cert-manager
spec:
interval: 40h
url: https://charts.jetstack.io
@@ -1,6 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kube-system
resources:
- helm-repo.yaml
- helm-release.yaml
@@ -1,12 +0,0 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: cert-manager
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: casa
namespace: casa-limbosolutions-com
path: services/cert-manager/deploy/app
prune: true
@@ -1,5 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: kube-system
resources:
- app-sync.yaml
@@ -1,28 +0,0 @@
#########################################################################
# requires ./.env
# ./.env example:
# EMAIL="myemail@example.com"
# check README.md for more information
##########################################################################
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: kube-system
spec:
acme:
email: "${EMAIL}"
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- selector:
dnsZones:
- "limbosolutions.com"
dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token
@@ -1,29 +0,0 @@
#########################################################################
# requires ./.env
# ./.env example:
# EMAIL="myemail@example.com"
# CLOUDFLARE_API_TOKEN="clouddlare api key"
# check README.md for more information
##########################################################################
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: kube-system
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Replace with your domain email.
email: "${EMAIL}"
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- dns01:
cloudflare:
email: ${EMAIL}
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token
-25
View File
@@ -1,25 +0,0 @@
# fluxcd-system
## Setup
⚠️ **Note**
Do not use helm upgrade --install for the Flux Operator.
Operators mutate their own resources, so Helm cannot reconcile them.
Use helm upgrade or uninstall + install instead.
### Install operator
``` bash
helm install flux-operator oci://ghcr.io/controlplaneio-fluxcd/charts/flux-operator \
--namespace flux-system \
--create-namespace
```
### Update operator and flux system
``` bash
helm upgrade flux-operator oci://ghcr.io/controlplaneio-fluxcd/charts/flux-operator \
--namespace flux-system \
--create-namespace
kubectl apply -f ./deploy/fluxsystem.yaml
```
@@ -1,26 +0,0 @@
apiVersion: fluxcd.controlplane.io/v1
kind: FluxInstance
metadata:
name: flux
namespace: flux-system
annotations:
fluxcd.controlplane.io/reconcileEvery: "1h"
fluxcd.controlplane.io/reconcileTimeout: "10m"
spec:
distribution:
version: "2.x"
registry: "ghcr.io/fluxcd"
artifact: "oci://ghcr.io/controlplaneio-fluxcd/flux-operator-manifests"
components:
- source-controller
- source-watcher
- kustomize-controller
- helm-controller
- notification-controller
- image-reflector-controller
- image-automation-controller
cluster:
type: kubernetes
size: medium
multitenant: false
networkPolicy: true
-11
View File
@@ -1,11 +0,0 @@
creation_rules:
# encrypt all values from file
- path_regex: \.private\.dec\.yaml$
encrypted_regex: '^(.*)$'
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
# encrypt secrets files
- path_regex: .*.yaml
encrypted_regex: ^(data|stringData)$
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
-22
View File
@@ -1,22 +0,0 @@
# monitoring
## prometheus-stack
- <https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack>
- <https://github.com/prometheus-community/helm-charts/blob/main/charts/kube-prometheus-stack/values.yaml>
## promtail
## Setup
Using flux for reconciliation.
``` bash
./ops-scripts/apply-flux.sh
```
**promtail Encrypt secrets:**
``` bash
sops -e deploy/promtail/helm-values.private.dec.yaml > deploy/promtail/helm-values.private.yaml
```
@@ -1,2 +0,0 @@
**
!.gitignore
@@ -1,12 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: monitoring
resources:
- promtail-app-sync.yaml
- prometheus-app-sync.yaml
secretGenerator:
- name: flux-sops-age
files:
- "age.agekey=./.env.d/age.agekey"
generatorOptions:
disableNameSuffixHash: true
@@ -1,16 +0,0 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: prometheus
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: casa
namespace: casa-limbosolutions-com
path: services/monitoring/deploy/prometheus
prune: true
decryption:
provider: sops
secretRef:
name: flux-sops-age
@@ -1,16 +0,0 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: promtail
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: casa
namespace: casa-limbosolutions-com
path: services/monitoring/deploy/promtail
prune: true
decryption:
provider: sops
secretRef:
name: flux-sops-age
@@ -1,55 +0,0 @@
# values.yaml to install only Prometheus Operator and CRDs
# Disable all components except the operator
defaultRules:
create: false
alertmanager:
enabled: false
grafana:
enabled: false
kubeStateMetrics:
enabled: false
nodeExporter:
enabled: false
prometheus:
enabled: false
coreDns:
enabled: false
kubeControllerManager:
enabled: false
kubeEtcd:
enabled: false
kubeProxy:
enabled: false
kubeScheduler:
enabled: false
prometheusOperator:
enabled: true
createCustomResource: true
tls:
enabled: false
admissionWebhooks:
enabled: false
cleanupCustomResource: false
serviceMonitor:
selfMonitor: false
kubeletService:
enabled: true
# requires manual creation of service #prom-kublet-service
nodeSelector:
role: worker-node
# global:
# nodeSelector:
# dedicated: worker-node
@@ -1,36 +0,0 @@
kubeStateMetrics:
enabled: true
kube-state-metrics: # ok tested!
podLabels:
role: worker-node
nodeSelector:
role: worker-node
prometheus:
monitor:
interval: "60s"
relabelings:
- targetLabel: cluster
replacement: casa
additionalLabels:
app.kubernetes.io/name: prometheus-kube-state-metrics # !important: selector used by agent
coreDns: # ok tested!
enabled: true
serviceMonitor:
relabelings:
- targetLabel: cluster
replacement: casa
additionalLabels:
app.kubernetes.io/name: prometheus-stack-coredns # !important: selector used by agent
kubeApiServer: # ok tested!
enabled: true
serviceMonitor:
relabelings:
- targetLabel: cluster
replacement: casa
additionalLabels:
app.kubernetes.io/name: prometheus-stack-apiserver # !important: selector used by agent
@@ -1,25 +0,0 @@
# Deploy node exporter as a daemonset to all nodes
nodeExporter:
enabled: true
# job node exporter
prometheus-node-exporter:
prometheus:
monitor:
enabled: true
interval: "60s"
relabelings:
# https://github.com/dotdc/grafana-dashboards-kubernetes
- action: replace
sourceLabels: [__meta_kubernetes_pod_node_name]
targetLabel: nodename
# identification of cluster
- targetLabel: cluster
replacement: casa
# it seams to be an timestamp can not be an label!
- action: labeldrop
regex: __meta_kubernetes_endpoints_annotation_endpoints_kubernetes_io_last_change_trigger_time
@@ -1,78 +0,0 @@
# Used file to testing new options and configurations
# Should be the laste file to be loaded
kubelet:
enabled: true
namespace: kube-system
serviceMonitor:
interval: 60s #WARN: Error on ingesting out-of-order samples. https://github.com/prometheus-community/helm-charts/issues/5483
enabled: true
## Enable scraping /metrics from kubelet's service
kubelet: true
cAdvisor: true
additionalLabels:
app.kubernetes.io/name: prometheus-kubelet # !important: selector used by agent
probesMetricRelabelings:
- targetLabel: cluster
replacement: casa
- sourceLabels: [__name__, image]
separator: ;
regex: container_([a-z_]+);
replacement: $1
action: drop
- sourceLabels: [__name__]
separator: ;
regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s)
replacement: $1
action: drop
# # RelabelConfigs to apply to samples before scraping
# # ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md#relabelconfig
# #
# # metrics_path is required to match upstream rules and charts
cAdvisorRelabelings:
- targetLabel: cluster
replacement: casa
- action: replace
sourceLabels: [__metrics_path__]
targetLabel: metrics_path
- sourceLabels: [__meta_kubernetes_pod_node_name]
separator: ;
regex: ^(.*)$
targetLabel: nodename
replacement: $1
action: replace
# # RelabelConfigs to apply to samples before scraping
# # ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api-reference/api.md#relabelconfig
# #
probesRelabelings:
- targetLabel: cluster
replacement: casa
- action: replace
sourceLabels: [__metrics_path__]
targetLabel: metrics_path
- sourceLabels: [__meta_kubernetes_pod_node_name]
separator: ;
regex: ^(.*)$
targetLabel: nodename
replacement: $1
action: replace
resourceRelabelings:
- targetLabel: cluster
replacement: casa
- action: replace
sourceLabels: [__metrics_path__]
targetLabel: metrics_path
@@ -1,28 +0,0 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: prometheus-stack
spec:
releaseName: prometheus-stack
interval: 40h
chart:
spec:
chart: prometheus-stack
version: 86.x.x
sourceRef:
kind: HelmRepository
name: prometheus-stack
interval: 40h
valuesFrom:
- kind: Secret
name: prometheus-stack-helm-values
valuesKey: 01-only-crd-and-operator.yaml
- kind: Secret
name: prometheus-stack-helm-values
valuesKey: 02-kube-metrics.yaml
- kind: Secret
name: prometheus-stack-helm-values
valuesKey: 03-node-exporter.yaml
- kind: Secret
name: prometheus-stack-helm-values
valuesKey: 04-kubelet.yaml
@@ -1,7 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: prometheus-stack
spec:
interval: 40h
url: https://prometheus-community.github.io/helm-charts
File diff suppressed because it is too large Load Diff
@@ -1,14 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: monitoring
resources:
- helm/helm-repo.yaml
- helm/helm-release.yaml
- prometheus-agent.yaml
secretGenerator:
- name: prometheus-stack-helm-values
files:
- 01-only-crd-and-operator.yaml=helm/01-only-crd-and-operator.yaml
- 02-kube-metrics.yaml=helm/02-kube-metrics.yaml
- 03-node-exporter.yaml=helm/03-node-exporter.yaml
- 04-kubelet.yaml=helm/04-kubelet.yaml
@@ -1,75 +0,0 @@
apiVersion: monitoring.coreos.com/v1alpha1
kind: PrometheusAgent
metadata:
name: prometheus-agent
spec:
podMonitorNamespaceSelector:
matchLabels:
prometheus-monitoring: enabled
podMonitorSelector:
matchLabels:
release: prometheus-stack
serviceMonitorNamespaceSelector:
matchLabels:
prometheus-monitoring: enabled
serviceMonitorSelector:
matchLabels:
release: prometheus-stack
replicas: 1
remoteWrite:
- url: https://prometheus.monitoring.limbosolutions.com/api/v1/write
scrapeInterval: 60s
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 300Mi
serviceAccountName: prometheus-agent
nodeSelector:
role: worker-node
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus-agent
rules:
- apiGroups: [""]
resources: ["nodes", "nodes/metrics", "nodes/proxy", "services", "endpoints", "pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["monitoring.coreos.com"]
resources: ["servicemonitors", "podmonitors"]
verbs: ["get", "list", "watch"]
- nonResourceURLs:
- /metrics
- /metrics/cadvisor
- /metrics/probes
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus-agent-monitoring
roleRef:
kind: ClusterRole
name: prometheus-agent
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: prometheus-agent
namespace: monitoring
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus-agent
namespace: monitoring
@@ -1,22 +0,0 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: promtail
spec:
releaseName: promtail
interval: 40h
chart:
spec:
chart: promtail
version: 6.x.x
sourceRef:
kind: HelmRepository
name: grafana
interval: 40h
valuesFrom:
- kind: Secret
name: promtail-helm-values
valuesKey: values.yaml
- kind: Secret
name: promtail-helm-values
valuesKey: values.private.yaml
@@ -1,7 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: grafana
spec:
interval: 40h
url: https://grafana.github.io/helm-charts
@@ -1,18 +0,0 @@
config:
clients:
- url: ENC[AES256_GCM,data:AarLpmfJTu63kYzATeKf4m+60h93G5unSf2e8BplmCws7iVRzeFYGdvp14caaFZiZwWXe5rsdrMBQRc=,iv:Se74MvPyIP5xDcjrKBv3/X4G3G+Q9AYmdK/5t4yDuZc=,tag:A64ERrlrlCgf7PiQMT9WuQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYWjJxcitwdjR3QzQrSGVn
OVRFeTVrUGZMWlcycUREeWJWenpnVDVSbVJRClphakRuL2h2dEsvYWQ3VXJ4aHZL
YzQrU0FiRWttRUpmQkd5eVJFVVZBdVkKLS0tIDB3Y1FwQU5ndVlOQzNkZHA3V1Vl
bVpyTmhtUUhVTk9xZUFibHFyMVdqOEEKgoIrI9rJ1Q93AOZrP8r4rOggIGpSDv2H
uLp0yj1VqyyvtB/RHu4/Gyef2P5IwjTBnYYhZHbfX3AnYYWN58Riog==
-----END AGE ENCRYPTED FILE-----
recipient: age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
encrypted_regex: ^(.*)$
lastmodified: "2026-06-07T21:04:02Z"
mac: ENC[AES256_GCM,data:Ieh41SbHtPqOIT2ynSEnz+qwaCsEDo9cZOk63AyuiMqsT0vR8TR94gimOKrMgQhjLpJPREYg0hXALgq7x6BxMfzts8n+eRuDsVxah8e17Ad4Gk9Vq9RtHYL06RO4EhevhzuzX32W8N1jt2wJTSDA4Ztjh1QIAAd7YyNnvYOATBo=,iv:eNzc4ObZ7lplIDPjF8Ub4Rfq3AiWLyOGwAdMLY7ojvo=,tag:87y5KNeAYASA/wDs4ETWmw==,type:str]
version: 3.13.1
@@ -1,52 +0,0 @@
config:
clients:
- url: "????" #replaced values.local.yaml. Example: https://lokiserver/loki/api/v1/push
# by default all scrap configs had node_name
snippets:
extraRelabelConfigs:
- target_label: host
replacement: ${HOSTNAME}
- target_label: cluster
replacement: casa
extraScrapeConfigs: |
#scrape config for syslog
- job_name: host-journald
journal:
json: true
max_age: 24h
path: /var/log/host/journal
labels:
job: journald
relabel_configs:
- source_labels: ['__journal__systemd_unit']
target_label: 'journal_systemd_unit'
- source_labels: ['__journal_syslog_identifier']
target_label: 'journal_syslog_identifier'
- source_labels: ['__journal__hostname']
target_label: 'journal_hostname'
- target_label: 'host'
replacement: '${HOSTNAME}'
- target_label: 'cluster'
replacement: 'casa'
extraArgs:
- --config.expand-env=true
extraVolumes:
- name: node-logs
hostPath:
path: /var/log
extraVolumeMounts:
- name: node-logs
mountPath: /var/log/host
readOnly: true
resources:
limits:
cpu: 200m
memory: 100Mi
requests:
cpu: 100m
memory: 50Mi
@@ -1,13 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: monitoring
resources:
- helm-repo.yaml
- helm-release.yaml
secretGenerator:
- name: promtail-helm-values
files:
- values.yaml=helm-values.yaml
- values.private.yaml=helm-values.private.yaml
generatorOptions:
disableNameSuffixHash: true
@@ -1,4 +0,0 @@
#!/bin/bash
set -e
kubectl kustomize deploy/flux | kubectl apply -f -
@@ -0,0 +1,140 @@
services:
act-runner:
container_name: myLimbo-casa-gitea-act-runner
image: docker.io/gitea/act_runner:latest
restart: always
volumes:
- myLimbo-casa-gitea-act-runner-data:/data
- myLimbo-casa-gitea-act-runner-config:/config
- /var/run/docker.sock:/var/run/docker.sock
environment:
- GITEA_INSTANCE_URL=${GITEA_INSTANCE_URL}
# When using Docker Secrets, it's also possible to use
# GITEA_RUNNER_REGISTRATION_TOKEN_FILE to pass the location.
# The env var takes precedence.
# Needed only for the first start.
- CONFIG_FILE= /config/config.yaml
- GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN}
- GITEA_RUNNER_NAME=myLimbo-casa-gitea-act-runner
#- GITEA_RUNNER_CONFIG_FILE="/config/config.yaml"
configs:
- source: act-runner-config
target: /config/config.yaml
mode: 0444
volumes:
myLimbo-casa-gitea-act-runner-data:
name: myLimbo-casa-gitea-act-runner-data
myLimbo-casa-gitea-act-runner-config:
name: myLimbo-casa-gitea-act-runner-config
configs:
act-runner-config:
content: |
# Example configuration file, it's safe to copy this as the default config file without any modification.
# You don't have to copy this file to your instance,
# just run `./act_runner generate-config > config.yaml` to generate a config file.
log:
# The level of logging, can be trace, debug, info, warn, error, fatal
level: info
runner:
# Where to store the registration result.
file: .runner
# Execute how many tasks concurrently at the same time.
capacity: 1
# Extra environment variables to run jobs.
envs:
A_TEST_ENV_NAME_1: a_test_env_value_1
A_TEST_ENV_NAME_2: a_test_env_value_2
# Extra environment variables to run jobs from a file.
# It will be ignored if it's empty or the file doesn't exist.
env_file: .env
# The timeout for a job to be finished.
# Please note that the Gitea instance also has a timeout (3h by default) for the job.
# So the job could be stopped by the Gitea instance if it's timeout is shorter than this.
timeout: 3h
# The timeout for the runner to wait for running jobs to finish when shutting down.
# Any running jobs that haven't finished after this timeout will be cancelled.
shutdown_timeout: 0s
# Whether skip verifying the TLS certificate of the Gitea instance.
insecure: false
# The timeout for fetching the job from the Gitea instance.
fetch_timeout: 5s
# The interval for fetching the job from the Gitea instance.
fetch_interval: 2s
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
# Like: "macos-arm64:host" or "ubuntu-latest:docker://gitea/runner-images:ubuntu-latest"
# Find more images provided by Gitea at https://gitea.com/gitea/runner-images .
# If it's empty when registering, it will ask for inputting labels.
# If it's empty when execute `daemon`, will use labels in `.runner` file.
labels:
- "myLimbo-casa-gitea-act-runner:docker://gitea/runner-images:ubuntu-latest"
#- "ubuntu-latest:docker://gitea/runner-images:ubuntu-latest"
#- "ubuntu-22.04:docker://gitea/runner-images:ubuntu-22.04"
#- "ubuntu-20.04:docker://gitea/runner-images:ubuntu-20.04"
cache:
# Enable cache server to use actions/cache.
enabled: true
# The directory to store the cache data.
# If it's empty, the cache data will be stored in $HOME/.cache/actcache.
dir: ""
# The host of the cache server.
# It's not for the address to listen, but the address to connect from job containers.
# So 0.0.0.0 is a bad choice, leave it empty to detect automatically.
host: ""
# The port of the cache server.
# 0 means to use a random available port.
port: 0
# The external cache server URL. Valid only when enable is true.
# If it's specified, act_runner will use this URL as the ACTIONS_CACHE_URL rather than start a server by itself.
# The URL should generally end with "/".
external_server: ""
container:
# Specifies the network to which the container will connect.
# Could be host, bridge or the name of a custom network.
# If it's empty, act_runner will create a network automatically.
network: ""
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
privileged: false
# And other options to be used when the container is started (eg, --add-host=my.gitea.url:host-gateway).
options:
# The parent directory of a job's working directory.
# NOTE: There is no need to add the first '/' of the path as act_runner will add it automatically.
# If the path starts with '/', the '/' will be trimmed.
# For example, if the parent directory is /path/to/my/dir, workdir_parent should be path/to/my/dir
# If it's empty, /workspace will be used.
workdir_parent:
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
# You can specify multiple volumes. If the sequence is empty, no volumes can be mounted.
# For example, if you only allow containers to mount the `data` volume and all the json files in `/src`, you should change the config to:
# valid_volumes:
# - data
# - /src/*.json
# If you want to allow any volume, please use the following configuration:
# valid_volumes:
# - '**'
valid_volumes: []
# overrides the docker client host with the specified one.
# If it's empty, act_runner will find an available docker host automatically.
# If it's "-", act_runner will find an available docker host automatically, but the docker host won't be mounted to the job containers and service containers.
# If it's not empty or "-", the specified docker host will be used. An error will be returned if it doesn't work.
docker_host: ""
# Pull docker image(s) even if already present
force_pull: true
# Rebuild docker image(s) even if already present
force_rebuild: false
host:
# The parent directory of a job's working directory.
# If it's empty, $HOME/.cache/act/ will be used.
workdir_parent:
+41
View File
@@ -0,0 +1,41 @@
configs:
run-sh:
content: |
#!/bin/sh
# patch security so kubctl on sync-certs-job can write to the mounted volume
chown -R 1001:1001 /etc/ssl/certs/casa-limbosolutions-com-certs
while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"
services:
nginx:
build:
context: ./docker
pull_policy: build
image: homesrv/nginx:latest
volumes:
- casa-limbosolutions-com-certs:/etc/ssl/certs/casa-limbosolutions-com-certs
ports:
- 443:443
- 80:80
networks:
- public
restart: unless-stopped
command: /bin/sh -c '/run.sh'
configs:
- source: run-sh
target: /run.sh
mode: 0755
volumes:
nginx-conf.d:
casa-limbosolutions-com-certs:
name: casa-limbosolutions-com-certs
external: false
networks:
public:
name: reverseproxy_public
external: true
+4
View File
@@ -0,0 +1,4 @@
FROM nginx:latest
COPY nginx.conf.d/* /etc/nginx/conf.d
@@ -0,0 +1,35 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name casa.limbosolutions.com *.casa.limbosolutions.com has.lan;
return 301 https://has.casa.limbosolutions.com$request_uri;
}
server {
listen 443 ssl;
ssl_certificate /etc/ssl/certs/casa-limbosolutions-com-certs/casa-limbosolutions-com-tls_tls.crt;
ssl_certificate_key /etc/ssl/certs/casa-limbosolutions-com-certs/casa-limbosolutions-com-tls_tls.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://homeassistant-app:80;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
@@ -0,0 +1,32 @@
server {
server_name lms.casa.limbosolutions.com music.casa.limbosolutions.com;
listen 443 ssl;
ssl_certificate /etc/ssl/certs/casa-limbosolutions-com-certs/casa-limbosolutions-com-tls_tls.crt;
ssl_certificate_key /etc/ssl/certs/casa-limbosolutions-com-certs/casa-limbosolutions-com-tls_tls.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
set $upstream lms-lms-1;
#docker default resolver
resolver 127.0.0.11 ipv6=off;
proxy_pass http://$upstream:9002;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Url-Scheme $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
server {
listen 80;
server_name lms.casa.limbosolutions.com music.casa.limbosolutions.com lms.lan music.lan;
return 301 https://lms.casa.limbosolutions.com$request_uri;
}
@@ -0,0 +1,22 @@
server {
listen 80;
proxy_buffering off;
server_name zigbee2mqtt.lan;
location / {
proxy_pass http://zigbee2mqtt:8080/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Url-Scheme $scheme;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
-11
View File
@@ -1,11 +0,0 @@
creation_rules:
# encrypt all values from file
- path_regex: \.private\.dec\.yaml$
encrypted_regex: '^(.*)$'
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
# encrypt secrets files
- path_regex: .*.yaml
encrypted_regex: ^(data|stringData)$
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
-21
View File
@@ -1,21 +0,0 @@
# node-red
``` bash
#npm install bcryptjs
node -e "console.log(require('bcryptjs').hashSync(process.argv[1], 8));" YOUR-PASSWORD
```
## Setup
Using flux for reconciliation.
``` bash
./ops-scripts/apply-flux.sh
```
**Encrypt secrets:**
``` bash
sops -e deploy/app/limbomox-ssh-secret.dec.yaml > deploy/app/limbomox-ssh-secret.yaml
sops -e deploy/app/node-red-settings-secret.dec.yaml > deploy/app/node-red-settings-secret.yaml
```
@@ -1,49 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-red
namespace: node-red
spec:
replicas: 1
selector:
matchLabels:
app: node-red
template:
metadata:
labels:
app: node-red
spec:
containers:
- name: node-red
### Maintained by flux - Image Update Automation
image: nodered/node-red:latest@sha256:153f411d2993abd9ccd8290017ff2bb531326320b5cd3b200c1a4bb1339eb819 # {"$imagepolicy": "node-red:node-red"}
###
imagePullPolicy: Always
ports:
- containerPort: 1880
volumeMounts:
- name: node-red-data
mountPath: /data
- name: node-red-settings
mountPath: /data/settings.js
subPath: settings.js
- name: limbomox-ssh
mountPath: /.keys/limbomox-ssh-node-red/id_ed25519
subPath: id-ed25519
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
volumes:
- name: node-red-data
persistentVolumeClaim:
claimName: node-red
- name: node-red-settings
secret:
secretName: node-red-settings
- name: limbomox-ssh
secret:
secretName: limbomox-ssh
@@ -1,13 +0,0 @@
apiVersion: image.toolkit.fluxcd.io/v1
kind: ImagePolicy
metadata:
name: node-red
spec:
imageRepositoryRef:
name: node-red
filterTags:
pattern: '^latest$'
policy:
alphabetical: {}
digestReflectionPolicy: Always
interval: 24h
@@ -1,7 +0,0 @@
apiVersion: image.toolkit.fluxcd.io/v1
kind: ImageRepository
metadata:
name: node-red
spec:
image: nodered/node-red
interval: 72h
@@ -1,25 +0,0 @@
apiVersion: image.toolkit.fluxcd.io/v1
kind: ImageUpdateAutomation
metadata:
name: node-red
spec:
interval: 72h
sourceRef:
kind: GitRepository
name: casa
namespace: casa-limbosolutions-com
git:
checkout:
ref:
branch: main
commit:
author:
name: FluxCD
email: flux@local
messageTemplate: |
Update node-red image.
push:
branch: main
update:
path: ./services/node-red/deploy/app/deployment.yaml
strategy: Setters
-15
View File
@@ -1,15 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: node-red
namespace: node-red
spec:
entryPoints:
- websecure
routes:
- match: Host(`node-red.casa.limbosolutions.com`)
kind: Rule
services:
- name: node-red
port: 1880
tls: {}
@@ -1,15 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: node-red
resources:
- pvc.yaml
- deployment.yaml
- service.yaml
- ingress.yaml
- node-red-settings-secret.yaml
- limbomox-ssh-secret.yaml
- image-policy.yaml
- image-repo.yaml
- image-update-automation.yaml
@@ -1,23 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: limbomox-ssh
namespace: default
type: Opaque
stringData:
id-ed25519: ENC[AES256_GCM,data:9uENRt6+bjLClesmUeyAMAuITsyHiAdsNyX2rqHaasf93UjZOm/yURzyqiTgTcnboCjQo0gesPKoCssWmsOO+vstzN9mkVGMTnQZb7lC1+cbiD5ZQ+BXuIyejdjkcJ3fFrE8YcIjwH9VsYed/cXTM4XCPexg32oXO/0Hw903S5/NW4mmVB/q7nbXToHUBrDJ3lGutX6+74q7bSYTNC2QXb2mRnC/5MKBKWq6aISNBjaeQrELuF6gbNO1xg7aETWuDbqJvsFXU+Lv2XrjXeTjeAYTS9WuB9NNhz6GdjyYVt5BuPpFwJjzPGTOcxNOwvOeKUEw5Kc60nec+EoYVDufyH9WtLE8uJ7Y5vcDo1T7/KIq3Dv37Ib+JVMM+gpopBdcz4MyuWCIfjOUQuhiaYSVjtFTUl9MFCmRBbph0g/Ji+fGfeXEBGkdarwkiM+5mBMoAea08/4V5Q65JStMTs66smY3o3jagczbRoWvYgGXSuwqL/cB0hu8lkcM+gHSNB4tFZssotv2s+q7dOzfYrz245A1e8B5BsK+bt4d,iv:Kxez06BbXrF5Tt/JeNwqHexjctXmlFdMXvBRTNJEjCw=,tag:nDsAJwNxYPiFudyxvtnOTQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZeFNidktjbXlpQ3BYWHdm
cFJVZ3lFUHAvTHN0Y0J6aG1ibmNHWnFFc3g4Ck83NElVMjF3UjROUEMwN3lQekRD
RVZoTS9QN0Z1M2p5ajM4MDJnVjhXcE0KLS0tIGdYSU5TMS9zd2pETTJhWnY1cHV0
eDZSTlNOclFBdmFuRXZHbGNPbGNIeEUKUfuZRzkXPP0EIE+tgjnlkfgFzchmDLHa
Yqk7lPPPBbpHbMHFh63+Lv5d2bW59gnZlX3vCUqIeKHem6YgLHEVqw==
-----END AGE ENCRYPTED FILE-----
recipient: age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-06-06T03:28:41Z"
mac: ENC[AES256_GCM,data:ctXzJqFSyUi/PGjeQINEI+VQHAPFaWa297E8bMZKHqcnvcwpAoAL3wCnjP309DSoq+lNA/ahwIPCK2QKn/8H4wRGEELeT3fUD5L2IxKshhnxa84mDd3wTy5ed9X/VQobpcA/mdm4fnF5X4Bq8IejCanW5bYUsC3ManPdNIN2imQ=,iv:AbzGZcT1q7yxPwo/65t9g/pfU8R6bahTmjMQ791w3QY=,tag:DGxAVdi4qA18U8EF/OHzWg==,type:str]
version: 3.13.1
@@ -1,23 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: node-red-settings
namespace: default
type: Opaque
stringData:
settings.js: ENC[AES256_GCM,data:vQn3dEEN76rYbVlURLYloa7EeN7C9QB4VH6aHeu7lTvGb0Jh9fMaVGuPX0vYspwKEedPTB3oW1C/Q/EMFOqzPZlEbdfWWl37sVrdgu/lvUDApZoX4TU7hQI1VYN6s1tOJu2X2pw99cmq9MqZ1iEDyjwuhGZjTZ2lpTzSMoOTOwLE0Ugnnc3T/oeFYCO5MJzQ1jAa4tkf11YZiXie3Qa1FjehbrBzjrrPX781Gmv94TClEtx0IqnDftaQS4JaIGAfQq2expcgvGuPR2p2MAqVhtK9e6zQzZ2lKzhJQDBbiVisDiyw9FWxZRHDyjbPHe+PgSLF78A=,iv:l/Aev3/0zDmCL2PG4Erhfc8L5sXQYGcGCzMG4miWbJI=,tag:uyJe0ER5mMPi5BY9PnZICQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2NWxsWnF3L2pGQTdGVzJD
ODVSK25RUWo1MFBXa25TRVQrclFqaDFoOHg0CjFOVTRQS25tU1ZOZkxCNlA5Nmtu
OWRYbjJUWVBiNnlrZWhHMjJuZmZoZUUKLS0tIEpKTU94NXJ3ZVFid2VnWFhTcFp3
MVUrTklXZGpBNFRZa05oSFVjdGoyamcKTEUcmBHKK1NUqS9Zp5ychbB5u+xUCXCp
1I5usEDrWxOUkPqWN1PasKGm8BwTh6Onm1Gj3xZ+C+KRiAxPd6Grpg==
-----END AGE ENCRYPTED FILE-----
recipient: age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-06-06T03:28:41Z"
mac: ENC[AES256_GCM,data:lKuguuZ4oNQ3g6RqovFKoGb5zbZIt0OV+GLVSYT0CS1Vl5lsecN8UmzY7E2X83Sv+koOfc7DAgUa1bsxT0CeeM34W9Zk1RM8ZyHRzPpPLsxjZezYPnXdOHwRuXQWf16wb3SAooLZ25L1Y0TEoFybzqbhXvorHmx90d55DGZuWII=,iv:glW4I7A20Y5USeKTKCgE3XJ+w4hTRWeEwaAWw9HJqX4=,tag:qVmVvX9jYT3fgw4+C/Osbw==,type:str]
version: 3.13.1
-12
View File
@@ -1,12 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: node-red
namespace: node-red
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: local-path
-13
View File
@@ -1,13 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: node-red
namespace: node-red
spec:
selector:
app: node-red
ports:
- protocol: TCP
port: 1880
targetPort: 1880
type: ClusterIP
@@ -1,2 +0,0 @@
**
!.gitignore
@@ -1,16 +0,0 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: node-red
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: casa
namespace: casa-limbosolutions-com
path: services/node-red/deploy/app
prune: true
decryption:
provider: sops
secretRef:
name: flux-sops-age
@@ -1,11 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: node-red
resources:
- app-sync.yaml
secretGenerator:
- name: flux-sops-age
files:
- "age.agekey=./.env.d/age.agekey"
generatorOptions:
disableNameSuffixHash: true
@@ -1,3 +0,0 @@
#!/bin/bash
set -e
kubectl kustomize ./deploy/flux | kubectl apply -f -
-13
View File
@@ -1,13 +0,0 @@
# replicator
Kubernetes Replicator (mittwald/kubernetesreplicator) is a lightweight controller that automatically copies Secrets and ConfigMaps between namespaces. It is ideal for sharing resources like wildcard TLS certificates generated by certmanager across multiple namespaces without manual copying.
Replicator watches for annotations on a source Secret and keeps synchronized copies updated in the target namespaces. It preserves custom metadata and removes certmanagerspecific annotations from the replicated secrets to avoid conflicts. When certmanager renews a certificate, Replicator automatically updates all replicated copies.
## Setup
Using flux for reconciliation.
``` bash
kubectl kustomize deploy/flux | kubectl apply -f -
```
@@ -1,15 +0,0 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: replicator
spec:
releaseName: replicator
interval: 40h
chart:
spec:
chart: kubernetes-replicator
version: 2.x.x
sourceRef:
kind: HelmRepository
name: replicator
interval: 40h
@@ -1,7 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: replicator
spec:
interval: 40h
url: https://helm.mittwald.de
@@ -1,6 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: replicator
resources:
- helm-repo.yaml
- helm-release.yaml
@@ -1,12 +0,0 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: replicator
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: casa
namespace: casa-limbosolutions-com
path: services/replicator/deploy/app
prune: true
@@ -1,5 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: replicator
resources:
- app-sync.yaml
@@ -1,11 +0,0 @@
creation_rules:
# encrypt all values from file
- path_regex: \.dec\.yaml$
encrypted_regex: '^(.*)$'
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
# encrypt secrets files
- path_regex: .*.yaml
encrypted_regex: ^(data|stringData)$
age:
- age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
@@ -1,17 +0,0 @@
# storage-limbosolutions-com
<https://github.com/seaweedfs/seaweedfs-csi-driver>
## Setup
Using flux for reconciliation.
``` bash
./ops-scripts/apply-flux.sh
```
**Encrypt secrets:**
``` bash
sops -e deploy/app/helm-values.private.dec.yaml > deploy/app/helm-values.private.yaml
```
@@ -1,22 +0,0 @@
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: storage-limbosolutions-com-seaweedfs-csi-driver
spec:
releaseName: storage-limbosolutions-com-seaweedfs-csi-driver
interval: 40h
chart:
spec:
chart: seaweedfs-csi-driver
version: 0.2.23
sourceRef:
kind: HelmRepository
name: seaweedfs-csi-driver
interval: 40h
valuesFrom:
- kind: Secret
name: seaweedfs-csi-helm-values
valuesKey: values.yaml
- kind: Secret
name: seaweedfs-csi-helm-values
valuesKey: values.private.yaml
@@ -1,7 +0,0 @@
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: seaweedfs-csi-driver
spec:
interval: 40h
url: https://seaweedfs.github.io/seaweedfs-csi-driver/helm
@@ -1,16 +0,0 @@
seaweedfsFiler: ENC[AES256_GCM,data:NkXmSvxU0i4HmwzXi3X31pY=,iv:hk8W9Yo7SG4TZKjNwhC8Ov70K9sa0I9ddiX6YZt+uIM=,tag:SDPqLpvW7UjQUr1jLVB0AA==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUOGtiaWhmZ0p6Z29HdGVX
OGM1NGlZV1c2M3psZTdNOVVVYzBHak1HVVV3CjZFYXpudDdlTHBnekwvQ2NqcnVW
cE9LRk5mYnBYZkphc0ZzRjFMdVBuZjAKLS0tIGUvUSswZzlTRTRPWExTOTdPQlps
RUhBc280ODVjaFgyYi91d2U2WEtoS0EKk5PrgsSWWfCkwg+I7nIPY2dmOkLuOME4
RGO+MgqmlJIkw0c3sE0HnEjsbJm/QNClHPPVG+DvG1+2Hmw/iHBitQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1f9e4pvp5y8gzuk8mz2s5xm85dd7znxhk56tcpuxqwn78qfjwja0qekwlju
encrypted_regex: ^(.*)$
lastmodified: "2026-06-07T22:11:46Z"
mac: ENC[AES256_GCM,data:4Evu7sdJuy6aRw58/qQkxY9HzDHcREfOklzjc43PASrMjXrfgwzFJVGZ2KAIHlQtLPMgrdRaxHV+u0XQ6pMiGvfzJg2q3IYQOA9SqyeKAnvOsIjWcKnIzRkvhiEC3RCsOxm4dR1dFiITz/0exiCs2E3AFAdo2H4cC7joA7AQFYk=,iv:550SS2OnNvtoP9ERlI0IYeDRY93zNpUAKKNrrrDKJb0=,tag:MBs8CguK+51AxRfHiOoUgA==,type:str]
version: 3.13.1
@@ -1,15 +0,0 @@
storageClassName: storage-limbosolutions-com
storageClassVolumeBindingMode: Immediate
isDefaultStorageClass: false
tlsSecret: ""
driverName: storage-limbosolutions-com-csi-driver
mountService:
enabled: true
image: chrislusf/seaweedfs-mount
# problems with latest version of mounter on helm version 0.2.15
tag: v1.4.4
seaweedfsCsiPlugin:
image: chrislusf/seaweedfs-csi-driver
# problems with latest version of mounter on helm version 0.2.15
tag: v1.4.4
@@ -1,13 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: storage-limbosolutions-com
resources:
- helm-repo.yaml
- helm-release.yaml
secretGenerator:
- name: seaweedfs-csi-helm-values
files:
- values.yaml=helm-values.yaml
- values.private.yaml=helm-values.private.yaml
generatorOptions:
disableNameSuffixHash: true

Some files were not shown because too many files have changed in this diff Show More