Compare commits

...

14 Commits

72 changed files with 3006 additions and 401 deletions

50
proxmox/homeassistant/.gitignore vendored Normal file
View File

@@ -0,0 +1,50 @@
# Created by https://gitignore.org
# Terraform.gitignore
# Local .terraform directories
.terraform/
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Ignore transient lock info files created by terraform apply
.terraform.tfstate.lock.info
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc
# Optional: ignore graph output files generated by `terraform graph`
# *.dot
# Optional: ignore plan files saved before destroying Terraform configuration
# Uncomment the line below if you want to ignore planout files.
# planout
aircon.json

View File

@@ -0,0 +1,44 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/bpg/proxmox" {
version = "0.86.0"
constraints = "0.86.0"
hashes = [
"h1:0OH908XIuDk42UTevFCfMMEnDdbsqNzSZBLGqjoj8S0=",
"zh:09b627b92a59848769fadfc3d8103eebf070a3800144bf03cb93f44472327f44",
"zh:0e19eb7f1047d541e50b97d7ac440ea73685d0c28ed2dbe64217cbe2f0b353e0",
"zh:20f1e70091ff3056876618c93afd79527c8995f955d153993e8fbb10fa42593b",
"zh:3920315be565976f5a9da0803f8f1a108221282f1bc9e21160669d793af4e0c8",
"zh:5133b2a2027428d3926eaa3bcdc0ab65a75305d54f6cbc7c54cce746dfddbc8e",
"zh:514c588b04738d55c9e6b1c5a4e3fb1ef4041dfb809d2268f14d29839ecfba59",
"zh:55916034025b4833bd6a93bb5948dfb7d00830a772ef74fa70898c6f7de0da0b",
"zh:58b485a4b0bde56ca7032fca0ac09cb4c6ff2579e06cf4f2a311bb695baa0df1",
"zh:75ebe44e6da4108af5fe02a9cd99ed0189985b486a2a56594952098d161ceb3d",
"zh:a8c870bfb5958a3d49d639db3c2761cfb453c6a6f95e5e241890922b11c8a4d8",
"zh:c2df2748b9be47a6c3e613667c64874d5cb1d3fbb5b985d6eb9c3af5af298454",
"zh:c3059668f4f81e450e555a47310e7042044b335f131643262fd51f9ba96f2214",
"zh:ddbbb23910666f70cf4a9587ba57b45f5f58c53a1f8d7cee1d6f90a3d3ef38ef",
"zh:e430138b897edcd3b64e4309db34ac872526187782626aa074d8d1647a0abfa8",
"zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597",
]
}
provider "registry.terraform.io/hashicorp/local" {
version = "2.5.3"
hashes = [
"h1:1Nkh16jQJMp0EuDmvP/96f5Unnir0z12WyDuoR6HjMo=",
"zh:284d4b5b572eacd456e605e94372f740f6de27b71b4e1fd49b63745d8ecd4927",
"zh:40d9dfc9c549e406b5aab73c023aa485633c1b6b730c933d7bcc2fa67fd1ae6e",
"zh:6243509bb208656eb9dc17d3c525c89acdd27f08def427a0dce22d5db90a4c8b",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:885d85869f927853b6fe330e235cd03c337ac3b933b0d9ae827ec32fa1fdcdbf",
"zh:bab66af51039bdfcccf85b25fe562cbba2f54f6b3812202f4873ade834ec201d",
"zh:c505ff1bf9442a889ac7dca3ac05a8ee6f852e0118dd9a61796a2f6ff4837f09",
"zh:d36c0b5770841ddb6eaf0499ba3de48e5d4fc99f4829b6ab66b0fab59b1aaf4f",
"zh:ddb6a407c7f3ec63efb4dad5f948b54f7f4434ee1a2607a49680d494b1776fe1",
"zh:e0dafdd4500bec23d3ff221e3a9b60621c5273e5df867bc59ef6b7e41f5c91f6",
"zh:ece8742fd2882a8fc9d6efd20e2590010d43db386b920b2a9c220cfecc18de47",
"zh:f4c6b3eb8f39105004cf720e202f04f57e3578441cfb76ca27611139bc116a82",
]
}

View File

