From 26391945013bbcb647568da54be967e156f89032 Mon Sep 17 00:00:00 2001 From: NeonXP Date: Sun, 19 Feb 2023 00:27:14 +0300 Subject: [PATCH] initial --- .env.dist | 8 ++ .gitignore | 1 + README.md | 55 ++++++++++ docker-compose.yml | 238 +++++++++++++++++++++++++++++++++++++++++ etc/Caddyfile | 101 +++++++++++++++++ etc/init.sql | 4 + minidlna/Dockerfile | 13 +++ minidlna/entrypoint.sh | 62 +++++++++++ setup.sh | 18 ++++ 9 files changed, 500 insertions(+) create mode 100644 .env.dist create mode 100644 .gitignore create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 etc/Caddyfile create mode 100644 etc/init.sql create mode 100644 minidlna/Dockerfile create mode 100755 minidlna/entrypoint.sh create mode 100755 setup.sh diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000..90d0901 --- /dev/null +++ b/.env.dist @@ -0,0 +1,8 @@ +TZ=Europe/Moscow +EMAIL=YOUR_EMAIL +HOST=YOUR_DOMAIN +PG_USER=docker +PG_PASSWORD=CHANGE_PASSWORD +REDIS_PASSWORD=CHANGE_PASSWORD +TRANSMISSION_USER=root +TRANSMISSION_PASSWORD=CHANGE_PASSWORD \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2eea525 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..866b339 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# TinyNAS + +Дистрибутив софта на базе докера для быстрого развертования домашнего NAS. + +В дистрибутив входят: + +* Transmission - торрент клиент +* miniDLNA - DLNA сервер для трансляции скачанных файлов на ТВ/другие устройства +* NextCloud - персональное облако +* VaultWarden - селфхостед менеджер паролей, свободная реализация Bitwarden + +Помимо этого, сконфигурированы Caddy, Postgres, Redis чтобы всю эту красоту поддерживать. + +## Перед установкой: + +Требования для установки: + +* Сервер доступный снаружи +* Домен который смотрит на этот сервер (его нужно будет указать в первом шаге установки) +* docker + docker-compose + +## Установка: + +1. Запустить на сервере `./setup.sh` для генерации файла настроек .env +2. Запустить TinyNAS: `docker compose up -d` + +## Использование + +Здесь и далее будет использоваться `example.com` как домен указанный 1 шаге установки + +### Transmission + +Адрес: https://transmission.example.com/ + +Логин: TRANSMISSION_USER из файла .env + +Пароль: TRANSMISSION_PASSWORD из файла .env + +### Nextcloud + +Адрес: https://nextcloud.example.com/ + +Необходимо ввести новый логин и пароль для создания администратора. Нажать "Создать". + +После этого в какой-то момент будет ошибка таймаута браузера. Это *нормально*! + +Ничего не делаем, обновляем страницу раз в пару минут, пока окно создания администратора не сменится на окно входа. + +Почему так - не знаю. Но оно работает. Пуллреквесты приветствуются. + +### VaultWarden + +Адрес: https://vaultwarden.example.com/ + +Тут нет особенностей. Оно просто работает. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..34a32f3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,238 @@ +version: "3.0" + +volumes: + media: + transmission-config: + transmission-watch: + nextcloud-config: + nextcloud-data: + nextcloud-www: + caddy-config: + caddy-data: + vw-data: + postgres-data: + postgres-backups: + +networks: + inner: + +services: + minidlna: + build: + context: minidlna + dockerfile: Dockerfile + container_name: dlna + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TZ} + MINIDLNA_MEDIA_DIR: /media + MINIDLNA_FRIENDLY_NAME: tinyNAS + volumes: + - media:/media + healthcheck: + test: + [ + "CMD", + "curl", + "--silent", + "--fail", + "127.0.0.1:8200", + "||", + "exit 1" + ] + interval: 10s + timeout: 10s + retries: 6 + start_period: 10s + restart: unless-stopped + ports: + - 8200:8200 + + transmission: + image: lscr.io/linuxserver/transmission:latest + container_name: transmission + environment: + - PUID=1000 + - PGID=1000 + - TZ=${TZ} + - USER=${TRANSMISSION_USER} + - PASS=${TRANSMISSION_PASSWORD} + volumes: + - transmission-config:/config + - media:/downloads + - transmission-watch:/watch + ports: + - 51413:51413 + - 51413:51413/udp + restart: unless-stopped + networks: + - inner + + nextcloud: + image: nextcloud:stable-fpm-alpine + container_name: nextcloud + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TZ} + POSTGRES_DB: nextcloud + POSTGRES_USER: ${PG_USER} + POSTGRES_PASSWORD: ${PG_PASSWORD} + POSTGRES_HOST: postgres:5432 + NEXTCLOUD_TRUSTED_DOMAINS: nextcloud.${HOST} + REDIS_HOST: redis + REDIS_HOST_PASSWORD: ${REDIS_PASSWORD} + volumes: + - nextcloud-config:/config:rw + - nextcloud-data:/var/data:rw + - nextcloud-www:/var/www/html:rw + restart: unless-stopped + networks: + - inner + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + + nextcloud-cron: + image: nextcloud:stable-fpm-alpine + restart: always + container_name: nextcloud-cron + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TZ} + POSTGRES_DB: nextcloud + POSTGRES_USER: ${PG_USER} + POSTGRES_PASSWORD: ${PG_PASSWORD} + POSTGRES_HOST: postgres:5432 + NEXTCLOUD_TRUSTED_DOMAINS: nextcloud.${HOST} + REDIS_HOST: redis + REDIS_HOST_PASSWORD: ${REDIS_PASSWORD} + volumes: + - nextcloud-config:/config:rw + - nextcloud-data:/data:rw + - nextcloud-www:/var/www/html:rw + entrypoint: /cron.sh + networks: + - inner + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + + vaultwarden: + image: vaultwarden/server:latest + container_name: vaultwarden + restart: always + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TZ} + WEBSOCKET_ENABLED: "true" + DATABASE_URL: postgresql://${PG_USER}:${PG_PASSWORD}@postgres:5432/vaultwarden + volumes: + - vw-data:/data + networks: + - inner + depends_on: + postgres: + condition: service_healthy + + gateway: + image: caddy:2 + container_name: caddy + restart: always + ports: + - 80:80 + - 443:443 + volumes: + - ./etc/Caddyfile:/etc/caddy/Caddyfile:ro + - caddy-config:/config:rw + - caddy-data:/data:rw + - nextcloud-www:/var/www/nextcloud:rw + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TZ} + HOST: ${HOST} + EMAIL: ${EMAIL} + LOG_FILE: "/data/access.log" + networks: + - inner + depends_on: + - nextcloud + - vaultwarden + - transmission + + postgres: + image: postgres:15.2-alpine3.17 + restart: always + container_name: postgres + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TZ} + PGUSER: ${PG_USER} + POSTGRES_USER: ${PG_USER} + POSTGRES_PASSWORD: ${PG_PASSWORD} + DB_NAME: nextcloud,vaultwarden + LANG: ru_RU.utf8 + volumes: + - "postgres-data:/var/lib/postgresql/data" + - "./etc/init.sql:/docker-entrypoint-initdb.d/init.sql" + healthcheck: + test: ["CMD-SHELL", "pg_isready -d vaultwarden -U docker"] + interval: 20s + timeout: 10s + retries: 10 + networks: + - inner + + backups: + image: postgres:15.2-alpine3.17 + container_name: postgres_backup + # Run nextcloud-restore-application-data.sh to restore application data if needed. + # Run nextcloud-restore-database.sh to restore database if needed. + command: sh -c 'sleep 30m + && while true; do + PGPASSWORD="$$(echo $$POSTGRES_PASSWORD)" + pg_dump + -h postgres + -p 5432 + -d nextcloud + -U docker | gzip > /srv/nextcloud-postgres/backups/nextcloud-postgres-backup-$$(date "+%Y-%m-%d_%H-%M").gz + && tar -zcpf /srv/nextcloud-application-data/backups/nextcloud-application-data-backup-$$(date "+%Y-%m-%d_%H-%M").tar.gz /var/www/html + && find /srv/nextcloud-postgres/backups -type f -mtime +7 | xargs rm -f + && find /srv/nextcloud-application-data/backups -type f -mtime +7 | xargs rm -f; + sleep 24h; done' + environment: + PUID: 1000 + PGID: 1000 + TZ: ${TZ} + PGUSER: ${PG_USER} + POSTGRES_USER: ${PG_USER} + POSTGRES_PASSWORD: ${PG_PASSWORD} + DB_NAME: nextcloud,vaultwarden + LANG: ru_RU.utf8 + volumes: + - "postgres-data:/var/lib/postgresql/data" + # Database backups location + - "postgres-backups:/srv/nextcloud-postgres/backups" + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + + redis: + container_name: redis + image: redis:alpine3.17 + restart: always + mem_limit: 2048m + mem_reservation: 512m + command: redis-server --requirepass $REDIS_PASSWORD + networks: + - inner \ No newline at end of file diff --git a/etc/Caddyfile b/etc/Caddyfile new file mode 100644 index 0000000..0239f72 --- /dev/null +++ b/etc/Caddyfile @@ -0,0 +1,101 @@ +{ + servers :443 { + timeouts { + idle 600s + read_body 600s + read_header 600s + write 600s + } + max_header_size 100MB + } + servers { + timeouts { + idle 600s + read_body 600s + read_header 600s + write 600s + } + max_header_size 20MB + } +} + +nextcloud.{$HOST} { + log { + level INFO + output file {$LOG_FILE} { + roll_size 10MB + roll_keep 10 + } + } + + tls {$EMAIL} + + encode gzip + + header { + # enable HSTS + # Strict-Transport-Security max-age=31536000; + } + + file_server + root * /var/www/nextcloud + + @forbidden { + path /.htaccess + path /data/* + path /config/* + path /db_structure + path /.xml + path /README + path /3rdparty/* + path /lib/* + path /templates/* + path /occ + path /console.php + } + respond @forbidden 404 + php_fastcgi nextcloud:9000 { + root /var/www/html + env front_controller_active true + dial_timeout 600s + read_timeout 600s + write_timeout 600s + } +} + +vaultwarden.{$HOST} { + log { + level INFO + output file {$LOG_FILE} { + roll_size 10MB + roll_keep 10 + } + } + + tls {$EMAIL} + + encode gzip + + reverse_proxy /notifications/hub vaultwarden:3012 + reverse_proxy vaultwarden:80 { + header_up X-Real-IP {remote_host} + } +} + +transmission.{$HOST} { + log { + level INFO + output file {$LOG_FILE} { + roll_size 10MB + roll_keep 10 + } + } + + tls {$EMAIL} + + encode gzip + + reverse_proxy transmission:9091 { + header_up X-Real-IP {remote_host} + } +} diff --git a/etc/init.sql b/etc/init.sql new file mode 100644 index 0000000..e42c6bd --- /dev/null +++ b/etc/init.sql @@ -0,0 +1,4 @@ +CREATE DATABASE nextcloud; +GRANT ALL PRIVILEGES ON DATABASE nextcloud TO docker; +CREATE DATABASE vaultwarden; +GRANT ALL PRIVILEGES ON DATABASE vaultwarden TO docker; \ No newline at end of file diff --git a/minidlna/Dockerfile b/minidlna/Dockerfile new file mode 100644 index 0000000..d8d4332 --- /dev/null +++ b/minidlna/Dockerfile @@ -0,0 +1,13 @@ +FROM alpine:3.17.2 +LABEL maintainer "Alexander Kiryukhin i@neonxp.dev" + +# Install +RUN apk --no-cache add bash curl minidlna tini shadow su-exec alpine-conf inotify-tools + +# Entrypoint +COPY entrypoint.sh / +RUN chmod +x /entrypoint.sh + +EXPOSE 8200 + +ENTRYPOINT ["/sbin/tini", "--", "/entrypoint.sh"] \ No newline at end of file diff --git a/minidlna/entrypoint.sh b/minidlna/entrypoint.sh new file mode 100755 index 0000000..5b77916 --- /dev/null +++ b/minidlna/entrypoint.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# Bash strict mode +set -euo pipefail +IFS=$'\n\t' + +# DEBUG +[ -z "${DEBUG:-}" ] || set -x + +# VARs +export TZ="${TZ:-}" +export PUID="${PUID:-100}" +export PGID="${PGID:-101}" +export PIDFILE='/minidlna/minidlna.pid' +export FORCE_SCAN="${FORCE_SCAN:-false}" +export FORCE_REBUILD="${FORCE_REBUILD:-false}" + +# Remove old pid if it exists +[ -f "$PIDFILE" ] && rm -f "$PIDFILE" + +echo '=== Set user and group identifier' +groupmod --non-unique --gid "$PGID" minidlna +usermod --non-unique --uid "$PUID" minidlna + +if [[ -n "$TZ" ]]; then + echo '=== Set timezone' + setup-timezone -z "$TZ" +fi + +echo '=== Set standard configuration' +export MINIDLNA_DB_DIR="${MINIDLNA_DB_DIR:-/minidlna/cache}" +export MINIDLNA_LOG_DIR="${MINIDLNA_LOG_DIR:-/minidlna}" +export MINIDLNA_INOTIFY="${MINIDLNA_INOTIFY:-yes}" + +echo '=== Set configuration from environment variables' +: > /etc/minidlna.conf +for VAR in $(env); do + if [[ "$VAR" =~ ^MINIDLNA_ ]]; then + if [[ "$VAR" =~ ^MINIDLNA_MEDIA_DIR ]]; then + minidlna_name='media_dir' + else + minidlna_name=$(echo "$VAR" | sed -r "s/MINIDLNA_(.*)=.*/\\1/g" | tr '[:upper:]' '[:lower:]') + fi + minidlna_value=$(echo "$VAR" | sed -r "s/.*=(.*)/\\1/g") + echo "${minidlna_name}=${minidlna_value}" >> /etc/minidlna.conf + fi +done + +echo '=== Set permissions' +mkdir -p /minidlna/ "${MINIDLNA_DB_DIR}" "${MINIDLNA_LOG_DIR}" +chown -R "${PUID}:${PGID}" /minidlna/ "${MINIDLNA_DB_DIR}" "${MINIDLNA_LOG_DIR}" + +echo '=== Generate scan/rebuild flags' +if [[ "$FORCE_SCAN" == true ]]; then + set -- -r "$@" +fi +if [[ "$FORCE_REBUILD" == true ]]; then + set -- -R "$@" +fi + +echo '=== Start daemon' +exec su-exec minidlna /usr/sbin/minidlnad -P "$PIDFILE" -S "$@" \ No newline at end of file diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..63825d9 --- /dev/null +++ b/setup.sh @@ -0,0 +1,18 @@ +#! /bin/sh + +read -p "Ваш e-mail: " EMAIL +read -p "Базовый домен, для которого будут созданы поддомены с сервисами: " HOST + +PG_PASSWORD=`tr -dc A-Za-z0-9 .env +echo "Конфиг записан в файл .env" \ No newline at end of file