commit
34c9ced75a
27 changed files with 382 additions and 184 deletions
53
.github/workflows/build-images.yml
vendored
53
.github/workflows/build-images.yml
vendored
|
@ -1,53 +0,0 @@
|
||||||
name: Docker build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
-
|
|
||||||
name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v1
|
|
||||||
-
|
|
||||||
name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v1
|
|
||||||
-
|
|
||||||
name: Login to DockerHub
|
|
||||||
uses: docker/login-action@v1
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
-
|
|
||||||
name: Get tag from VERSION file
|
|
||||||
id: meta
|
|
||||||
run: |
|
|
||||||
VERSION=$(cat VERSION)
|
|
||||||
TAG=${VERSION}
|
|
||||||
echo "::set-output name=tag::${TAG}"
|
|
||||||
-
|
|
||||||
name: Build and push dashboard
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: ./packages/dashboard
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: meienberger/tipi-dashboard:latest,meienberger/tipi-dashboard:${{ steps.meta.outputs.TAG }}
|
|
||||||
cache-from: type=registry,ref=meienberger/tipi-dashboard:latest
|
|
||||||
cache-to: type=inline
|
|
||||||
-
|
|
||||||
name: Build and push api
|
|
||||||
uses: docker/build-push-action@v2
|
|
||||||
with:
|
|
||||||
context: ./packages/system-api
|
|
||||||
platforms: linux/amd64,linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: meienberger/tipi-api:latest,meienberger/tipi-api:${{ steps.meta.outputs.TAG }}
|
|
||||||
cache-from: type=registry,ref=meienberger/tipi-api:latest
|
|
||||||
cache-to: type=inline
|
|
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
@ -47,4 +47,3 @@ jobs:
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: pnpm -r test
|
run: pnpm -r test
|
||||||
|
|
||||||
|
|
98
.github/workflows/release-candidate.yml
vendored
Normal file
98
.github/workflows/release-candidate.yml
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
name: Release candidate
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Build images and publish RCs to DockerHub
|
||||||
|
build-images:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: technote-space/get-diff-action@v6
|
||||||
|
with:
|
||||||
|
FILES: |
|
||||||
|
VERSION
|
||||||
|
|
||||||
|
- name: Ensure env.MATCHED_FILES has VERSION in it
|
||||||
|
id: check-version
|
||||||
|
run: |
|
||||||
|
if [[ -z "${{ env.MATCHED_FILES }}" ]]; then
|
||||||
|
echo "::error::VERSION not modified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ ! "${{ env.MATCHED_FILES }}" =~ VERSION ]]; then
|
||||||
|
echo "::error::VERSION not modified"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- uses: vishnudxb/cancel-workflow@v1.2
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
repo: meienberger/runtipi
|
||||||
|
workflow_id: ${{ github.run_id }}
|
||||||
|
access_token: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Get tag from VERSION file
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat VERSION)
|
||||||
|
TAG=${VERSION}
|
||||||
|
echo "::set-output name=tag::${TAG}"
|
||||||
|
|
||||||
|
- name: Build and push dashboard
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./packages/dashboard
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: meienberger/tipi-dashboard:rc-${{ steps.meta.outputs.TAG }}
|
||||||
|
cache-from: type=registry,ref=meienberger/tipi-dashboard:latest
|
||||||
|
cache-to: type=inline
|
||||||
|
|
||||||
|
- name: Build and push api
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./packages/system-api
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: meienberger/tipi-api:rc-${{ steps.meta.outputs.TAG }}
|
||||||
|
cache-from: type=registry,ref=meienberger/tipi-api:latest
|
||||||
|
cache-to: type=inline
|
||||||
|
|
||||||
|
# Test installation script
|
||||||
|
# test-install:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# steps:
|
||||||
|
# - uses: actions/checkout@master
|
||||||
|
|
||||||
|
# - name: Check if user id 1000 exists
|
||||||
|
# run: |
|
||||||
|
# if [[ ! $(id -u 1000) -eq 1000 ]]; then
|
||||||
|
# echo "Creating user 1000"
|
||||||
|
# sudo useradd -u 1000 test
|
||||||
|
# fi
|
||||||
|
# id: check-user-id
|
||||||
|
|
||||||
|
# - name: Run install script
|
||||||
|
# run: sudo ./scripts/start.sh --rc --ci
|
||||||
|
|
||||||
|
|
48
.github/workflows/release.yml
vendored
48
.github/workflows/release.yml
vendored
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
name: Build & Deploy
|
name: Publish release
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
@ -30,3 +30,49 @@ jobs:
|
||||||
release_name: ${{ steps.create_tag.outputs.version }}
|
release_name: ${{ steps.create_tag.outputs.version }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
-
|
||||||
|
name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
-
|
||||||
|
name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
-
|
||||||
|
name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
-
|
||||||
|
name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
-
|
||||||
|
name: Get tag from VERSION file
|
||||||
|
id: meta
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat VERSION)
|
||||||
|
TAG=${VERSION}
|
||||||
|
echo "::set-output name=tag::${TAG}"
|
||||||
|
-
|
||||||
|
name: Build and push dashboard
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./packages/dashboard
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: meienberger/tipi-dashboard:latest,meienberger/tipi-dashboard:${{ steps.meta.outputs.TAG }}
|
||||||
|
cache-from: type=registry,ref=meienberger/tipi-dashboard:latest
|
||||||
|
cache-to: type=inline
|
||||||
|
-
|
||||||
|
name: Build and push api
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
context: ./packages/system-api
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: meienberger/tipi-api:latest,meienberger/tipi-api:${{ steps.meta.outputs.TAG }}
|
||||||
|
cache-from: type=registry,ref=meienberger/tipi-api:latest
|
||||||
|
cache-to: type=inline
|
33
.github/workflows/verify-release.yml
vendored
33
.github/workflows/verify-release.yml
vendored
|
@ -1,33 +0,0 @@
|
||||||
name: Verify release
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
verify:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
|
|
||||||
- uses: technote-space/get-diff-action@v6
|
|
||||||
with:
|
|
||||||
FILES: |
|
|
||||||
VERSION
|
|
||||||
|
|
||||||
- name: Ensure env.MATCHED_FILES has VERSION in it
|
|
||||||
id: check-version
|
|
||||||
run: |
|
|
||||||
if [[ -z "${{ env.MATCHED_FILES }}" ]]; then
|
|
||||||
echo "::error::VERSION not modified"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [[ ! "${{ env.MATCHED_FILES }}" =~ VERSION ]]; then
|
|
||||||
echo "::error::VERSION not modified"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
|
@ -32,8 +32,6 @@ Tipi is a personal homeserver orchestrator. It is running docker containers unde
|
||||||
### Installation Requirements
|
### Installation Requirements
|
||||||
- Ubuntu 18.04 LTS or higher (or Debian 10)
|
- Ubuntu 18.04 LTS or higher (or Debian 10)
|
||||||
|
|
||||||
Make sure your User ID is `1000` (verify it by running `id -u`)
|
|
||||||
|
|
||||||
### Step 1. Download Tipi
|
### Step 1. Download Tipi
|
||||||
Run this in an empty directory where you want to install Tipi.
|
Run this in an empty directory where you want to install Tipi.
|
||||||
|
|
||||||
|
@ -49,6 +47,11 @@ cd runtipi && sudo ./scripts/start.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
The script will prompt you the ip address of the dashboard once configured.
|
The script will prompt you the ip address of the dashboard once configured.
|
||||||
|
Tipi will run by default on port 80. To select another port you can run the start script with the `--port` argument
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./scripts/start.sh --port 7000
|
||||||
|
```
|
||||||
|
|
||||||
To stop Tipi, run the stop script.
|
To stop Tipi, run the stop script.
|
||||||
|
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
0.1.3
|
0.1.4
|
|
@ -21,11 +21,11 @@
|
||||||
when: lsb_release.stdout == 'Debian'
|
when: lsb_release.stdout == 'Debian'
|
||||||
|
|
||||||
- name: Add deb repo for docker (Ubuntu)
|
- name: Add deb repo for docker (Ubuntu)
|
||||||
shell: echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
shell: echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
when: lsb_release.stdout == 'Ubuntu'
|
when: lsb_release.stdout == 'Ubuntu'
|
||||||
|
|
||||||
- name: Add deb repo for docker (Debian)
|
- name: Add deb repo for docker (Debian)
|
||||||
shell: echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
shell: echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||||
when: lsb_release.stdout == 'Debian'
|
when: lsb_release.stdout == 'Debian'
|
||||||
|
|
||||||
- name: Update packages
|
- name: Update packages
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
name: "{{ packages }}"
|
name: "{{ packages }}"
|
||||||
state: latest
|
state: latest
|
||||||
|
|
||||||
|
- name: Upgrade packages
|
||||||
|
apt:
|
||||||
|
upgrade: yes
|
||||||
|
|
||||||
- name: Add user to root group
|
- name: Add user to root group
|
||||||
user:
|
user:
|
||||||
name: "{{ username }}"
|
name: "{{ username }}"
|
||||||
|
@ -26,3 +30,4 @@
|
||||||
user: "{{ username }}"
|
user: "{{ username }}"
|
||||||
minute: "*/1"
|
minute: "*/1"
|
||||||
job: "{{ playbook_dir }}/../scripts/system-info.sh"
|
job: "{{ playbook_dir }}/../scripts/system-info.sh"
|
||||||
|
ignore_errors: yes
|
|
@ -8,7 +8,8 @@ services:
|
||||||
- PUID=1000
|
- PUID=1000
|
||||||
- PGID=1000
|
- PGID=1000
|
||||||
volumes:
|
volumes:
|
||||||
- ${APP_DATA_DIR}/../..:/srv
|
- ${ROOT_FOLDER_HOST}/app-data:/srv/app-data
|
||||||
|
- ${ROOT_FOLDER_HOST}/media:/srv/media
|
||||||
- ${APP_DATA_DIR}/data/db:/database
|
- ${APP_DATA_DIR}/data/db:/database
|
||||||
- ${APP_DATA_DIR}/data/config:/config
|
- ${APP_DATA_DIR}/data/config:/config
|
||||||
networks:
|
networks:
|
||||||
|
|
60
docker-compose.rc.yml
Normal file
60
docker-compose.rc.yml
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
version: "3.7"
|
||||||
|
|
||||||
|
services:
|
||||||
|
reverse-proxy:
|
||||||
|
container_name: reverse-proxy
|
||||||
|
image: traefik:v2.6
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- ${NGINX_PORT}:80
|
||||||
|
- ${PROXY_PORT}:8080
|
||||||
|
command: --api.insecure=true --providers.docker
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- ${PWD}/traefik:/root/.config
|
||||||
|
networks:
|
||||||
|
- tipi_main_network
|
||||||
|
|
||||||
|
api:
|
||||||
|
image: meienberger/tipi-api:rc-${TIPI_VERSION}
|
||||||
|
container_name: api
|
||||||
|
ports:
|
||||||
|
- 3001:3001
|
||||||
|
volumes:
|
||||||
|
## Docker sock
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- ${PWD}:/tipi
|
||||||
|
environment:
|
||||||
|
- INTERNAL_IP=${INTERNAL_IP}
|
||||||
|
- TIPI_VERSION=${TIPI_VERSION}
|
||||||
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
|
- ROOT_FOLDER_HOST=${ROOT_FOLDER_HOST}
|
||||||
|
networks:
|
||||||
|
- tipi_main_network
|
||||||
|
|
||||||
|
dashboard:
|
||||||
|
image: meienberger/tipi-dashboard:rc-${TIPI_VERSION}
|
||||||
|
container_name: dashboard
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
networks:
|
||||||
|
- tipi_main_network
|
||||||
|
environment:
|
||||||
|
- INTERNAL_IP=${INTERNAL_IP}
|
||||||
|
labels:
|
||||||
|
traefik.enable: true
|
||||||
|
traefik.http.routers.dashboard.rule: PathPrefix("/") # Host(`tipi.local`) &&
|
||||||
|
traefik.http.routers.dashboard.entrypoints: webinsecure
|
||||||
|
traefik.http.routers.dashboard.service: dashboard
|
||||||
|
traefik.http.services.dashboard.loadbalancer.server.port: 3000
|
||||||
|
|
||||||
|
networks:
|
||||||
|
tipi_main_network:
|
||||||
|
driver: bridge
|
||||||
|
driver_opts:
|
||||||
|
com.docker.network.bridge.enable_ip_masquerade: "true"
|
||||||
|
com.docker.network.bridge.enable_icc: "true"
|
||||||
|
ipam:
|
||||||
|
driver: default
|
||||||
|
config:
|
||||||
|
- subnet: 10.21.21.0/24
|
|
@ -6,8 +6,8 @@ services:
|
||||||
image: traefik:v2.6
|
image: traefik:v2.6
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- ${NGINX_PORT}:80
|
||||||
- 8080:8080
|
- ${PROXY_PORT}:8080
|
||||||
command: --api.insecure=true --providers.docker
|
command: --api.insecure=true --providers.docker
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
@ -15,7 +15,6 @@ services:
|
||||||
networks:
|
networks:
|
||||||
- tipi_main_network
|
- tipi_main_network
|
||||||
|
|
||||||
|
|
||||||
api:
|
api:
|
||||||
image: meienberger/tipi-api:${TIPI_VERSION}
|
image: meienberger/tipi-api:${TIPI_VERSION}
|
||||||
container_name: api
|
container_name: api
|
||||||
|
@ -30,6 +29,7 @@ services:
|
||||||
- TIPI_VERSION=${TIPI_VERSION}
|
- TIPI_VERSION=${TIPI_VERSION}
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
- ROOT_FOLDER_HOST=${ROOT_FOLDER_HOST}
|
- ROOT_FOLDER_HOST=${ROOT_FOLDER_HOST}
|
||||||
|
- NGINX_PORT=${NGINX_PORT}
|
||||||
networks:
|
networks:
|
||||||
- tipi_main_network
|
- tipi_main_network
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "runtipi",
|
"name": "runtipi",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"description": "A homeserver for everyone",
|
"description": "A homeserver for everyone",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"act:test-install": "act --container-architecture linux/amd64 -j test-install",
|
"act:test-install": "act --container-architecture linux/amd64 -j test-install",
|
||||||
"act:docker": "act --container-architecture linux/amd64 --secret-file github.secrets -j docker",
|
"act:docker": "act --container-architecture linux/amd64 --secret-file github.secrets -j docker",
|
||||||
"start:dev": "docker-compose -f docker-compose.dev.yml --env-file .env.dev up --build",
|
"start:dev": "docker-compose -f docker-compose.dev.yml --env-file .env.dev up --build",
|
||||||
|
"start:rc": "docker-compose -f docker-compose.rc.yml --env-file .env up --build",
|
||||||
"start:prod": "docker-compose --env-file .env up --build"
|
"start:prod": "docker-compose --env-file .env up --build"
|
||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
singleQuote: true,
|
singleQuote: true,
|
||||||
semi: true,
|
semi: true,
|
||||||
trailingComma: "all",
|
trailingComma: 'all',
|
||||||
printWidth: 200,
|
printWidth: 200,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
FROM node:18
|
FROM node:18-buster-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ./package.json ./
|
COPY ./package.json ./
|
||||||
|
|
||||||
RUN yarn
|
RUN npm install
|
||||||
|
|
||||||
COPY ./ ./
|
COPY ./ ./
|
||||||
|
|
||||||
RUN yarn build
|
RUN npm run build
|
||||||
|
|
||||||
CMD ["yarn", "start"]
|
CMD ["npm", "run", "start"]
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:latest
|
FROM node:18-buster-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "dashboard",
|
"name": "dashboard",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "system-api",
|
"name": "system-api",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"description": "",
|
"description": "",
|
||||||
"exports": "./dist/server.js",
|
"exports": "./dist/server.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
@ -11,13 +11,13 @@ interface IConfig {
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
const { NODE_ENV = 'development', JWT_SECRET = '', INTERNAL_IP = '', TIPI_VERSION = '', ROOT_FOLDER_HOST = '' } = process.env;
|
const { NODE_ENV = 'development', JWT_SECRET = '', INTERNAL_IP = '', TIPI_VERSION = '', ROOT_FOLDER_HOST = '', NGINX_PORT = '80' } = process.env;
|
||||||
|
|
||||||
const config: IConfig = {
|
const config: IConfig = {
|
||||||
NODE_ENV,
|
NODE_ENV,
|
||||||
ROOT_FOLDER: '/tipi',
|
ROOT_FOLDER: '/tipi',
|
||||||
JWT_SECRET,
|
JWT_SECRET,
|
||||||
CLIENT_URLS: ['http://localhost:3000', `http://${INTERNAL_IP}`, `http://${INTERNAL_IP}:3000`],
|
CLIENT_URLS: ['http://localhost:3000', `http://${INTERNAL_IP}`, `http://${INTERNAL_IP}:${NGINX_PORT}`, `http://${INTERNAL_IP}:3000`],
|
||||||
VERSION: TIPI_VERSION,
|
VERSION: TIPI_VERSION,
|
||||||
ROOT_FOLDER_HOST,
|
ROOT_FOLDER_HOST,
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,7 +75,9 @@ const getVersion = async (_: Request, res: Response<{ current: string; latest: s
|
||||||
version = json.name.replace('v', '');
|
version = json.name.replace('v', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).send({ current: config.VERSION, latest: version });
|
TipiCache.set('latestVersion', version.replace('v', ''));
|
||||||
|
|
||||||
|
res.status(200).send({ current: config.VERSION, latest: version.replace('v', '') });
|
||||||
};
|
};
|
||||||
|
|
||||||
export default { getCpuInfo, getDiskInfo, getMemoryInfo, getVersion };
|
export default { getCpuInfo, getDiskInfo, getMemoryInfo, getVersion };
|
||||||
|
|
|
@ -12,7 +12,7 @@ ROOT_FOLDER="$($rdlk -f $(dirname "${BASH_SOURCE[0]}")/..)"
|
||||||
STATE_FOLDER="${ROOT_FOLDER}/state"
|
STATE_FOLDER="${ROOT_FOLDER}/state"
|
||||||
|
|
||||||
show_help() {
|
show_help() {
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
app 0.0.1
|
app 0.0.1
|
||||||
|
|
||||||
CLI for managing Tipi apps
|
CLI for managing Tipi apps
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
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.
|
||||||
|
|
||||||
ROOT_FOLDER="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
|
ROOT_FOLDER="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
|
||||||
USERNAME="$(id -nu 1000)"
|
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
|
@ -15,19 +14,39 @@ echo "=============== TIPI ================="
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Install ansible if not installed
|
sudo apt-get update
|
||||||
if ! command -v ansible-playbook > /dev/null; then
|
sudo apt-get install -y jq coreutils ca-certificates curl gnupg lsb-release
|
||||||
echo "Installing Ansible..."
|
|
||||||
sudo apt-get update
|
LSB="$(lsb_release -is)"
|
||||||
sudo apt-get install python3 python3-pip -y
|
|
||||||
sudo pip3 install ansible
|
# Add docker gpg key (Debian)
|
||||||
|
if [[ "${LSB}" == "Debian" ]]; then
|
||||||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ansible-playbook ansible/setup.yml -i ansible/hosts -K -e username="$USERNAME"
|
# Add docker gpg key (Ubuntu)
|
||||||
|
if [[ "${LSB}" == "Ubuntu" ]]; then
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
||||||
|
fi
|
||||||
|
|
||||||
# echo "Configuring permissions..."
|
# Add deb repo for docker (Debian)
|
||||||
# echo
|
if [[ "${LSB}" == "Debian" ]]; then
|
||||||
# find "$ROOT_FOLDER" -path "$ROOT_FOLDER/app-data" -prune -o -exec chown 1000:1000 {} + || true
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add deb repo for docker (Ubuntu)
|
||||||
|
if [[ "${LSB}" == "Ubuntu" ]]; then
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||||
|
|
||||||
|
# Install docker compose if not here
|
||||||
|
if ! command -v docker-compose >/dev/null; then
|
||||||
|
sudo curl -L "https://github.com/docker/compose/releases/download/v2.3.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||||
|
sudo chmod +x /usr/local/bin/docker-compose
|
||||||
|
fi
|
||||||
|
|
||||||
# Create configured status
|
# Create configured status
|
||||||
touch "${ROOT_FOLDER}/state/configured"
|
touch "${ROOT_FOLDER}/state/configured"
|
103
scripts/start.sh
103
scripts/start.sh
|
@ -8,15 +8,58 @@ else
|
||||||
readlink=readlink
|
readlink=readlink
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
NGINX_PORT=80
|
||||||
|
PROXY_PORT=8080
|
||||||
|
|
||||||
|
while [ -n "$1" ]; do # while loop starts
|
||||||
|
case "$1" in
|
||||||
|
--rc) rc="true" ;;
|
||||||
|
--ci) ci="true" ;;
|
||||||
|
--port)
|
||||||
|
port="$2"
|
||||||
|
|
||||||
|
if [[ "${port}" =~ ^[0-9]+$ ]]; then
|
||||||
|
NGINX_PORT="${port}"
|
||||||
|
else
|
||||||
|
echo "--port must be a number"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--proxy-port)
|
||||||
|
proxy_port="$2"
|
||||||
|
|
||||||
|
if [[ "${proxy_port}" =~ ^[0-9]+$ ]]; then
|
||||||
|
PROXY_PORT="${proxy_port}"
|
||||||
|
else
|
||||||
|
echo "--proxy-port must be a number"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift # The double dash makes them parameters
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*) echo "Option $1 not recognized" && exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check we are on linux
|
||||||
|
if [[ "$(uname)" != "Linux" ]]; then
|
||||||
|
echo "Tipi only works on Linux"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
ROOT_FOLDER="$($readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
|
ROOT_FOLDER="$($readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
|
||||||
STATE_FOLDER="${ROOT_FOLDER}/state"
|
STATE_FOLDER="${ROOT_FOLDER}/state"
|
||||||
SED_ROOT_FOLDER="$(echo $ROOT_FOLDER | sed 's/\//\\\//g')"
|
SED_ROOT_FOLDER="$(echo $ROOT_FOLDER | sed 's/\//\\\//g')"
|
||||||
INTERNAL_IP="$(hostname -I | awk '{print $1}')"
|
INTERNAL_IP="$(hostname -I | awk '{print $1}')"
|
||||||
DNS_IP=9.9.9.9 # Default to Quad9 DNS
|
DNS_IP=9.9.9.9 # Default to Quad9 DNS
|
||||||
USERNAME="$(id -nu 1000)"
|
|
||||||
ARCHITECTURE="$(uname -m)"
|
ARCHITECTURE="$(uname -m)"
|
||||||
|
|
||||||
if [[ "$architecture" == "aarch64" ]]; then
|
if [[ "$ARCHITECTURE" == "aarch64" ]]; then
|
||||||
ARCHITECTURE="arm64"
|
ARCHITECTURE="arm64"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -47,7 +90,7 @@ function derive_entropy() {
|
||||||
tipi_seed=$(cat "${SEED_FILE}") || true
|
tipi_seed=$(cat "${SEED_FILE}") || true
|
||||||
|
|
||||||
if [[ -z "$tipi_seed" ]] || [[ -z "$identifier" ]]; then
|
if [[ -z "$tipi_seed" ]] || [[ -z "$identifier" ]]; then
|
||||||
>&2 echo "Missing derivation parameter, this is unsafe, exiting."
|
echo >&2 "Missing derivation parameter, this is unsafe, exiting."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -69,8 +112,10 @@ if [[ ! -f "${STATE_FOLDER}/users.json" ]]; then
|
||||||
cp "${ROOT_FOLDER}/templates/users-sample.json" "${STATE_FOLDER}/users.json"
|
cp "${ROOT_FOLDER}/templates/users-sample.json" "${STATE_FOLDER}/users.json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
chown -R 1000:1000 "${STATE_FOLDER}/apps.json"
|
# Get current dns from host
|
||||||
chown -R 1000:1000 "${STATE_FOLDER}/users.json"
|
if [[ -f "/etc/resolv.conf" ]]; then
|
||||||
|
TEMP=$(cat /etc/resolv.conf | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -n 1)
|
||||||
|
fi
|
||||||
|
|
||||||
# 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)
|
||||||
|
@ -83,7 +128,7 @@ fi
|
||||||
# Create seed file with cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
|
# Create seed file with cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
|
||||||
if [[ ! -f "${STATE_FOLDER}/seed" ]]; then
|
if [[ ! -f "${STATE_FOLDER}/seed" ]]; then
|
||||||
echo "Generating seed..."
|
echo "Generating seed..."
|
||||||
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 > "${STATE_FOLDER}/seed"
|
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 >"${STATE_FOLDER}/seed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export DOCKER_CLIENT_TIMEOUT=240
|
export DOCKER_CLIENT_TIMEOUT=240
|
||||||
|
@ -112,7 +157,8 @@ for template in "${ENV_FILE}"; do
|
||||||
sed -i "s/<root_folder>/${SED_ROOT_FOLDER}/g" "${template}"
|
sed -i "s/<root_folder>/${SED_ROOT_FOLDER}/g" "${template}"
|
||||||
sed -i "s/<tipi_version>/$(cat "${ROOT_FOLDER}/VERSION")/g" "${template}"
|
sed -i "s/<tipi_version>/$(cat "${ROOT_FOLDER}/VERSION")/g" "${template}"
|
||||||
sed -i "s/<architecture>/${ARCHITECTURE}/g" "${template}"
|
sed -i "s/<architecture>/${ARCHITECTURE}/g" "${template}"
|
||||||
|
sed -i "s/<nginx_port>/${NGINX_PORT}/g" "${template}"
|
||||||
|
sed -i "s/<proxy_port>/${PROXY_PORT}/g" "${template}"
|
||||||
done
|
done
|
||||||
|
|
||||||
mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
|
mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
|
||||||
|
@ -121,28 +167,29 @@ mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
|
||||||
echo "Running system-info.sh..."
|
echo "Running system-info.sh..."
|
||||||
bash "${ROOT_FOLDER}/scripts/system-info.sh"
|
bash "${ROOT_FOLDER}/scripts/system-info.sh"
|
||||||
|
|
||||||
# ansible-playbook ansible/start.yml -i ansible/hosts -K -e username="$USERNAME"
|
## Don't run if config-only
|
||||||
|
if [[ ! $ci == "true" ]]; then
|
||||||
|
|
||||||
docker-compose --env-file "${ROOT_FOLDER}/.env" pull
|
if [[ $rc == "true" ]]; then
|
||||||
# Run docker-compose
|
docker-compose -f docker-compose.rc.yml --env-file "${ROOT_FOLDER}/.env" pull
|
||||||
docker-compose --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {
|
# Run docker-compose
|
||||||
|
docker-compose -f docker-compose.rc.yml --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {
|
||||||
echo "Failed to start containers"
|
echo "Failed to start containers"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
else
|
||||||
# str=$(get_json_field ${STATE_FOLDER}/apps.json installed)
|
docker-compose --env-file "${ROOT_FOLDER}/.env" pull
|
||||||
# apps_to_start=($str)
|
# Run docker-compose
|
||||||
|
docker-compose --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {
|
||||||
# for app in "${apps_to_start[@]}"; do
|
echo "Failed to start containers"
|
||||||
# "${ROOT_FOLDER}/scripts/app.sh" start $app
|
exit 1
|
||||||
# done
|
}
|
||||||
|
fi
|
||||||
# Give permissions 1000:1000 to app data
|
fi
|
||||||
chown -R 1000:1000 "${ROOT_FOLDER}/app-data"
|
|
||||||
|
|
||||||
echo "Tipi is now running"
|
echo "Tipi is now running"
|
||||||
echo ""
|
echo ""
|
||||||
cat << "EOF"
|
cat <<"EOF"
|
||||||
_,.
|
_,.
|
||||||
,` -.)
|
,` -.)
|
||||||
'( _/'-\\-.
|
'( _/'-\\-.
|
||||||
|
@ -164,8 +211,12 @@ cat << "EOF"
|
||||||
| {__)
|
| {__)
|
||||||
()`
|
()`
|
||||||
EOF
|
EOF
|
||||||
echo ""
|
|
||||||
echo "Visit http://${INTERNAL_IP}/ to view the dashboard"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
|
port_display=""
|
||||||
|
if [[ $NGINX_PORT != "80" ]]; then
|
||||||
|
port_display=":${NGINX_PORT}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Visit http://${INTERNAL_IP}${port_display}/ to view the dashboard"
|
||||||
|
echo ""
|
||||||
|
|
|
@ -8,7 +8,6 @@ else
|
||||||
readlink=readlink
|
readlink=readlink
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ $UID != 0 ]]; then
|
if [[ $UID != 0 ]]; then
|
||||||
echo "Tipi must be stopped as root"
|
echo "Tipi must be stopped as root"
|
||||||
echo "Please re-run this script as"
|
echo "Please re-run this script as"
|
||||||
|
@ -21,8 +20,6 @@ STATE_FOLDER="${ROOT_FOLDER}/state"
|
||||||
|
|
||||||
cd "$ROOT_FOLDER"
|
cd "$ROOT_FOLDER"
|
||||||
|
|
||||||
ansible-playbook ansible/stop.yml -i ansible/hosts -e username="$USER"
|
|
||||||
|
|
||||||
export DOCKER_CLIENT_TIMEOUT=240
|
export DOCKER_CLIENT_TIMEOUT=240
|
||||||
export COMPOSE_HTTP_TIMEOUT=240
|
export COMPOSE_HTTP_TIMEOUT=240
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ MEM_USED_BYTES=$(($MEM_TOTAL_BYTES - $MEM_AVAILABLE_BYTES))
|
||||||
|
|
||||||
# Create temporary json file
|
# Create temporary json file
|
||||||
TEMP_JSON_FILE=$(mktemp)
|
TEMP_JSON_FILE=$(mktemp)
|
||||||
echo '{ "cpu": { "load": '"${CPU_LOAD_PERCENTAGE}"' }, "memory": { "total": '"${MEM_TOTAL_BYTES}"' , "used": '"${MEM_USED_BYTES}"', "available": '"${MEM_AVAILABLE_BYTES}"' }, "disk": { "total": '"${TOTAL_DISK_SPACE_BYTES}"' , "used": '"${USED_DISK_SPACE_BYTES}"', "available": '"${AVAILABLE_DISK_SPACE_BYTES}"' } }' > "${TEMP_JSON_FILE}"
|
echo '{ "cpu": { "load": '"${CPU_LOAD_PERCENTAGE}"' }, "memory": { "total": '"${MEM_TOTAL_BYTES}"' , "used": '"${MEM_USED_BYTES}"', "available": '"${MEM_AVAILABLE_BYTES}"' }, "disk": { "total": '"${TOTAL_DISK_SPACE_BYTES}"' , "used": '"${USED_DISK_SPACE_BYTES}"', "available": '"${AVAILABLE_DISK_SPACE_BYTES}"' } }' >"${TEMP_JSON_FILE}"
|
||||||
|
|
||||||
# Write to state file
|
# Write to state file
|
||||||
echo "$(cat "${TEMP_JSON_FILE}")" > "${STATE_FOLDER}/system-info.json"
|
echo "$(cat "${TEMP_JSON_FILE}")" >"${STATE_FOLDER}/system-info.json"
|
||||||
|
|
|
@ -10,3 +10,5 @@ ARCHITECTURE=<architecture>
|
||||||
TIPI_VERSION=<tipi_version>
|
TIPI_VERSION=<tipi_version>
|
||||||
JWT_SECRET=<jwt_secret>
|
JWT_SECRET=<jwt_secret>
|
||||||
ROOT_FOLDER_HOST=<root_folder>
|
ROOT_FOLDER_HOST=<root_folder>
|
||||||
|
NGINX_PORT=<nginx_port>
|
||||||
|
PROXY_PORT=<proxy_port>
|
Loading…
Add table
Reference in a new issue