Просмотр исходного кода

Merge pull request #12 from meienberger/readme

Update README
Nicolas Meienberger 3 лет назад
Родитель
Сommit
f2a3111331
7 измененных файлов с 119 добавлено и 18 удалено
  1. 1 0
      .gitignore
  2. 67 5
      README.md
  3. 6 0
      scripts/configure.sh
  4. 37 9
      scripts/start.sh
  5. 3 1
      system-api/src/config/config.ts
  6. 2 3
      system-api/src/server.ts
  7. 3 0
      templates/env-api-sample

+ 1 - 0
.gitignore

@@ -1,4 +1,5 @@
 .env
 .env
+.env*
 nginx/*
 nginx/*
 letsencrypt/*
 letsencrypt/*
 app-data/*
 app-data/*

+ 67 - 5
README.md

@@ -1,7 +1,69 @@
-![License](https://img.shields.io/github/license/meienberger/runtipi?style=flat-square)
-![RunsOn](https://img.shields.io/badge/Debian-Supported-green?logo=debian&style=flat-square)
-![RunsOn](https://img.shields.io/badge/Ubuntu-Supported-green?logo=ubuntu&style=flat-square)
-![RunsOn](https://img.shields.io/badge/Arch-Partial-yellow?logo=archlinux&style=flat-square)
-![RunsOn](https://img.shields.io/badge/Fedora-Not%20Supported-red?logo=fedora&style=flat-square)
+
+# ⛺️ Tipi — A personal homeserver for everyone
+[![License](https://img.shields.io/github/license/meienberger/runtipi)](https://github.com/meienberger/runtipi/blob/master/LICENSE)
+[![Version](https://img.shields.io/github/v/release/meienberger/runtipi?color=%235351FB&label=version)](https://github.com/meienberger/runtipi/releases)
+![RunsOn](https://img.shields.io/badge/Debian-Supported-green?logo=debian)
+![RunsOn](https://img.shields.io/badge/Ubuntu-Supported-green?logo=ubuntu)
 
 
 ![Preview](https://raw.githubusercontent.com/meienberger/runtipi/develop/screenshots/1.png)
 ![Preview](https://raw.githubusercontent.com/meienberger/runtipi/develop/screenshots/1.png)
+> ⚠️ Tipi is still at an early stage of development and issues are to be expected. Feel free to open an issue or pull request if you find a bug.
+
+Tipi is a personal homeserver orchestrator. It is running docker containers under the hood and provides a simple web interface to manage them. Every service comes with an opinionated configuration in order to remove the need for manual configuration and network setup.
+
+## Apps available
+- [Anonaddy](https://github.com/anonaddy/anonaddy) - Anonymous email forwarding
+- [Filebrowser](https://github.com/filebrowser/filebrowser) - Web File Browser
+- [Freshrss](https://github.com/FreshRSS/FreshRSS) - A free, self-hostable RSS aggregator
+- [Invidious](https://github.com/iv-org/invidious) - An alternative front-end to YouTube
+- [Jackett](https://github.com/Jackett/Jackett) - API Support for your favorite torrent trackers
+- [Jellyfin](https://github.com/jellyfin/jellyfin) - A media server for your home collection
+- [Joplin](https://github.com/laurent22/joplin) - Privacy focused note-taking app
+- [n8n](https://github.com/n8n-io/n8n) - Workflow Automation Tool
+- [Nextcloud](https://github.com/nextcloud/server) - A safe home for all your data
+- [Pihole](https://github.com/pi-hole/pi-hole) - A black hole for Internet advertisements
+- [Radarr](https://github.com/Radarr/Radarr) - Movie collection manager for Usenet and BitTorrent users.
+- [Sonarr](https://github.com/Sonarr/Sonarr) - TV show manager for Usenet and BitTorrent
+- [Syncthing](https://github.com/syncthing/syncthing) - Continuous File Synchronization
+- [Tailscale](https://github.com/tailscale/tailscale) - The easiest, most secure way to use WireGuard and 2FA.
+- [Transmission](https://github.com/transmission/transmission) - Fast, easy, and free BitTorrent client
+- [Wireguard Easy](https://github.com/WeeJeWel/wg-easy) - WireGuard VPN + Web-based Admin UI
+## 🛠 Installation
+### Installation Requirements
+- Ubuntu 18.04 LTS or higher (or Debian 10)
+
+Make sure your User ID is `1000` (verify it by running `id -u`) and ensure that your account is [correctly permissioned to use docker](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user).
+
+### Step 1. Download Tipi
+Run this in an empty directory where you want to install Tipi.
+
+```bash
+git clone https://github.com/meienberger/runtipi.git
+```
+
+### Step 2. Run Tipi
+cd into the downloaded directory and run the start script.
+
+```bash
+cd runtipi && sudo ./scripts/start.sh
+```
+
+The script will prompt you the ip address of the dashboard once configured.
+
+To stop Tipi, run the stop script.
+
+```bash
+sudo ./scripts/stop.sh
+```
+
+## ❤️ Contributing
+
+Tipi is made to be very easy to plug in new apps. We welcome and appreciate new contributions.
+
+If you want to support a new app or feature, you can:
+- Fork the repository and create a new branch for your changes.
+- Create a pull request.
+
+## 📜 License
+[![License](https://img.shields.io/github/license/meienberger/runtipi)](https://github.com/meienberger/runtipi/blob/master/LICENSE)
+
+Tipi is licensed under the GNU General Public License v3.0. TL;DR — You may copy, distribute and modify the software as long as you track changes/dates in source files. Any modifications to or software including (via compiler) GPL-licensed code must also be made available under the GPL along with build & install instructions.

+ 6 - 0
scripts/configure.sh

@@ -22,6 +22,12 @@ if ! command -v ansible-playbook > /dev/null; then
   sudo pip3 install ansible
   sudo pip3 install ansible
 fi
 fi
 
 
+# Create seed file with cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
+if [[ ! -f "${ROOT_FOLDER}/state/seed" ]]; then
+  echo "Generating seed..."
+  cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 > "${ROOT_FOLDER}/state/seed"
+fi
+
 ansible-playbook ansible/setup.yml -i ansible/hosts -K
 ansible-playbook ansible/setup.yml -i ansible/hosts -K
 
 
 # echo "Configuring permissions..."
 # echo "Configuring permissions..."

+ 37 - 9
scripts/start.sh

@@ -1,14 +1,6 @@
 #!/usr/bin/env bash
 #!/usr/bin/env bash
 set -e  # Exit immediately if a command exits with a non-zero status.
 set -e  # Exit immediately if a command exits with a non-zero status.
 
 
-# Get field from json file
-function get_json_field() {
-    local json_file="$1"
-    local field="$2"
-
-    echo $(jq -r ".${field}" "${json_file}")
-}
-
 # use greadlink instead of readlink on osx
 # use greadlink instead of readlink on osx
 if [[ "$(uname)" == "Darwin" ]]; then
 if [[ "$(uname)" == "Darwin" ]]; then
   readlink=greadlink
   readlink=greadlink
@@ -21,6 +13,31 @@ STATE_FOLDER="${ROOT_FOLDER}/state"
 INTERNAL_IP="$(hostname -I | awk '{print $1}')"
 INTERNAL_IP="$(hostname -I | awk '{print $1}')"
 DNS_IP=9.9.9.9
 DNS_IP=9.9.9.9
 
 
+# Get field from json file
+function get_json_field() {
+    local json_file="$1"
+    local field="$2"
+
+    echo $(jq -r ".${field}" "${json_file}")
+}
+
+# Deterministically derives 128 bits of cryptographically secure entropy
+function derive_entropy() {
+  SEED_FILE="${STATE_FOLDER}/seed"
+  identifier="${1}"
+  tipi_seed=$(cat "${SEED_FILE}") || true
+
+  if [[ -z "$tipi_seed" ]] || [[ -z "$identifier" ]]; then
+    >&2 echo "Missing derivation parameter, this is unsafe, exiting."
+    exit 1
+  fi
+
+  # We need `sed 's/^.* //'` to trim the "(stdin)= " prefix from some versions of openssl
+  printf "%s" "${identifier}" | openssl dgst -sha256 -hmac "${tipi_seed}" | sed 's/^.* //'
+}
+
+
+
 # Get dns ip if pihole is installed
 # Get dns ip if pihole is installed
 str=$(get_json_field ${STATE_FOLDER}/apps.json installed)
 str=$(get_json_field ${STATE_FOLDER}/apps.json installed)
 
 
@@ -61,25 +78,36 @@ export COMPOSE_HTTP_TIMEOUT=240
 echo "Generating config files..."
 echo "Generating config files..."
 # Remove current .env file
 # Remove current .env file
 [[ -f "${ROOT_FOLDER}/.env" ]] && rm -f "${ROOT_FOLDER}/.env"
 [[ -f "${ROOT_FOLDER}/.env" ]] && rm -f "${ROOT_FOLDER}/.env"
+[[ -f "${ROOT_FOLDER}/system-api/.env" ]] && rm -f "${ROOT_FOLDER}/system-api/.env"
 
 
 # Store paths to intermediary config files
 # Store paths to intermediary config files
 ENV_FILE="$ROOT_FOLDER/templates/.env"
 ENV_FILE="$ROOT_FOLDER/templates/.env"
+ENV_FILE_SYSTEM_API="$ROOT_FOLDER/templates/.env-api"
 
 
 # Remove intermediary config files
 # Remove intermediary config files
 [[ -f "$ENV_FILE" ]] && rm -f "$ENV_FILE"
 [[ -f "$ENV_FILE" ]] && rm -f "$ENV_FILE"
+[[ -f "$ENV_FILE_SYSTEM_API" ]] && rm -f "$ENV_FILE_SYSTEM_API"
 
 
 # Copy template configs to intermediary configs
 # Copy template configs to intermediary configs
 [[ -f "$ROOT_FOLDER/templates/env-sample" ]] && cp "$ROOT_FOLDER/templates/env-sample" "$ENV_FILE"
 [[ -f "$ROOT_FOLDER/templates/env-sample" ]] && cp "$ROOT_FOLDER/templates/env-sample" "$ENV_FILE"
+[[ -f "$ROOT_FOLDER/templates/env-api-sample" ]] && cp "$ROOT_FOLDER/templates/env-api-sample" "$ENV_FILE_SYSTEM_API"
+
+JWT_SECRET=$(derive_entropy "jwt")
+
+echo $JWT_SECRET
 
 
-for template in "${ENV_FILE}"; do
+for template in "${ENV_FILE}" "${ENV_FILE_SYSTEM_API}"; do
   sed -i "s/<dns_ip>/${DNS_IP}/g" "${template}"
   sed -i "s/<dns_ip>/${DNS_IP}/g" "${template}"
   sed -i "s/<internal_ip>/${INTERNAL_IP}/g" "${template}"
   sed -i "s/<internal_ip>/${INTERNAL_IP}/g" "${template}"
   sed -i "s/<puid>/${PUID}/g" "${template}"
   sed -i "s/<puid>/${PUID}/g" "${template}"
   sed -i "s/<pgid>/${PGID}/g" "${template}"
   sed -i "s/<pgid>/${PGID}/g" "${template}"
   sed -i "s/<tz>/${TZ}/g" "${template}"
   sed -i "s/<tz>/${TZ}/g" "${template}"
+  sed -i "s/<root_folder>/${ROOT_FOLDER}/g" "${template}"
+  sed -i "s/<jwt_secret>/${JWT_SECRET}/g" "${template}"
 done
 done
 
 
 mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
 mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
+mv -f "$ENV_FILE_SYSTEM_API" "$ROOT_FOLDER/system-api/.env"
 
 
 ansible-playbook ansible/start.yml -i ansible/hosts -K
 ansible-playbook ansible/start.yml -i ansible/hosts -K
 
 

+ 3 - 1
system-api/src/config/config.ts

@@ -4,11 +4,12 @@ interface IConfig {
   NODE_ENV: string;
   NODE_ENV: string;
   ROOT_FOLDER: string;
   ROOT_FOLDER: string;
   JWT_SECRET: string;
   JWT_SECRET: string;
+  CLIENT_URLS: string[];
 }
 }
 
 
 dotenv.config();
 dotenv.config();
 
 
-const { NODE_ENV = 'development', ROOT_FOLDER = '', JWT_SECRET = '' } = process.env;
+const { NODE_ENV = 'development', ROOT_FOLDER = '', JWT_SECRET = '', INTERNAL_IP = '' } = process.env;
 
 
 const missing = [];
 const missing = [];
 
 
@@ -22,6 +23,7 @@ const config: IConfig = {
   NODE_ENV,
   NODE_ENV,
   ROOT_FOLDER,
   ROOT_FOLDER,
   JWT_SECRET,
   JWT_SECRET,
+  CLIENT_URLS: ['locahost:3000', `${INTERNAL_IP}`, `${INTERNAL_IP}:3000`],
 };
 };
 
 
 export default config;
 export default config;

+ 2 - 3
system-api/src/server.ts

@@ -10,8 +10,7 @@ import systemRoutes from './modules/system/system.routes';
 import authRoutes from './modules/auth/auth.routes';
 import authRoutes from './modules/auth/auth.routes';
 import { tradeTokenForUser } from './modules/auth/auth.helpers';
 import { tradeTokenForUser } from './modules/auth/auth.helpers';
 import cookieParser from 'cookie-parser';
 import cookieParser from 'cookie-parser';
-
-// suExec.init();
+import config from './config';
 
 
 const app = express();
 const app = express();
 const port = 3001;
 const port = 3001;
@@ -24,7 +23,7 @@ if (isProd) {
   app.use(helmet());
   app.use(helmet());
 }
 }
 
 
-app.use(cors());
+app.use(cors({ credentials: true, origin: config.CLIENT_URLS }));
 
 
 // Get user from token
 // Get user from token
 app.use((req, res, next) => {
 app.use((req, res, next) => {

+ 3 - 0
templates/env-api-sample

@@ -0,0 +1,3 @@
+ROOT_FOLDER=<root_folder>
+JWT_SECRET=<jwt_secret>
+INTERNAL_IP=<internal_ip>