diff --git a/homelab/applications/authelia/compose.yaml b/homelab/applications/authelia/compose.yaml
deleted file mode 100644
index b961bc7..0000000
--- a/homelab/applications/authelia/compose.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-secrets:
- STORAGE_ENCRYPTION_KEY:
- file: './secrets/authelia_db_encryption_key'
-
-services:
- authelia:
- image: authelia/authelia:latest
- container_name: authelia
- volumes:
- # Config files are still mounted as volumes
- - ./config/configuration.yml:/config/configuration.yml:ro
- - ./config/users_database.yml:/config/users_database.yml:ro
-
- # Persistent SQLite database directory
- - ./db:/config/db
- ports:
- - '9091:9091'
- secrets: ['STORAGE_ENCRYPTION_KEY']
- environment:
- TZ: 'Etc/UTC'
- AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: '/run/secrets/STORAGE_ENCRYPTION_KEY'
-
- restart: always
- healthcheck:
- test: ["CMD", "authelia", "healthcheck"]
- interval: 5s
- timeout: 5s
- retries: 5
- start_period: 5s
\ No newline at end of file
diff --git a/homelab/applications/authelia/config/configuration.yml b/homelab/applications/authelia/config/configuration.yml
deleted file mode 100644
index 38e4cbc..0000000
--- a/homelab/applications/authelia/config/configuration.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-server:
- address: 0.0.0.0:9091
- endpoints:
- authz:
- forward-auth:
- implementation: 'ForwardAuth'
-
-log:
- level: info
-
-# --- Storage ---
-storage:
- local:
- path: /config/db/authelia.sqlite.db
-
-# --- Authentication ---
-authentication_backend:
- file:
- path: /config/users_database.yml
- password:
- algorithm: argon2id
- iterations: 1
- memory: 2097152
- parallelism: 4
- salt_length: 16
- key_length: 32
- password_reset:
- disable: true
- password_change:
- disable: false
-
-# --- Session ---
-session:
- cookies:
- - domain: 'saljic.me'
- authelia_url: 'https://auth.saljic.me'
- default_redirection_url: 'https://home.saljic.me'
-
-# --- Notifier (No Mail) ---
-notifier:
- filesystem:
- filename: /config/db/notifications.log
-
-# --- Access Control ---
-access_control:
- default_policy: deny
- rules:
- - domain: "*.saljic.me"
- policy: one_factor
-
-# --- Password policies ---
-password_policy:
- standard:
- enabled: true
- min_length: 8
- require_uppercase: true
- require_lowercase: true
- require_number: true
- require_special: true
\ No newline at end of file
diff --git a/homelab/applications/authelia/config/users_database.yml b/homelab/applications/authelia/config/users_database.yml
deleted file mode 100644
index f0575bc..0000000
--- a/homelab/applications/authelia/config/users_database.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-users:
- amar:
- disabled: false
- displayname: 'Amar Šaljić'
- password: '$argon2id$v=19$m=65536,t=3,p=4$5PaYrZOdJzg3SMIAqql/uA$EFH9v2DfJZw6ni8uup4BWMEFvMwIlM5HbH7MLX7F4g0'
- email: 'amar@saljic.me'
- groups:
- - 'admins'
- - 'dev'
\ No newline at end of file
diff --git a/homelab/applications/caddy/Caddyfile b/homelab/applications/caddy/Caddyfile
index c14733e..ddbde91 100644
--- a/homelab/applications/caddy/Caddyfile
+++ b/homelab/applications/caddy/Caddyfile
@@ -1,34 +1,48 @@
-# --- Authelia Portal ---
-# This is the login page itself. It does NOT have forward_auth.
-auth.saljic.me {
- # Proxy to the Authelia Docker container on port 9091
- reverse_proxy localhost:9091
+# --- Home Assistant ---
+(logging) {
+ log {
+ output file /var/log/caddy/access.log {
+ # Roll logs to save space
+ roll_size 100mb
+ roll_keep 10
+ roll_keep_for 720h # 30 days
+ }
+ format json
+ level INFO # This ensures all requests (INFO, WARN, ERROR) are logged
+ }
}
-# --- Home Assistant (Protected App) ---
-ha.saljic.me {
- # 1. Apply authentication using Caddy's 'forward_auth'
- forward_auth localhost:9091 {
- uri /api/authz/forward-auth
- copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
- }
+# --- top domain ---
+saljic.me {
+ import logging
+ respond "Welcome! In the making..."
+}
- # 2. If auth is successful, proxy to your Home Assistant instance
+ha.saljic.me {
+ import logging
reverse_proxy 10.10.10.6:8123
}
+# --- FreshRSS ---
+feed.saljic.me {
+ import logging
+ reverse_proxy 10.10.10.6:8081
+}
+
# --- Immich ---
tagebuch.saljic.me {
+ import logging
reverse_proxy 10.10.10.6:2283
}
-# --- default ---
-home.saljic.me {
- header Content-Type text/html
- respond <
-
saljic.me
- Hello there
-
- HTML 200
+# --- Gitea ---
+git.saljic.me {
+ import logging
+ reverse_proxy 10.10.10.6:8030
+}
+
+# --- ntfy ---
+ntfy.saljic.me {
+ import logging
+ reverse_proxy 10.10.10.6:8500
}
\ No newline at end of file
diff --git a/homelab/applications/gitea/compose.yml b/homelab/applications/gitea/compose.yml
new file mode 100644
index 0000000..46dc1f7
--- /dev/null
+++ b/homelab/applications/gitea/compose.yml
@@ -0,0 +1,14 @@
+ services:
+ server:
+ image: docker.gitea.com/gitea:latest
+ container_name: gitea
+ environment:
+ - USER_UID=1000
+ - USER_GID=1000
+ - DISABLE_REGISTRATION=true
+ restart: always
+ volumes:
+ - ./data:/data
+ ports:
+ - "8030:3000"
+ - "222:22"
\ No newline at end of file
diff --git a/homelab/applications/homeassistant/config/configuration.yaml b/homelab/applications/homeassistant/config/configuration.yaml
new file mode 100644
index 0000000..da2f478
--- /dev/null
+++ b/homelab/applications/homeassistant/config/configuration.yaml
@@ -0,0 +1,19 @@
+# Loads default set of integrations. Do not remove.
+default_config:
+
+# Load frontend themes from the themes folder
+frontend:
+ themes: !include_dir_merge_named themes
+
+automation: !include automations.yaml
+script: !include scripts.yaml
+scene: !include scenes.yaml
+http:
+ use_x_forwarded_for: true
+ trusted_proxies:
+ - 192.168.100.5
+homeassistant:
+ external_url: "https://ha.saljic.me"
+ internal_url: "http://10.10.10.6:8123"
+
+sensor: !include sensor.yaml
diff --git a/homelab/applications/postgres/README.md b/homelab/applications/postgres/README.md
new file mode 100644
index 0000000..980a0d0
--- /dev/null
+++ b/homelab/applications/postgres/README.md
@@ -0,0 +1,28 @@
+# Postgres
+## Set up non-root user for container
+We are providing a non-root user to the container to limit the attack surface for privilege escalations. In order for this to work in our setup, please make sure to check if you have a user called `postgres` set up.
+
+1. Check if user `postgres` exists and if the UID is 1002
+
+```
+cat /etc/passwd | grep postgres
+```
+
+In case the `postgres` user exists but the UID is not 1002, please adjust it via
+```
+sudo usermod -u 1002 postgres
+```
+
+In case the `postgres` user doesn't exist at all, please create the user incl. the right UID by running
+```
+sudo useradd -u 1002 postgres
+```
+
+## About secrets
+In order to manage secrets centrally in 1Password and due to the need for secrets in Postgres, using `docker compose` directly in the terminal does not work.
+
+## Bring up/tear down container
+Please use the `start.sh` to spin up the container
+### Prerequisites start.sh
+- User executing the script is part of the `docker` group
+- Env variable `OP_SERVICE_ACCOUNT_TOKEN` is set up \[check out top-level README.md for more information on how to set this up\]
\ No newline at end of file
diff --git a/homelab/applications/postgres/compose.yml b/homelab/applications/postgres/compose.yml
new file mode 100644
index 0000000..ec0f5ae
--- /dev/null
+++ b/homelab/applications/postgres/compose.yml
@@ -0,0 +1,18 @@
+secrets:
+ postgres_password:
+ environment: POSTGRES_PASSWORD
+ postgres_user:
+ environment: POSTGRES_USER
+services:
+ postgres:
+ image: postgres:18
+ container_name: postgres
+ user: "1002"
+ restart: always
+ shm_size: 1024mb
+ environment:
+ POSTGRES_USER_FILE: /run/secrets/postgres_user
+ POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
+ secrets: ['postgres_password', 'postgres_user']
+ ports: ['5432:5432']
+ volumes: ['./data:/var/lib/postgresql']
diff --git a/homelab/applications/postgres/start.sh b/homelab/applications/postgres/start.sh
new file mode 100644
index 0000000..a0dada1
--- /dev/null
+++ b/homelab/applications/postgres/start.sh
@@ -0,0 +1,13 @@
+#!/bin/zsh
+# Exit immediately if a command exits with a non-zero status.
+set -e
+
+echo "--- Starting Docker Secret Management ---"
+# Mount secrets
+export POSTGRES_USER="$(op read 'op://NAxS Homelab/Postgres Homelab/username')"
+export POSTGRES_PASSWORD="$(op read 'op://NAxS Homelab/Postgres Homelab/password')"
+
+# Bring up container
+docker compose up -d
+
+echo "--- Docker Secret Management Complete ---"
\ No newline at end of file
diff --git a/homelab/ubuntu-server-setup.sh b/homelab/ubuntu-server-setup.sh
new file mode 100644
index 0000000..918715b
--- /dev/null
+++ b/homelab/ubuntu-server-setup.sh
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Simple installer for Ubuntu server:
+# - unattended-upgrades (security updates + automatic reboot)
+# - Docker (engine + compose plugin) per Docker docs steps 1-3
+# - zsh (set as default shell for original user)
+# - 1Password CLI for access to secrets
+# - secret-tools for storing tokens needed (i.e. for 1Password CLI)
+
+# Must be run as root
+if [ "$EUID" -ne 0 ]; then
+ echo "Please run as root: sudo bash $0"
+ exit 1
+fi
+
+# Detect target user to set default shell for
+TARGET_USER="${SUDO_USER:-$(whoami)}"
+
+apt-get update
+
+# 1) Enable automatic security updates and automatic reboot
+apt-get install -y unattended-upgrades
+
+# Enable periodic updates/unattended-upgrades
+cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
+APT::Periodic::Update-Package-Lists "1";
+APT::Periodic::Unattended-Upgrade "1";
+APT::Periodic::AutocleanInterval "7";
+EOF
+
+# Ensure automatic reboot after unattended-upgrades (time adjustable)
+cat > /etc/apt/apt.conf.d/99auto-reboot <<'EOF'
+Unattended-Upgrade::Automatic-Reboot "true";
+Unattended-Upgrade::Automatic-Reboot-Time "04:00";
+EOF
+
+# Start/enable unattended-upgrades (if system uses service/timer)
+if systemctl list-unit-files | grep -q unattended-upgrades; then
+ systemctl enable --now unattended-upgrades || true
+fi
+
+# 2) Install Docker (steps 1-3 from Docker docs)
+# Install prerequisites
+apt-get install -y ca-certificates curl gnupg lsb-release
+
+# Create keyrings dir and add Docker GPG key
+install -m 0755 -d /etc/apt/keyrings
+curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
+chmod a+r /etc/apt/keyrings/docker.asc
+
+# Add Docker apt repository
+ARCH=$(dpkg --print-architecture)
+. /etc/os-release
+UBU_CODENAME="${UBUNTU_CODENAME:-$VERSION_CODENAME}"
+echo "deb [arch=${ARCH} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu ${UBU_CODENAME} stable" \
+ > /etc/apt/sources.list.d/docker.list
+
+apt-get update
+
+# Install Docker Engine + plugins including compose plugin
+apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
+
+# Verify Docker works by running hello-world (this will pull an image)
+if command -v docker >/dev/null 2>&1; then
+ docker run --rm hello-world || true
+fi
+
+# 3) Install zsh and make it the default shell for the target user
+apt-get install -y zsh
+
+ZSH_PATH="$(which zsh)"
+if ! grep -q "^${ZSH_PATH}$" /etc/shells; then
+ echo "${ZSH_PATH}" >> /etc/shells
+fi
+
+# Change shell for target user (if possible)
+if id "${TARGET_USER}" >/dev/null 2>&1; then
+ chsh -s "${ZSH_PATH}" "${TARGET_USER}" || echo "chsh failed for ${TARGET_USER}; you may need to run 'chsh -s ${ZSH_PATH} ${TARGET_USER}' manually"
+else
+ echo "User ${TARGET_USER} not found; skipping chsh"
+fi
+
+# 4) Install 1Password CLI for access to secrets
+curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
+gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg && \
+echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" | \
+tee /etc/apt/sources.list.d/1password.list && \
+mkdir -p /etc/debsig/policies/AC2D62742012EA22/ && \
+curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | \
+tee /etc/debsig/policies/AC2D62742012EA22/1password.pol && \
+mkdir -p /usr/share/debsig/keyrings/AC2D62742012EA22 && \
+curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
+gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg && \
+apt update && apt install 1password-cli
+
+# Check successful install
+op --version
+
+# 5) Install gnome-keyring secret-tool for securely storing tokens
+apt install pass gnupg2
+
+
+
+
+echo "Done. Recommended: log out and back in (or reboot) to start using zsh and ensure all services are active."
\ No newline at end of file