@@ -0,0 +1,98 @@
# Home Assistant Installation
These files allow you to deploy a Home Assistant OS virtual machine on Proxmox using Terraform.
Terraform handles the creation of the VM based on the pre-built `.qcow2` image of Home Assistant OS.
All further configuration (such as the proxy settings) is done directly from the Home Assistant web interface.
## Terraform Execution
To create the VM with Terraform, the configuration must be defined in the `terraform.tfvars` file.
You can use `terraform.tfvars.example` as a base.
Then run the following commands:
1. Initialize Terraform:
```bash
terraform init
```
2. Review the plan:
```bash
terraform plan
```
3. Apply the plan:
```bash
terraform apply
```
The process will create a new VM on the configured Proxmox node using the uploaded `.qcow2` image.
Once created, Home Assistant OS will boot automatically and obtain an IP via DHCP.
Access the web interface at:
[http://homeassistant.local:8123](http://homeassistant.local:8123)
That should work given that Pi-hole is already runing on the network
## Home Assistant Configuration
After the initial setup (creating your user and restoring backups if applicable),
you must adjust the HTTP configuration to properly support a reverse proxy such as Traefik.
To edit Home Assistants configuration file `configuration.yaml`, first install the File Editor add-on:
1. Open the Home Assistant web interface.
2. Go to `Settings` -> `Add-ons` -> `Add-on Store`.
3. Search for File Editor and click Install.
4. Once installed, click Start and optionally enable Show in sidebar.
Then use the File Editor to open `/config/configuration.yaml`
Add the following section
```yaml
http:
use_x_forwarded_for: true
trusted_proxies:
- "192.168.0.0/16"
```
Finally:
1. Go to `Settings` -> `System` -> `Check configuration` to validate the file.
2. Restart Home Assistant Core via `Settings` -> `System` -> `Restart`.
This ensures Home Assistant correctly interprets requests forwarded through your proxy, preserving real client IPs and maintaining secure access.
## AC Integraion
To control the air conditioner that uses the NetHome Plus app, install HACS (Home Assistant Community Store) and the Midea AC LAN integration.
### Step 1 - Install HACS
Follow the documentation at [HACS](https://hacs.xyz/docs/use/)
### Step 2 — Install Midea AC LAN Integration
Follow the documentation at [midea_ac_lan](https://github.com/wuwentao/midea_ac_lan/tree/master)
> Important: recent Midea / NetHome Plus API changes limit how tokens can be obtained.
> Keep a backup file containing your current tokens — it will be necessary if API access becomes restricted in the future.
> Tokens can be found via SSH at: `/config/.storage/midea_ac_lan`
## Reinstallation
If a full reinstall is needed, simply destroy and recreate the Terraform resources:
```bash
terraform destroy
```
Then run:
```bash
terraform apply
```
to provision a clean instance again.

View File

@@ -0,0 +1,58 @@
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "0.86.0"
}
}
}
data "local_file" "proxmox_ssh_private_key" {
filename = var.proxmox_ssh_privkey_path
}
provider "proxmox" {
endpoint = var.proxmox_endpoint
username = var.proxmox_user
password = var.proxmox_password
insecure = true
ssh {
agent = true
username = var.proxmox_ssh_username
private_key = trimspace(data.local_file.proxmox_ssh_private_key.content)
}
}
resource "proxmox_virtual_environment_vm" "homeassistant" {
name = "homeassistant"
node_name = var.proxmox_node
agent { enabled = true }
bios = "ovmf"
cpu {
cores = 2
type = "host"
}
memory {
dedicated = 8096
}
efi_disk {
datastore_id = var.vm_datastore
}
disk {
datastore_id = var.vm_datastore
import_from = "${var.proxmox_datastore}:import/haos_ova-16.3.qcow2"
interface = "virtio0"
size = 100
}
network_device {
bridge = var.bridge
}
}

View File

@@ -0,0 +1,7 @@
proxmox_endpoint = "https://192.168.1.1:8006"
proxmox_user = "terraform@pam"
proxmox_password = "secret"
proxmox_node = "pve"
proxmox_ssh_username = "terraform"
proxmox_ssh_privkey_path = "/home/user/.ssh/id_ed25519"

View File

@@ -0,0 +1,11 @@
variable "proxmox_endpoint" {}
variable "proxmox_user" {}
variable "proxmox_password" { sensitive = true }
variable "proxmox_node" { default = "pve" }
variable "proxmox_ssh_username" {}
variable "proxmox_ssh_privkey_path" {}
variable "proxmox_datastore" { default = "local" }
variable "bridge" { default = "vmbr0" }
variable "vm_datastore" { default = "local-vm" }

58
proxmox/pihole/README.md Normal file
View File

