Update README
This commit is contained in:
parent
bd68df8995
commit
2d71de5c10
7 changed files with 119 additions and 18 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
.env
|
.env
|
||||||
|
.env*
|
||||||
nginx/*
|
nginx/*
|
||||||
letsencrypt/*
|
letsencrypt/*
|
||||||
app-data/*
|
app-data/*
|
||||||
|
|
72
README.md
72
README.md
|
@ -1,7 +1,69 @@
|
||||||

|
|
||||||

|
# ⛺️ Tipi — A personal homeserver for everyone
|
||||||

|
[](https://github.com/meienberger/runtipi/blob/master/LICENSE)
|
||||||

|
[](https://github.com/meienberger/runtipi/releases)
|
||||||

|

|
||||||
|

|
||||||
|
|
||||||

|

|
||||||
|
> ⚠️ 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
|
||||||
|
[](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.
|
||||||
|
|
|
@ -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..."
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
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/<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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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';
|
||||||
|
import config from './config';
|
||||||
// suExec.init();
|
|
||||||
|
|
||||||
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
templates/env-api-sample
Normal file
3
templates/env-api-sample
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
ROOT_FOLDER=<root_folder>
|
||||||
|
JWT_SECRET=<jwt_secret>
|
||||||
|
INTERNAL_IP=<internal_ip>
|
Loading…
Add table
Reference in a new issue