Merge pull request #13 from meienberger/develop

Develop
This commit is contained in:
Nicolas Meienberger 2022-05-07 06:31:07 +00:00 committed by GitHub
commit a2feb47d77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 15882 additions and 702 deletions

1
.gitignore vendored
View file

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

View file

@ -1,7 +1,68 @@
![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-Not%20Supported-red?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)
> ⚠️ 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.

View file

@ -11,6 +11,7 @@ packages:
- npm
username: nicolas
jwt_secret: test
### ZSH Settings
zsh_theme: "powerlevel10k/powerlevel10k"

View file

@ -14,6 +14,7 @@
dest: "{{ playbook_dir }}/../system-api/.env"
content: |
ROOT_FOLDER={{ playbook_dir }}/../
JWT_SECRET={{ jwt_secret }}
- name: Install packages based on package.json.
community.general.npm:

View file

View file

2
dashboard/.dockerignore Normal file
View file

@ -0,0 +1,2 @@
node_modules/
.next/

View file

@ -1,4 +1,4 @@
FROM node:latest
FROM node:18
WORKDIR /app

View file

@ -19,9 +19,9 @@
"framer-motion": "^6",
"immer": "^9.0.12",
"js-cookie": "^3.0.1",
"next": "12.1.4",
"react": "18.0.0",
"react-dom": "18.0.0",
"next": "12.1.6",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-final-form": "^6.5.9",
"react-icons": "^4.3.1",
"swr": "^1.3.0",
@ -31,9 +31,9 @@
},
"devDependencies": {
"@types/js-cookie": "^3.0.2",
"@types/node": "17.0.23",
"@types/react": "17.0.43",
"@types/react-dom": "17.0.14",
"@types/node": "17.0.31",
"@types/react": "18.0.8",
"@types/react-dom": "18.0.3",
"@types/validator": "^13.7.2",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"autoprefixer": "^10.4.4",
@ -42,6 +42,6 @@
"eslint-config-next": "12.1.4",
"postcss": "^8.4.12",
"tailwindcss": "^3.0.23",
"typescript": "4.6.3"
"typescript": "4.6.4"
}
}

View file

@ -10,6 +10,7 @@ import MenuDrawer from './MenuDrawer';
interface IProps {
loading?: boolean;
breadcrumbs?: { name: string; href: string; current?: boolean }[];
children: React.ReactNode;
}
const Layout: React.FC<IProps> = ({ children, loading, breadcrumbs }) => {

View file

@ -4,6 +4,7 @@ import React from 'react';
interface IProps {
isOpen: boolean;
onClose: () => void;
children: React.ReactNode;
}
const MenuDrawer: React.FC<IProps> = ({ children, isOpen, onClose }) => {

View file

@ -4,6 +4,7 @@ import React from 'react';
interface IProps {
title: string;
description: string;
children: React.ReactNode;
}
const AuthFormLayout: React.FC<IProps> = ({ children, title, description }) => {

View file

@ -4,7 +4,11 @@ import { useAuthStore } from '../../../state/authStore';
import Login from './Login';
import Onboarding from './Onboarding';
const AuthWrapper: React.FC = ({ children }) => {
interface IProps {
children: React.ReactNode;
}
const AuthWrapper: React.FC<IProps> = ({ children }) => {
const [initialLoad, setInitialLoad] = useState(true);
const { configured, user, me, fetchConfigured } = useAuthStore();

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,12 @@ if ! command -v ansible-playbook > /dev/null; then
sudo pip3 install ansible
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
# echo "Configuring permissions..."

View file

@ -1,14 +1,6 @@
#!/usr/bin/env bash
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
if [[ "$(uname)" == "Darwin" ]]; then
readlink=greadlink
@ -21,6 +13,31 @@ STATE_FOLDER="${ROOT_FOLDER}/state"
INTERNAL_IP="$(hostname -I | awk '{print $1}')"
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
str=$(get_json_field ${STATE_FOLDER}/apps.json installed)
@ -47,7 +64,12 @@ fi
# Copy the app state if it isn't here
if [[ ! -f "${STATE_FOLDER}/apps.json" ]]; then
cp "${ROOT_FOLDER}/templates/apps-sample.json" "${STATE_FOLDER}/apps.json"
cp "${ROOT_FOLDER}/templates/apps-sample.json" "${STATE_FOLDER}/apps.json" && chown -R "1000:1000" "${STATE_FOLDER}/users.json"
fi
# Copy the user state if it isn't here
if [[ ! -f "${STATE_FOLDER}/users.json" ]]; then
cp "${ROOT_FOLDER}/templates/users-sample.json" "${STATE_FOLDER}/users.json" && chown -R "1000:1000" "${STATE_FOLDER}/users.json"
fi
export DOCKER_CLIENT_TIMEOUT=240
@ -56,25 +78,36 @@ export COMPOSE_HTTP_TIMEOUT=240
echo "Generating config files..."
# Remove current .env file
[[ -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
ENV_FILE="$ROOT_FOLDER/templates/.env"
ENV_FILE_SYSTEM_API="$ROOT_FOLDER/templates/.env-api"
# Remove intermediary config files
[[ -f "$ENV_FILE" ]] && rm -f "$ENV_FILE"
[[ -f "$ENV_FILE_SYSTEM_API" ]] && rm -f "$ENV_FILE_SYSTEM_API"
# 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-api-sample" ]] && cp "$ROOT_FOLDER/templates/env-api-sample" "$ENV_FILE_SYSTEM_API"
for template in "${ENV_FILE}"; do
JWT_SECRET=$(derive_entropy "jwt")
echo $JWT_SECRET
for template in "${ENV_FILE}" "${ENV_FILE_SYSTEM_API}"; do
sed -i "s/<dns_ip>/${DNS_IP}/g" "${template}"
sed -i "s/<internal_ip>/${INTERNAL_IP}/g" "${template}"
sed -i "s/<puid>/${PUID}/g" "${template}"
sed -i "s/<pgid>/${PGID}/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
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
@ -84,8 +117,6 @@ docker-compose --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --b
exit 1
}
str=$(get_json_field ${STATE_FOLDER}/apps.json installed)
apps_to_start=($str)

File diff suppressed because it is too large Load diff

View file

@ -4,11 +4,12 @@ interface IConfig {
NODE_ENV: string;
ROOT_FOLDER: string;
JWT_SECRET: string;
CLIENT_URLS: string[];
}
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 = [];
@ -22,6 +23,7 @@ const config: IConfig = {
NODE_ENV,
ROOT_FOLDER,
JWT_SECRET,
CLIENT_URLS: ['locahost:3000', `${INTERNAL_IP}`, `${INTERNAL_IP}:3000`],
};
export default config;

View file

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

3
templates/env-api-sample Normal file
View file

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