@@ -0,0 +1,58 @@
# Pi-hole instalation
These files allow you to install Pi-hole in an idempotent way. Terraform creates
the VM on Proxmox, and Ansible installs Pi-hole unattended, using the configuration
defined in `pihole.toml`.
## Terraform execution
To create the VM with Terraform, the configuration must be defined in the `terraform.tfvars`
file. You can use `terraform.tfvars.example` as a base.
Then to execute the following commands:
1. Intialize terraform
```bash
terraform init
```
2. Review the plan
```bash
terraform plan
```
3. Apply the plan.
This step might take a few minutes but if it takes significantly longer,
there may be an issue with cloud-init.
```bash
terraform apply
```
After execution, the `ansible` folder should contain a new `inventory.yaml` file.
## Ansible execution
To install Pi-hole with Ansible, make sure the `inventory.yaml` file exists,
and adjust `pihole.toml` if needed.
Then run:
```bash
ansible-playbook install.yaml
```
## Reinstallation
If you need to reinstall everything in the same environment,
destroy and recreate the Terraform resources using:
```bash
terraform destroy
```
## Reference
[Unattended Pi-hole v6 Setup with Ansible](https://www.paulcourt.co.uk/articles/2025/unattended-pihole-ansible)
[Configure a VM with Cloud-Init](https://registry.terraform.io/providers/bpg/proxmox/latest/docs/guides/cloud-init)

1
proxmox/pihole/ansible/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
pihole.toml

View File

@@ -0,0 +1,3 @@
[defaults]
inventory = ./inventory.yaml
host_key_checking = False

View File

@@ -0,0 +1,38 @@
- name: Install Pihole
hosts: all
become: true
tasks:
- name: Update packages
apt:
update_cache: true
upgrade: safe
- name: Install curl
apt:
name: curl
- name: Create pihole directory
file:
path: /etc/pihole
state: directory
force: false
- name: Load pihole pre-configuration
copy:
src: pihole.toml
dest: /etc/pihole/pihole.toml
- name: Download install script
get_url:
url: https://install.pi-hole.net
dest: /tmp/install_pihole.sh
mode: "0755"
- name: Install pihole
command: /tmp/install_pihole.sh --unattended
args:
creates: "/usr/local/bin/pihole"
- name: Update gravity lists
command: pihole -g

View File

@@ -0,0 +1,8 @@
all:
children:
servers:
hosts:
pihole:
ansible_host: 192.168.3.1
ansible_user: ubuntu
ansible_ssh_private_key_file: /home/ryuuji/.ssh/id_ed25519

File diff suppressed because it is too large Load Diff

47
proxmox/pihole/terraform/.gitignore vendored Normal file
View File

@@ -0,0 +1,47 @@
# Created by https://gitignore.org
# Terraform.gitignore
# Local .terraform directories
.terraform/
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Ignore transient lock info files created by terraform apply
.terraform.tfstate.lock.info
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc
# Optional: ignore graph output files generated by `terraform graph`
# *.dot
# Optional: ignore plan files saved before destroying Terraform configuration
# Uncomment the line below if you want to ignore planout files.
# planout

View File

@@ -0,0 +1,44 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/bpg/proxmox" {
version = "0.86.0"
constraints = "0.86.0"
hashes = [
"h1:0OH908XIuDk42UTevFCfMMEnDdbsqNzSZBLGqjoj8S0=",
"zh:09b627b92a59848769fadfc3d8103eebf070a3800144bf03cb93f44472327f44",
"zh:0e19eb7f1047d541e50b97d7ac440ea73685d0c28ed2dbe64217cbe2f0b353e0",
"zh:20f1e70091ff3056876618c93afd79527c8995f955d153993e8fbb10fa42593b",
"zh:3920315be565976f5a9da0803f8f1a108221282f1bc9e21160669d793af4e0c8",
"zh:5133b2a2027428d3926eaa3bcdc0ab65a75305d54f6cbc7c54cce746dfddbc8e",
"zh:514c588b04738d55c9e6b1c5a4e3fb1ef4041dfb809d2268f14d29839ecfba59",
"zh:55916034025b4833bd6a93bb5948dfb7d00830a772ef74fa70898c6f7de0da0b",
"zh:58b485a4b0bde56ca7032fca0ac09cb4c6ff2579e06cf4f2a311bb695baa0df1",
"zh:75ebe44e6da4108af5fe02a9cd99ed0189985b486a2a56594952098d161ceb3d",
"zh:a8c870bfb5958a3d49d639db3c2761cfb453c6a6f95e5e241890922b11c8a4d8",
"zh:c2df2748b9be47a6c3e613667c64874d5cb1d3fbb5b985d6eb9c3af5af298454",
"zh:c3059668f4f81e450e555a47310e7042044b335f131643262fd51f9ba96f2214",
"zh:ddbbb23910666f70cf4a9587ba57b45f5f58c53a1f8d7cee1d6f90a3d3ef38ef",
"zh:e430138b897edcd3b64e4309db34ac872526187782626aa074d8d1647a0abfa8",
"zh:f26e0763dbe6a6b2195c94b44696f2110f7f55433dc142839be16b9697fa5597",
]
}
provider "registry.terraform.io/hashicorp/local" {
version = "2.5.3"
hashes = [
"h1:1Nkh16jQJMp0EuDmvP/96f5Unnir0z12WyDuoR6HjMo=",
"zh:284d4b5b572eacd456e605e94372f740f6de27b71b4e1fd49b63745d8ecd4927",
"zh:40d9dfc9c549e406b5aab73c023aa485633c1b6b730c933d7bcc2fa67fd1ae6e",
"zh:6243509bb208656eb9dc17d3c525c89acdd27f08def427a0dce22d5db90a4c8b",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:885d85869f927853b6fe330e235cd03c337ac3b933b0d9ae827ec32fa1fdcdbf",
"zh:bab66af51039bdfcccf85b25fe562cbba2f54f6b3812202f4873ade834ec201d",
"zh:c505ff1bf9442a889ac7dca3ac05a8ee6f852e0118dd9a61796a2f6ff4837f09",
"zh:d36c0b5770841ddb6eaf0499ba3de48e5d4fc99f4829b6ab66b0fab59b1aaf4f",
"zh:ddb6a407c7f3ec63efb4dad5f948b54f7f4434ee1a2607a49680d494b1776fe1",
"zh:e0dafdd4500bec23d3ff221e3a9b60621c5273e5df867bc59ef6b7e41f5c91f6",
"zh:ece8742fd2882a8fc9d6efd20e2590010d43db386b920b2a9c220cfecc18de47",
"zh:f4c6b3eb8f39105004cf720e202f04f57e3578441cfb76ca27611139bc116a82",
]
}

View File

@@ -0,0 +1,127 @@
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "0.86.0"
}
}
}
data "local_file" "ssh_public_key" {
filename = var.ssh_pubkey_path
}
data "local_file" "proxmox_ssh_private_key" {
filename = var.proxmox_ssh_privkey_path
}
provider "proxmox" {
endpoint = var.proxmox_endpoint
username = var.proxmox_user
password = var.proxmox_password
insecure = true
ssh {
agent = true
username = var.proxmox_ssh_username
private_key = trimspace(data.local_file.proxmox_ssh_private_key.content)
}
}
resource "proxmox_virtual_environment_download_file" "ubuntu_cloud_image" {
content_type = "import"
datastore_id = var.proxmox_datastore
node_name = var.proxmox_node
url = "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
file_name = "noble-server-cloudimg-amd64.qcow2"
}
resource "proxmox_virtual_environment_file" "user_data_cloud_config" {
content_type = "snippets"
datastore_id = var.proxmox_datastore
node_name = var.proxmox_node
source_raw {
data = <<-EOF
#cloud-config
hostname: ${var.vm_name}
timezone: America/Santiago
users:
- default
- name: ubuntu
groups:
- sudo
shell: /bin/bash
ssh_authorized_keys:
- ${trimspace(data.local_file.ssh_public_key.content)}
sudo: ALL=(ALL) NOPASSWD:ALL
package_update: true
packages:
- qemu-guest-agent
- net-tools
- curl
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
- echo "done" > /tmp/cloud-config.done
EOF
file_name = "user-data-cloud-config.yaml"
}
}
resource "proxmox_virtual_environment_vm" "pihole" {
name = var.vm_name
node_name = var.proxmox_node
agent { enabled = true }
cpu {
cores = 1
type = "host"
}
memory {
dedicated = 2048
}
disk {
datastore_id = var.vm_datastore
import_from = proxmox_virtual_environment_download_file.ubuntu_cloud_image.id
interface = "virtio0"
iothread = true
discard = "on"
size = 20
}
initialization {
datastore_id = var.vm_datastore
ip_config {
ipv4 {
address = "${var.vm_address}/${var.vm_cidr}"
gateway = var.vm_gateway
}
}
user_data_file_id = proxmox_virtual_environment_file.user_data_cloud_config.id
}
network_device {
bridge = var.bridge
}
}
resource "local_file" "ansible_inventory" {
filename = "${path.module}/../ansible/inventory.yaml"
content = <<-YAML
all:
children:
servers:
hosts:
${var.vm_name}:
ansible_host: ${var.vm_address}
ansible_user: ubuntu
ansible_ssh_private_key_file: ${var.ssh_privkey_path}
YAML
depends_on = [proxmox_virtual_environment_vm.pihole]
}

