diff --git a/services/authentik/docker-compose.yml b/services/authentik/docker-compose.yml new file mode 100644 index 0000000..3306a0f --- /dev/null +++ b/services/authentik/docker-compose.yml @@ -0,0 +1,62 @@ +services: + postgresql: + image: docker.io/library/postgres:16-alpine + restart: unless-stopped + env_file: + - /srv/authentik/.env + environment: + POSTGRES_PASSWORD: ${PG_PASS:?database password required} + POSTGRES_USER: ${PG_USER:-authentik} + POSTGRES_DB: ${PG_DB:-authentik} + healthcheck: + test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"] + start_period: 20s + interval: 30s + retries: 5 + timeout: 5s + volumes: + - /srv/authentik/postgresql:/var/lib/postgresql/data + + server: + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2.1-rc1} + restart: unless-stopped + command: server + depends_on: + postgresql: + condition: service_healthy + env_file: + - /srv/authentik/.env + environment: + AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required} + AUTHENTIK_POSTGRESQL__HOST: postgresql + AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} + ports: + - "${COMPOSE_PORT_HTTP:-9000}:9000" + - "${COMPOSE_PORT_HTTPS:-9443}:9443" + volumes: + - /srv/authentik/media:/media + - /srv/authentik/custom-templates:/templates + + worker: + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.2.1-rc1} + restart: unless-stopped + command: worker + user: root + depends_on: + postgresql: + condition: service_healthy + env_file: + - /srv/authentik/.env + environment: + AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required} + AUTHENTIK_POSTGRESQL__HOST: postgresql + AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} + AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} + AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /srv/authentik/media:/media + - /srv/authentik/certs:/certs + - /srv/authentik/custom-templates:/templates diff --git a/services/authentik/start.sh b/services/authentik/start.sh new file mode 100755 index 0000000..dbbe15e --- /dev/null +++ b/services/authentik/start.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +docker compose --env-file /srv/authentik/.env up -d diff --git a/services/caddy/Caddyfile b/services/caddy/Caddyfile index 3366cd2..43fe648 100644 --- a/services/caddy/Caddyfile +++ b/services/caddy/Caddyfile @@ -1,3 +1,4 @@ +import /opt/homelab/services/caddy/snippets/*.caddy { email pavel123357@gmail.com @@ -7,12 +8,29 @@ } } -:80 { - respond "Yarik, zdarova" +pass.sesur.dev { + reverse_proxy 127.0.0.1:9000 +} +home.sesur.dev { + route { + import authentik_forward_auth + reverse_proxy 127.0.0.1:3050 + } +} + +dozzle.sesur.dev { + route { + import authentik_forward_auth + reverse_proxy 127.0.0.1:9999 + } } photos.sesur.dev { + log { + output file /var/log/caddy/access.log + format json + } reverse_proxy 127.0.0.1:2283 # Optional: allow large uploads (adjust as you like) @@ -61,10 +79,25 @@ http://192.168.1.47 { http://dozzle.lan { reverse_proxy 127.0.0.1:9999 } -https://remnawave.lan { - tls internal - reverse_proxy 127.0.0.1:4000 + +rat.sesur.dev { + handle /api/sub/* { + reverse_proxy 127.0.0.1:4000 + } + route { + import authentik_forward_auth + reverse_proxy 127.0.0.1:4000 + } } + +rat-api.sesur.dev { + @notAllowed { + not remote_ip 31.57.61.253 + } + respond @notAllowed "Forbidden" 403 + reverse_proxy 127.0.0.1:4000 +} + http://cyberchef.lan { reverse_proxy 127.0.0.1:8085 } diff --git a/services/caddy/snippets/authentik_forward_auth.caddy b/services/caddy/snippets/authentik_forward_auth.caddy new file mode 100644 index 0000000..1d3c203 --- /dev/null +++ b/services/caddy/snippets/authentik_forward_auth.caddy @@ -0,0 +1,9 @@ +(authentik_forward_auth) { + reverse_proxy /outpost.goauthentik.io/* http://127.0.0.1:9000 + + forward_auth http://127.0.0.1:9000 { + uri /outpost.goauthentik.io/auth/caddy + copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt + trusted_proxies private_ranges + } +} diff --git a/services/homepage/docker-compose.yml b/services/homepage/docker-compose.yml new file mode 100644 index 0000000..4331151 --- /dev/null +++ b/services/homepage/docker-compose.yml @@ -0,0 +1,12 @@ +services: + homepage: + image: ghcr.io/gethomepage/homepage:latest + container_name: homepage + restart: unless-stopped + ports: + - "127.0.0.1:3050:3000" + volumes: + - /srv/homepage/config:/app/config + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + - HOMEPAGE_ALLOWED_HOSTS=home.sesur.dev diff --git a/services/remnawave/remnawave-nodes/boostrap.sh b/services/remnawave/remnawave-nodes/boostrap.sh new file mode 100644 index 0000000..09e6bad --- /dev/null +++ b/services/remnawave/remnawave-nodes/boostrap.sh @@ -0,0 +1,225 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# ========================= +# Config +# ========================= +ADMIN_USER="${ADMIN_USER:-pvlx}" +SSH_PORT="${SSH_PORT:-22}" + +NODE_NAME="${NODE_NAME:-fin-node-01}" +NODE_DIR="${NODE_DIR:-/opt/remnanode}" + +SECRET_KEY="${SECRET_KEY:-}" +MASTER_API_URL="${MASTER_API_URL:-https://rat-api.sesur.dev}" +NODE_PORT="${NODE_PORT:-2222}" + +ENABLE_UFW="${ENABLE_UFW:-true}" + +# ========================= +# Helpers +# ========================= +log() { + echo + echo "==> $1" +} + +require_root() { + if [[ "${EUID}" -ne 0 ]]; then + echo "Run as root" + exit 1 + fi +} + +require_secret() { + if [[ -z "${SECRET_KEY}" ]]; then + echo "SECRET_KEY is empty." + echo 'Run like:' + echo 'SECRET_KEY="your-secret" MASTER_API_URL="https://rat-api.sesur.dev" bash bootstrap-remnanode.sh' + exit 1 + fi +} + +# ========================= +# Main +# ========================= +require_root +require_secret + +log "Updating system" +apt-get update +DEBIAN_FRONTEND=noninteractive apt-get upgrade -y + +log "Installing base packages" +DEBIAN_FRONTEND=noninteractive apt-get install -y \ + ca-certificates curl gnupg lsb-release \ + ufw unattended-upgrades nano logrotate + +log "Enable automatic security updates" +dpkg-reconfigure -f noninteractive unattended-upgrades || true + +log "Creating admin user" +if ! id -u "${ADMIN_USER}" >/dev/null 2>&1; then + adduser --disabled-password --gecos "" "${ADMIN_USER}" +fi + +usermod -aG sudo "${ADMIN_USER}" + +log "Configuring passwordless sudo for ${ADMIN_USER}" +echo "${ADMIN_USER} ALL=(ALL) NOPASSWD:ALL" >/etc/sudoers.d/90-${ADMIN_USER} +chmod 440 /etc/sudoers.d/90-${ADMIN_USER} + +if [[ -f /root/.ssh/authorized_keys ]]; then + mkdir -p "/home/${ADMIN_USER}/.ssh" + cp /root/.ssh/authorized_keys "/home/${ADMIN_USER}/.ssh/authorized_keys" + chown -R "${ADMIN_USER}:${ADMIN_USER}" "/home/${ADMIN_USER}/.ssh" + chmod 700 "/home/${ADMIN_USER}/.ssh" + chmod 600 "/home/${ADMIN_USER}/.ssh/authorized_keys" +fi + +log "Hardening SSH" + +SSHD_CONFIG="/etc/ssh/sshd_config" +cp "${SSHD_CONFIG}" "${SSHD_CONFIG}.bak.$(date +%s)" + +sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' "${SSHD_CONFIG}" +sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' "${SSHD_CONFIG}" +sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' "${SSHD_CONFIG}" + +if grep -q '^AllowUsers' "${SSHD_CONFIG}"; then + sed -i "s/^AllowUsers.*/AllowUsers ${ADMIN_USER}/" "${SSHD_CONFIG}" +else + echo "AllowUsers ${ADMIN_USER}" >> "${SSHD_CONFIG}" +fi + +systemctl restart ssh || systemctl restart sshd + +log "Installing Docker" + +if ! command -v docker >/dev/null; then + curl -fsSL https://get.docker.com | sh +fi + +systemctl enable docker +systemctl start docker + +usermod -aG docker "${ADMIN_USER}" + +log "Configure Docker logs" + +mkdir -p /etc/docker + +cat >/etc/docker/daemon.json <<'EOF' +{ + "log-driver": "json-file", + "log-opts": { + "max-size": "50m", + "max-file": "3" + } +} +EOF + +systemctl restart docker + +log "Applying kernel network hardening" + +cat >/etc/sysctl.d/99-remnanode-security.conf <<'EOF' +net.ipv4.tcp_syncookies = 1 +net.ipv4.conf.all.rp_filter = 1 +net.ipv4.conf.default.rp_filter = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.conf.all.accept_redirects = 0 +net.ipv4.conf.default.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.default.send_redirects = 0 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 +EOF + +sysctl --system + +if [[ "${ENABLE_UFW}" == "true" ]]; then + log "Configuring firewall" + + ufw --force reset + ufw default deny incoming + ufw default allow outgoing + + ufw allow "${SSH_PORT}/tcp" + ufw allow 443/tcp + ufw allow "${NODE_PORT}/tcp" + + ufw --force enable +fi + +log "Creating log directory" +mkdir -p /var/log/remnanode +chown root:root /var/log/remnanode +chmod 755 /var/log/remnanode + +log "Configuring logrotate for remnanode" +cat >/etc/logrotate.d/remnanode <<'EOF' +/var/log/remnanode/*.log { + size 50M + rotate 5 + compress + missingok + notifempty + copytruncate +} +EOF + +log "Creating Remnawave node" + +mkdir -p "${NODE_DIR}" + +cat >"${NODE_DIR}/.env" <"${NODE_DIR}/docker-compose.yml" <