View File

@@ -0,0 +1,14 @@
proxmox_endpoint = "https://192.168.1.1:8006"
proxmox_user = "terraform@pam"
proxmox_password = "secret"
proxmox_node = "pve"
proxmox_ssh_username = "terraform"
proxmox_ssh_privkey_path = "/home/user/.ssh/id_ed25519"
ssh_pubkey_path = "/home/user/.ssh/id_ed25519.pub"
ssh_privkey_path = "/home/user/.ssh/id_ed25519"
vm_address = "192.168.3.1"
vm_cidr = "16"
vm_gateway = "192.168.1.1"

View File

@@ -0,0 +1,19 @@
variable "proxmox_endpoint" {}
variable "proxmox_user" {}
variable "proxmox_password" { sensitive = true }
variable "proxmox_node" { default = "pve" }
variable "proxmox_ssh_username" {}
variable "proxmox_ssh_privkey_path" {}
variable "proxmox_datastore" { default = "local" }
variable "vm_name" { default = "pihole" }
variable "vm_datastore" { default = "local-vm" }
variable "vm_address" {}
variable "vm_cidr" {}
variable "vm_gateway" {}
variable "ssh_pubkey_path" {}
variable "ssh_privkey_path" {}
variable "bridge" { default = "vmbr0" }

3
stacks/.gitignore vendored
View File

@@ -1,2 +1 @@
*.env .env
!*.env.example

View File

@@ -1,12 +0,0 @@
services:
actual_server:
image: ghcr.io/actualbudget/actual:latest
restart: unless-stopped
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/actual:/data
networks:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.13
networks:
macvlan_192_168_3_0:
external: true

View File

@@ -0,0 +1 @@
DATA_DIR="./data"

View File

@@ -0,0 +1,15 @@
services:
actual_server:
labels:
- "traefik.enable=true"
- "traefik.http.routers.actual-web.rule=Host(`actual.skrd.fun`)"
- "traefik.http.routers.actual-web.entrypoints=web"
- "traefik.http.routers.actual-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.actual.rule=Host(`actual.skrd.fun`)"
- "traefik.http.routers.actual.entrypoints=websecure"
- "traefik.http.routers.actual.tls.certresolver=cf"
- "traefik.http.services.actual.loadbalancer.server.port=5006"
networks:
default:
name: traefik
external: true

View File

@@ -0,0 +1,6 @@
services:
actual_server:
image: ghcr.io/actualbudget/actual:v26.2.0
restart: unless-stopped
volumes:
- ${DATA_DIR}:/data

2
stacks/ddns/.env.example Normal file
View File

@@ -0,0 +1,2 @@
API_TOKEN=secret
DOMAINS=

12
stacks/ddns/compose.yml Normal file
View File

@@ -0,0 +1,12 @@
services:
cloudflare-ddns:
image: favonia/cloudflare-ddns:1.15.1
restart: always
user: "1000:1000"
read_only: true
cap_drop: [all]
security_opt: [no-new-privileges:true]
environment:
CLOUDFLARE_API_TOKEN: ${API_TOKEN}
DOMAINS: ${DOMAINS}
PROXIED: false

View File

@@ -1,12 +0,0 @@
services:
gametabs:
image: nginx
restart: unless-stopped
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/gametabs:/usr/share/nginx/html
networks:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.6
networks:
macvlan_192_168_3_0:
external: true

View File

@@ -0,0 +1 @@
DATA_DIR=./gametabs

View File

@@ -0,0 +1,16 @@
services:
gametabs:
labels:
- "traefik.enable=true"
- "traefik.http.routers.gametabs-web.rule=Host(`gametabs.skrd.fun`)"
- "traefik.http.routers.gametabs-web.entrypoints=web"
- "traefik.http.routers.gametabs-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.gametabs.rule=Host(`gametabs.skrd.fun`)"
- "traefik.http.routers.gametabs.entrypoints=websecure"
- "traefik.http.routers.gametabs.tls.certresolver=cf"
- "traefik.http.services.gametabs.loadbalancer.server.port=80"
networks:
default:
name: traefik
external: true

View File

@@ -0,0 +1,6 @@
services:
gametabs:
image: nginx
restart: unless-stopped
volumes:
- ${DATA_DIR}:/usr/share/nginx/html

View File

@@ -1,11 +0,0 @@
USER_UID=1000
USER_GID=1000
CONFIG_FILE=/config/config.yaml
GITEA_INSTANCE_URL=https://git.skrd.fun
GITEA_RUNNER_REGISTRATION_TOKEN=secret
GITEA_RUNNER_NAME=gitea-runner-1
POSTGRES_PASSWORD=secret
POSTGRES_DB=gitea
POSTGRES_USER=gitea

View File

@@ -1,46 +0,0 @@
services:
gitea:
image: gitea/gitea:latest
restart: unless-stopped
env_file:
- gitea.env
networks:
gitea_network:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.3
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/gitea/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
- gitea-db
runner:
image: gitea/act_runner:latest
restart: unless-stopped
env_file:
- gitea.env
networks:
- gitea_network
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/gitea/runner/config:/config
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/gitea/runner/data:/data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- gitea
gitea-db:
image: postgres:16
restart: unless-stopped
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/gitea/db:/var/lib/postgresql/data
networks:
- gitea_network
env_file:
- gitea.env
networks:
gitea_network:
macvlan_192_168_3_0:
external: true

12
stacks/gitea/.env.example Normal file
View File

@@ -0,0 +1,12 @@
DATA_ROOT="./gitea"
USER_UID=1000
USER_GID=1000
GITEA_RUNNER_REGISTRATION_TOKEN=sercret
POSTGRES_PASSWORD=secret
POSTGRES_DB=gitea
POSTGRES_USER=gitea
INSTANCE_URL="https://gitea.skrd.fun"

View File

@@ -0,0 +1,30 @@
services:
gitea:
networks:
- internal
- proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.gitea-web.rule=Host(`git.skrd.fun`)"
- "traefik.http.routers.gitea-web.entrypoints=web"
- "traefik.http.routers.gitea-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.gitea.rule=Host(`git.skrd.fun`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver=cf"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
runner:
networks:
- internal
gitea-db:
networks:
- internal
networks:
internal:
name: gitea
proxy:
name: traefik
external: true

38
stacks/gitea/compose.yml Normal file
View File

@@ -0,0 +1,38 @@
services:
gitea:
image: gitea/gitea:1.25.4
restart: unless-stopped
environment:
USER_UID: ${USER_UID}
USER_GID: ${USER_GID}
volumes:
- ${DATA_ROOT}/data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
- gitea-db
runner:
image: gitea/act_runner:0.2.13
restart: unless-stopped
environment:
CONFIG_FILE: /config/config.yaml
GITEA_INSTANCE_URL: "${INSTANCE_URL}"
GITEA_RUNNER_NAME: "gitea-runner-1"
GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_REGISTRATION_TOKEN}"
volumes:
- ${DATA_ROOT}/runner/config:/config
- ${DATA_ROOT}/runner/data:/data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- gitea
gitea-db:
image: postgres:16
restart: unless-stopped
volumes:
- ${DATA_ROOT}/db:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: "${POSTGRES_DB}"
POSTGRES_USER: "${POSTGRES_USER}"

View File

@@ -1,8 +0,0 @@
DB_PASSWORD=secret
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
POSTGRES_PASSWORD=secret
POSTGRES_USER=postgres
POSTGRES_DB=immich
POSTGRES_INITDB_ARGS='--data-checksums'

View File

@@ -1,53 +0,0 @@
services:
immich-server:
image: ghcr.io/immich-app/immich-server:release
restart: unless-stopped
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/immich/upload:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
networks:
immich_network:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.12
env_file:
- immich.env
depends_on:
- redis
- database
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:release
restart: unless-stopped
networks:
immich_network:
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/immich/model-cache:/cache
redis:
image: docker.io/redis:6.2-alpine@sha256:328fe6a5822256d065debb36617a8169dbfbd77b797c525288e465f56c1d392b
restart: unless-stopped
networks:
immich_network:
healthcheck:
test: redis-cli ping || exit 1
database:
image: docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0
restart: unless-stopped
networks:
immich_network:
env_file:
- immich.env
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/immich/postgres:/var/lib/postgresql/data
healthcheck:
test: pg_isready --dbname='immich' --username='postgres' || exit 1; Chksum="$$(psql --dbname='immich' --username='postgres' --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')"; echo "checksum failure count is $$Chksum"; [ "$$Chksum" = '0' ] || exit 1
interval: 5m
start_interval: 30s
start_period: 5m
command: ["postgres", "-c" ,"shared_preload_libraries=vectors.so", "-c", 'search_path="$$user", public, vectors', "-c", "logging_collector=on", "-c", "max_wal_size=2GB", "-c", "shared_buffers=512MB", "-c", "wal_compression=on"]
networks:
immich_network:
macvlan_192_168_3_0:
external: true

View File

@@ -0,0 +1,9 @@
UPLOAD_LOCATION=./immich/upload
DB_DATA_LOCATION=./immich/postgres
TZ=America/Santiago
IMMICH_VERSION=v2
DB_PASSWORD=secret
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

View File

@@ -0,0 +1,34 @@
services:
immich-server:
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.immich-web.rule=Host(`photos.skrd.fun`)"
- "traefik.http.routers.immich-web.entrypoints=web"
- "traefik.http.routers.immich-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.immich.rule=Host(`photos.skrd.fun`)"
- "traefik.http.routers.immich.entrypoints=websecure"
- "traefik.http.routers.immich.tls.certresolver=cf"
- "traefik.http.services.immich.loadbalancer.server.port=2283"
networks:
- internal
- proxy
immich-machine-learning:
networks:
- internal
redis:
networks:
- internal
database:
networks:
- internal
networks:
internal:
name: immich
proxy:
name: traefik
external: true

49
stacks/immich/compose.yml Normal file
View File

@@ -0,0 +1,49 @@
services:
immich-server:
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
volumes:
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
depends_on:
- redis
- database
restart: unless-stopped
healthcheck:
disable: false
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
volumes:
- model-cache:/cache
env_file:
- .env
restart: always
healthcheck:
disable: false
redis:
image: docker.io/valkey/valkey:9@sha256:546304417feac0874c3dd576e0952c6bb8f06bb4093ea0c9ca303c73cf458f63
healthcheck:
test: redis-cli ping || exit 1
restart: always
database:
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: "--data-checksums"
DB_STORAGE_TYPE: "HDD"
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/immich2/extra:/tmp/extra
shm_size: 128mb
restart: always
healthcheck:
disable: false
volumes:
model-cache:

View File

@@ -1,19 +0,0 @@
services:
jellyfin:
image: jellyfin/jellyfin
restart: 'unless-stopped'
user: 1000:1000
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/jellyfin/config:/config
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/jellyfin/cache:/cache
- /srv/dev-disk-by-uuid-5392509c-5ccd-4d8f-8719-60064c4404d6/anime:/data/anime
- /srv/dev-disk-by-uuid-c7a96ee1-c08e-48b1-8afa-79c75380d142/movies:/data/movies
- /srv/dev-disk-by-uuid-c7a96ee1-c08e-48b1-8afa-79c75380d142/tv:/data/tv
environment:
- JELLYFIN_PublishedServerUrl=https://jelly.skrd.fun
networks:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.11
networks:
macvlan_192_168_3_0:
external: true

View File

@@ -0,0 +1,6 @@
DATA_ROOT="./data"
MEDIA_ANIME="./anime"
MEDIA_MOVIES="./movies"
MEDIA_TV="./tv"
SERVER_URL="localhost"

View File

@@ -0,0 +1,15 @@
services:
jellyfin:
labels:
- "traefik.enable=true"
- "traefik.http.routers.jellyfin-web.rule=Host(`jelly.skrd.fun`)"
- "traefik.http.routers.jellyfin-web.entrypoints=web"
- "traefik.http.routers.jellyfin-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.jellyfin.rule=Host(`jelly.skrd.fun`)"
- "traefik.http.routers.jellyfin.entrypoints=websecure"
- "traefik.http.routers.jellyfin.tls.certresolver=cf"
- "traefik.http.services.jellyfin.loadbalancer.server.port=8096"
networks:
default:
name: traefik
external: true

View File

@@ -0,0 +1,13 @@
services:
jellyfin:
image: jellyfin/jellyfin:10
restart: "unless-stopped"
user: 1000:1000
volumes:
- ${DATA_ROOT}/config:/config
- ${DATA_ROOT}/cache:/cache
- ${MEDIA_ANIME}:/data/anime
- ${MEDIA_MOVIES}:/data/movies
- ${MEDIA_TV}:/data/tv
environment:
- JELLYFIN_PublishedServerUrl=${SERVER_URL}

View File

@@ -0,0 +1,2 @@
DATA_ROOT="/srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker"
MEDIA_BOOKS="/srv/dev-disk-by-uuid-5392509c-5ccd-4d8f-8719-60064c4404d6/books"

View File

@@ -0,0 +1,16 @@
services:
kavita:
labels:
- "traefik.enable=true"
- "traefik.http.routers.books-web.rule=Host(`books.skrd.fun`)"
- "traefik.http.routers.books-web.entrypoints=web"
- "traefik.http.routers.books-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.books.rule=Host(`books.skrd.fun`)"
- "traefik.http.routers.books.entrypoints=websecure"
- "traefik.http.routers.books.tls.certresolver=cf"
- "traefik.http.services.books.loadbalancer.server.port=5000"
networks:
default:
name: traefik
external: true

View File

@@ -0,0 +1,7 @@
services:
kavita:
image: jvmilazz0/kavita:0.7.8
restart: unless-stopped
volumes:
- "${MEDIA_BOOKS}:/books"
- "${DATA_ROOT}/kavita/config:/kavita/config"

View File

@@ -0,0 +1,11 @@
POSTGRES_USER="miniflux"
POSTGRES_PASSWORD="secret"
POSTGRES_DB="miniflux"
DATA_DIR="./database"
DATABASE_URL="postgres://miniflux:secret@db/miniflux?sslmode=disable"
ADMIN_USERNAME="ryuuji"
ADMIN_PASSWORD="secret"
BASE_URL="https://rss.skrd.fun"

View File

@@ -0,0 +1,25 @@
services:
miniflux:
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.rss-web.rule=Host(`rss.skrd.fun`)"
- "traefik.http.routers.rss-web.entrypoints=web"
- "traefik.http.routers.rss-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.rss.rule=Host(`rss.skrd.fun`)"
- "traefik.http.routers.rss.entrypoints=websecure"
- "traefik.http.routers.rss.tls.certresolver=cf"
- "traefik.http.services.rss.loadbalancer.server.port=8080"
networks:
- internal
- proxy
db:
networks:
- internal
networks:
internal:
name: miniflux
proxy:
name: traefik
external: true

View File

@@ -0,0 +1,25 @@
services:
miniflux:
image: miniflux/miniflux:2.2.17
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: ${DATABASE_URL}
RUN_MIGRATIONS: 1
CREATE_ADMIN: 1
ADMIN_USERNAME: ${ADMIN_USERNAME}
ADMIN_PASSWORD: ${ADMIN_PASSWORD}
BASE_URL: ${BASE_URL}
db:
image: postgres:18
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- ${DATA_DIR}:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}"]
interval: 10s
start_period: 30s

View File

@@ -1,63 +0,0 @@
APP_NAME=Moka
APP_ENV=production
APP_KEY=secret
APP_DEBUG=false
APP_URL=https://moka.skrd.fun
APP_LOCALE=es
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
HTTPS=on
PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=pgsql
DB_HOST=pgsql
DB_PORT=5432
DB_DATABASE=moka
DB_USERNAME=moka
DB_PASSWORD=secret
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
OCTANE_SERVER=frankenphp

View File

@@ -1,121 +0,0 @@
services:
moka:
image: git.skrd.fun/skrd/moka:v0.3.9.1
restart: unless-stopped
env_file:
- moka.env
environment:
- SERVICE=server
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/moka:/app/storage
depends_on:
redis:
condition: service_healthy
pgsql:
condition: service_healthy
networks:
moka_network:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.19
init: true
healthcheck:
test: [ "CMD-SHELL", "curl -fsS http://localhost:8000/up >/dev/null || exit 1" ]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
schedule:
image: git.skrd.fun/skrd/moka:v0.3.9.1
restart: unless-stopped
env_file:
- moka.env
environment:
- SERVICE=schedule
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/moka:/app/storage
depends_on:
redis:
condition: service_healthy
pgsql:
condition: service_healthy
networks:
moka_network:
init: true
healthcheck:
test: [ "CMD-SHELL", "pgrep -f 'artisan schedule:work' >/dev/null || exit 1" ]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
queue:
image: git.skrd.fun/skrd/moka:v0.3.9.1
restart: unless-stopped
env_file:
- .env
environment:
- SERVICE=queue
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/moka:/app/storage
depends_on:
redis:
condition: service_healthy
pgsql:
condition: service_healthy
networks:
moka_network:
init: true
healthcheck:
test: [ "CMD-SHELL", "pgrep -f 'artisan queue:work' >/dev/null || exit 1" ]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
redis:
image: redis:alpine
restart: unless-stopped
volumes:
- redis_data:/data
networks:
moka_network:
healthcheck:
test: [ "CMD-SHELL", "redis-cli -h 127.0.0.1 ping | grep -q PONG" ]
interval: 3s
timeout: 3s
retries: 10
start_period: 5s
pgsql:
image: "postgres:18"
restart: unless-stopped
shm_size: 128mb
environment:
PGPASSWORD: "${DB_PASSWORD:-secret}"
POSTGRES_DB: "${DB_DATABASE}"
POSTGRES_USER: "${DB_USERNAME}"
POSTGRES_PASSWORD: "${DB_PASSWORD:-secret}"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
moka_network:
init: true
healthcheck:
test: [
"CMD-SHELL",
"pg_isready -h 127.0.0.1 -p 5432 -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-postgres}"
]
interval: 3s
timeout: 3s
retries: 10
start_period: 10s
volumes:
redis_data:
postgres_data:
networks:
moka_network:
macvlan_192_168_3_0:
external: true

View File

@@ -1,17 +0,0 @@
services:
navidrome:
image: deluan/navidrome:latest
user: 1000:1000
restart: unless-stopped
environment:
ND_BASEURL: "https:://navi.skrd.fun"
networks:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.10
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/navidrome:/data
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/music:/music:ro
networks:
macvlan_192_168_3_0:
external: true

View File

@@ -0,0 +1,4 @@
BASE_URL="http://localhost"
DATA_DIR="./data"
MEDIA_MUSIC="./music"

View File

@@ -0,0 +1,16 @@
services:
navidrome:
labels:
- "traefik.enable=true"
- "traefik.http.routers.navidrome-web.rule=Host(`navi.skrd.fun`)"
- "traefik.http.routers.navidrome-web.entrypoints=web"
- "traefik.http.routers.navidrome-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.navidrome.rule=Host(`navi.skrd.fun`)"
- "traefik.http.routers.navidrome.entrypoints=websecure"
- "traefik.http.routers.navidrome.tls.certresolver=cf"
- "traefik.http.services.navidrome.loadbalancer.server.port=4533"
networks:
default:
name: traefik
external: true

View File

@@ -0,0 +1,10 @@
services:
navidrome:
image: deluan/navidrome:0.60.3
user: 1000:1000
restart: unless-stopped
environment:
ND_BASEURL: ${BASE_URL}
volumes:
- ${DATA_DIR}:/data
- ${MEDIA_MUSIC}:/music:ro

View File

@@ -1,20 +0,0 @@
services:
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
environment:
- PUID=1000
- PGID=1000
- TZ=America/Santiago
- WEBUI_PORT=80
- TORRENTING_PORT=6881
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/qbittorrent:/config:/config
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/downloads:/downloads
restart: unless-stopped
networks:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.4
networks:
macvlan_192_168_3_0:
external: true

View File

@@ -0,0 +1,8 @@
DATA_DIR=./data
DOWNLOADS_DIR=./downloads
PUID=1000
PGID=1000
TZ=America/Santiago
WEBUI_PORT=80
TORRENTING_PORT=6881

View File

@@ -0,0 +1,15 @@
services:
qbittorrent:
labels:
- "traefik.enable=true"
- "traefik.http.routers.qbittorrent-web.rule=Host(`torrent.skrd.fun`)"
- "traefik.http.routers.qbittorrent-web.entrypoints=web"
- "traefik.http.routers.qbittorrent-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.qbittorrent.rule=Host(`torrent.skrd.fun`)"
- "traefik.http.routers.qbittorrent.entrypoints=websecure"
- "traefik.http.routers.qbittorrent.tls.certresolver=cf"
- "traefik.http.services.qbittorrent.loadbalancer.server.port=${WEBUI_PORT}"
networks:
default:
name: traefik
external: true

View File

@@ -0,0 +1,16 @@
services:
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:5.1.4
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- WEBUI_PORT=${WEBUI_PORT}
- TORRENTING_PORT=${TORRENTING_PORT}
ports:
- "${TORRENTING_PORT}:${TORRENTING_PORT}"
- "${TORRENTING_PORT}:${TORRENTING_PORT}/udp"
volumes:
- ${DATA_DIR}:/config
- ${DOWNLOADS_DIR}:/downloads
restart: unless-stopped

View File

@@ -0,0 +1,16 @@
services:
speedtest:
labels:
- "traefik.enable=true"
- "traefik.http.routers.speed-web.rule=Host(`speed.skrd.fun`)"
- "traefik.http.routers.speed-web.entrypoints=web"
- "traefik.http.routers.speed-web.middlewares=redirect-to-https@file"
- "traefik.http.routers.speed.rule=Host(`speed.skrd.fun`)"
- "traefik.http.routers.speed.entrypoints=websecure"
- "traefik.http.routers.speed.tls.certresolver=cf"
- "traefik.http.services.speed.loadbalancer.server.port=3000"
networks:
default:
name: traefik
external: true

View File

@@ -0,0 +1,4 @@
services:
speedtest:
image: openspeedtest/latest:v2.0.6
restart: unless-stopped

View File

@@ -0,0 +1,5 @@
DATA_ROOT="./data"
DYNAMIC_DIR="./dynamic"
CF_API_EMAIL=email@example.com
CF_DNS_API_TOKEN=secret

View File

@@ -0,0 +1,49 @@
services:
traefik:
image: traefik:v3.6
restart: unless-stopped
command:
- "--accesslog=true"
- "--accesslog.filepath=/logs/traefik-access.log"
- "--accesslog.format=json"
- "--accesslog.filters.statusCodes=200-299, 400-599"
- "--accesslog.bufferingSize=0"
- "--accesslog.fields.headers.defaultMode=drop"
- "--accesslog.fields.headers.names.User-Agent=keep"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.file.directory=/dynamic"
- "--providers.file.watch=true"
- "--entryPoints.web.address=:80"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.cf.acme.dnschallenge=true"
- "--certificatesresolvers.cf.acme.dnschallenge.provider=cloudflare"
- "--certificatesresolvers.cf.acme.email=tls@skrd.fun"
- "--certificatesresolvers.cf.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard-web.rule=Host(`traefik.skrd.fun`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))"
- "traefik.http.routers.dashboard-web.entrypoints=web"
- "traefik.http.routers.dashboard-web.middlewares=local-only@file, redirect-to-https@file"
- "traefik.http.routers.dashboard.rule=Host(`traefik.skrd.fun`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=cf"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=local-only@file"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "${DYNAMIC_DIR}:/dynamic"
- "${DATA_ROOT}/traefik/letsencrypt:/letsencrypt"
- "${DATA_ROOT}/traefik/logs:/logs"
environment:
CF_API_EMAIL: "${CF_API_EMAIL}"
CF_DNS_API_TOKEN: "${CF_DNS_API_TOKEN}"
networks:
default:
name: traefik

View File

@@ -0,0 +1,41 @@
http:
routers:
crafty-web:
rule: Host(`crafty.skrd.fun`)
entryPoints:
- web
middlewares:
- redirect-to-https
service: noop
crafty:
rule: Host(`crafty.skrd.fun`)
entryPoints:
- websecure
service: crafty-svc
tls:
certResolver: cf
middlewares:
- crafty-headers
services:
crafty-svc:
loadBalancer:
servers:
- url: "https://192.168.3.3:8443"
serversTransport: crafty-transport
noop:
loadBalancer:
servers:
- url: "http://0.0.0.0"
middlewares:
crafty-headers:
headers:
customRequestHeaders:
X-Forwarded-Proto: https
serversTransports:
crafty-transport:
insecureSkipVerify: true

View File

@@ -0,0 +1,25 @@
http:
routers:
home-assistant-web:
rule: Host(`haos.skrd.fun`)
entryPoints:
- web
middlewares:
- redirect-to-https
service: noop
home-assistant:
rule: Host(`haos.skrd.fun`)
entryPoints:
- websecure
service: home-assistant-svc
tls:
certResolver: cf
services:
home-assistant-svc:
loadBalancer:
servers:
- url: "http://192.168.3.2:8123"
noop:
loadBalancer:
servers:
- url: "http://0.0.0.0"

View File

@@ -0,0 +1,28 @@
http:
routers:
komodo-web:
rule: Host(`komodo.skrd.fun`)
entryPoints:
- web
middlewares:
- local-only
- redirect-to-https
service: noop
komodo:
rule: Host(`komodo.skrd.fun`)
entryPoints:
- websecure
service: komodo-svc
tls:
certResolver: cf
middlewares:
- local-only
services:
komodo-svc:
loadBalancer:
servers:
- url: "http://192.168.102.1:9120"
noop:
loadBalancer:
servers:
- url: "http://0.0.0.0"

View File

@@ -0,0 +1,14 @@
http:
middlewares:
local-only:
ipWhiteList:
sourceRange:
- "192.168.0.0/16"
redirect-to-https:
redirectScheme:
scheme: https
permanent: true
pihole-rewrite:
replacePathRegex:
regex: ^/$
replacement: /admin/

View File

@@ -0,0 +1,28 @@
http:
routers:
omv-web:
rule: Host(`omv.skrd.fun`)
entryPoints:
- web
middlewares:
- local-only
- redirect-to-https
service: noop
omv:
rule: Host(`omv.skrd.fun`)
entryPoints:
- websecure
service: omv-svc
tls:
certResolver: cf
middlewares:
- local-only
services:
omv-svc:
loadBalancer:
servers:
- url: "http://192.168.102.1:3000"
noop:
loadBalancer:
servers:
- url: "http://0.0.0.0"

View File

@@ -0,0 +1,29 @@
http:
routers:
pihole-web:
rule: Host(`pihole.skrd.fun`)
entryPoints:
- web
middlewares:
- local-only
- redirect-to-https
service: noop
pihole:
rule: Host(`pihole.skrd.fun`)
entryPoints:
- websecure
service: pihole-svc
tls:
certResolver: cf
middlewares:
- local-only
- pihole-rewrite
services:
pihole-svc:
loadBalancer:
servers:
- url: "http://192.168.3.1:80"
noop:
loadBalancer:
servers:
- url: "http://0.0.0.0"

View File

@@ -0,0 +1,34 @@
http:
routers:
proxmox-web:
rule: Host(`proxmox.skrd.fun`)
entryPoints:
- web
middlewares:
- local-only
- redirect-to-https
service: noop
proxmox:
rule: Host(`proxmox.skrd.fun`)
entryPoints:
- websecure
service: proxmox-svc
tls:
certResolver: cf
middlewares:
- local-only
services:
proxmox-svc:
loadBalancer:
servers:
- url: "https://192.168.2.1:8006"
passHostHeader: true
serversTransport: proxmox-transport
noop:
loadBalancer:
servers:
- url: "http://0.0.0.0"
serversTransports:
proxmox-transport:
insecureSkipVerify: true

View File

@@ -1,17 +0,0 @@
version: "3"
services:
db:
image: mariadb
restart: unless-stopped
env_file:
- zenithar.env
volumes:
- /srv/dev-disk-by-uuid-1582b800-1f82-407a-a3aa-3460b3390127/docker/zenithar:/var/lib/mysql:Z
networks:
macvlan_192_168_3_0:
ipv4_address: 192.168.103.7
networks:
macvlan_192_168_3_0:
external: true

View File

@@ -1 +1,2 @@
MARIADB_ROOT_PASSWORD=secret MARIADB_ROOT_PASSWORD=secret
DATA_DIR=./data

View File

@@ -0,0 +1,10 @@
services:
db:
image: mariadb
restart: unless-stopped
ports:
- "3306:3306"
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
volumes:
- ${DATA_DIR}:/var/lib/mysql:Z