فهرست منبع

Merge pull request #20 from meienberger/feature/arm64

Support different architectures for apps
Nicolas Meienberger 3 سال پیش
والد
کامیت
7612d689e4

+ 0 - 2
ansible/host_vars/tipi.yml

@@ -7,8 +7,6 @@ packages:
   - git
   - docker
   - avahi-daemon
-  - nodejs
-  - npm
 
 ### ZSH Settings
 zsh_theme: "powerlevel10k/powerlevel10k"

+ 3 - 5
ansible/tasks/common/docker.yml

@@ -9,7 +9,7 @@
     state: latest
 
 - name: Add docker gpg key
-  shell: curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
+  shell: curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg -y
 
 - name: Check lsb_release -cs
   shell: lsb_release -cs
@@ -20,7 +20,7 @@
   when: lsb_release.stdout == "bookworm"
 
 - name: Add deb for non-bookworm
-  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/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
   when: lsb_release.stdout != "bookworm"
 
 - name: Update packages
@@ -54,9 +54,7 @@
     name: docker
 
 - name: Put user in docker group
-  user:
-    name: "{{ username }}"
-    group: docker
+  shell: usermod -aG docker {{ username }}
 
 - name: Start docker service
   service:

+ 17 - 12
ansible/tasks/common/essential.yml

@@ -1,7 +1,13 @@
-# - name: Update packages
-#   apt:
-#     update_cache: yes
-#     upgrade: yes
+- name: Update packages
+  apt:
+    update_cache: yes
+    upgrade: yes
+
+- name: Install node 16
+  shell: curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
+
+- name: Install node
+  shell: apt-get install -y nodejs
 
 - name: Install essential packages
   package:
@@ -13,12 +19,12 @@
     name: "{{ username }}"
     group: root
 
-- name: Disable SSH password auth
-  lineinfile:
-    dest: /etc/ssh/sshd_config
-    regexp: "^#PasswordAuthentication yes"
-    line: "PasswordAuthentication no"
-  register: sshd_config
+# - name: Disable SSH password auth
+#   lineinfile:
+#     dest: /etc/ssh/sshd_config
+#     regexp: "^#PasswordAuthentication yes"
+#     line: "PasswordAuthentication no"
+#   register: sshd_config
 
 - name: Enable passwordless sudo for user
   lineinfile:
@@ -31,7 +37,6 @@
   service:
     name: sshd
     state: restarted
-  when: sshd_config.changed
 
 - name: Allow SSH in UFW
   community.general.ufw:
@@ -55,7 +60,7 @@
 - name: Allow ports for apps
   community.general.ufw:
     rule: allow
-    port: 8080:8180
+    port: 3000:3001
     proto: tcp
 
 - name: Enable ufw daemon

+ 1 - 0
ansible/tasks/common/packages.yml

@@ -21,6 +21,7 @@
   shell: cd {{ playbook_dir }} && pnpm -r clean
 
 - name: Build packages
+  become_user: "{{ username }}"
   shell: cd {{ playbook_dir }} && pnpm -r build-prod
 
 - name: Check if app is already running

+ 1 - 0
apps/filerun/config.json

@@ -1,6 +1,7 @@
 {
   "name": "FileRun",
   "port": 8087,
+  "available": false,
   "id": "filerun",
   "description": "Reliable and Performant File Management Desktop Sync and File Sharing",
   "short_desc": "Access your homeserver files from your browser",

+ 10 - 9
apps/freshrss/docker-compose.yml

@@ -2,23 +2,24 @@ version: "3.7"
 
 services:
   freshrss:
+    image: lscr.io/linuxserver/freshrss:1.19.2
     container_name: freshrss
-    image: freshrss/freshrss:arm
-    restart: unless-stopped
+    environment:
+      - PUID=1000
+      - PGID=1000
+      - TZ=${TZ}
+    volumes:
+      - ${APP_DATA_DIR}/data/freshrss:/config
     ports:
       - ${APP_PORT}:80
-    volumes:
-      - ${APP_DATA_DIR}/data/freshrss:/var/www/FreshRSS/data
-      - ${APP_DATA_DIR}/data/extensions/:/var/www/FreshRSS/extensions
-    environment:
-      CRON_MIN: '*/20'
-      TZ: $TZ
+    restart: unless-stopped
     networks:
       - tipi_main_network
+
     # labels:
     #     traefik.enable: true
     #     traefik.http.routers.freshrss.rule: Host(`freshrss.tipi.home`)
     #     traefik.http.routers.freshrss.service: freshrss
     #     traefik.http.routers.freshrss.tls: true
     #     traefik.http.routers.freshrss.entrypoints: websecure
-    #     traefik.http.services.freshrss.loadbalancer.server.port: 80
+    #     traefik.http.services.freshrss.loadbalancer.server.port: 80

+ 41 - 0
apps/invidious/docker-compose.arm.yml

@@ -0,0 +1,41 @@
+version: "3"
+services:
+  invidious:
+    user: 1000:1000
+    container_name: invidious
+    image: quay.io/invidious/invidious:latest-arm64
+    restart: unless-stopped
+    ports:
+      - "${APP_PORT}:3000"
+    environment:
+      INVIDIOUS_CONFIG: |
+        db:
+          dbname: invidious
+          user: tipi
+          password: tipi
+          host: invidious-db
+          port: 5432
+        check_tables: true
+    healthcheck:
+      test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/comments/jNQXAC9IVRw || exit 1
+      interval: 30s
+      timeout: 5s
+      retries: 2
+    depends_on:
+      - invidious-db
+
+  invidious-db:
+    user: 1000:1000
+    container_name: invidious-db
+    image: docker.io/library/postgres:14
+    restart: unless-stopped
+    volumes:
+      - ${APP_DATA_DIR}/data/postgres:/var/lib/postgresql/data
+      - ${APP_DATA_DIR}/data/sql:/config/sql
+      - ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
+    environment:
+      POSTGRES_DB: invidious
+      POSTGRES_USER: tipi
+      POSTGRES_PASSWORD: tipi
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]

+ 1 - 2
apps/invidious/docker-compose.yml

@@ -3,8 +3,7 @@ services:
   invidious:
     user: 1000:1000
     container_name: invidious
-    image: quay.io/invidious/invidious:latest-arm64
-    # image: quay.io/invidious/invidious:latest-arm64 # ARM64/AArch64 devices
+    image: quay.io/invidious/invidious:latest
     restart: unless-stopped
     ports:
       - "${APP_PORT}:3000"

+ 2 - 2
apps/pihole/docker-compose.yml

@@ -19,7 +19,7 @@ services:
     hostname: pihole
     dns:
       - 127.0.0.1
-      - 10.21.21.200 # Points to unbound
+      # - 10.21.21.200 # Points to unbound
     ports:
       - 53:53/tcp
       - 53:53/udp
@@ -30,7 +30,7 @@ services:
     environment:
       TZ: ${TZ}
       WEBPASSWORD: ${APP_PASSWORD}
-      PIHOLE_DNS_: 10.21.21.200 # Points to unbound
+      # PIHOLE_DNS_: 10.21.21.200 # Points to unbound
       FTLCONF_REPLY_ADDR4: 10.21.21.201
     cap_add:
       - NET_ADMIN

+ 2 - 1
packages/system-api/package.json

@@ -67,6 +67,7 @@
     "nodemon": "^2.0.15",
     "prettier": "2.6.2",
     "ts-jest": "^28.0.2",
-    "typescript": "4.6.4"
+    "typescript": "4.6.4",
+    "rimraf": "^3.0.2"
   }
 }

+ 5 - 0
packages/system-api/src/modules/apps/__tests__/apps.service.test.ts

@@ -37,6 +37,10 @@ const testApp2: Partial<AppConfig> = {
   id: 'test-app2',
 };
 
+const testApp3: Partial<AppConfig> = {
+  id: 'test-app3',
+};
+
 const MOCK_FILE_EMPTY = {
   [`${config.ROOT_FOLDER}/apps/test-app/config.json`]: JSON.stringify(testApp),
   [`${config.ROOT_FOLDER}/.env`]: 'TEST=test',
@@ -46,6 +50,7 @@ const MOCK_FILE_EMPTY = {
 const MOCK_FILE_INSTALLED = {
   [`${config.ROOT_FOLDER}/apps/test-app/config.json`]: JSON.stringify(testApp),
   [`${config.ROOT_FOLDER}/apps/test-app2/config.json`]: JSON.stringify(testApp2),
+  [`${config.ROOT_FOLDER}/apps/test-app3/config.json`]: JSON.stringify(testApp3),
   [`${config.ROOT_FOLDER}/.env`]: 'TEST=test',
   [`${config.ROOT_FOLDER}/state/apps.json`]: '{"installed": "test-app"}',
   [`${config.ROOT_FOLDER}/app-data/test-app`]: '',

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

@@ -8,7 +8,7 @@ import { isProd } from './constants/constants';
 import appsRoutes from './modules/apps/apps.routes';
 import systemRoutes from './modules/system/system.routes';
 import authRoutes from './modules/auth/auth.routes';
-import { tradeTokenForUser } from './modules/auth/auth.helpers';
+import AuthHelpers from './modules/auth/auth.helpers';
 import cookieParser from 'cookie-parser';
 import config from './config';
 
@@ -30,7 +30,7 @@ app.use((req, res, next) => {
   let user = null;
 
   if (req?.cookies?.tipi_token) {
-    user = tradeTokenForUser(req.cookies.tipi_token);
+    user = AuthHelpers.tradeTokenForUser(req.cookies.tipi_token);
     if (user) req.user = user;
   }
 

+ 209 - 29
pnpm-lock.yaml

@@ -31,8 +31,8 @@ importers:
       eslint-config-prettier: 8.5.0_eslint@8.15.0
       eslint-import-resolver-node: 0.3.6
       eslint-import-resolver-typescript: 2.4.0_gwd37gqv3vjv3xlpl7ju3ag2qu
-      eslint-module-utils: 2.7.3
-      eslint-plugin-import: 2.26.0_eslint@8.15.0
+      eslint-module-utils: 2.7.3_v4b42wzyzkfip445mys4cuddlu
+      eslint-plugin-import: 2.26.0_ffbagraxqjjjtz72imxnvni46e
       eslint-plugin-jsx-a11y: 6.5.1_eslint@8.15.0
       eslint-plugin-prettier: 4.0.0_iqftbjqlxzn3ny5nablrkczhqi
       eslint-plugin-react: 7.29.1_eslint@8.15.0
@@ -115,7 +115,7 @@ importers:
       eslint: 8.12.0
       eslint-config-airbnb-typescript: 17.0.0_r46exuh3jlhq2wmrnqx2ufqspa
       eslint-config-next: 12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu
-      eslint-plugin-import: 2.26.0_eslint@8.12.0
+      eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
       postcss: 8.4.13
       tailwindcss: 3.0.24
       typescript: 4.6.4
@@ -163,6 +163,7 @@ importers:
       passport-http-bearer: ^1.0.1
       prettier: 2.6.2
       public-ip: ^5.0.0
+      rimraf: ^3.0.2
       systeminformation: ^5.11.9
       tcp-port-used: ^1.0.2
       ts-jest: ^28.0.2
@@ -207,11 +208,12 @@ importers:
       eslint: 8.15.0
       eslint-config-airbnb-typescript: 17.0.0_c2ouaf3l4ivgkc6ae4nebvztom
       eslint-config-prettier: 8.5.0_eslint@8.15.0
-      eslint-plugin-import: 2.26.0_eslint@8.15.0
+      eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy
       eslint-plugin-prettier: 4.0.0_iqftbjqlxzn3ny5nablrkczhqi
       jest: 28.1.0
       nodemon: 2.0.16
       prettier: 2.6.2
+      rimraf: 3.0.2
       ts-jest: 28.0.2_k4xvjffwcpckmnpd5fcvxvnd24
       typescript: 4.6.4
 
@@ -2978,6 +2980,8 @@ packages:
       raw-body: 2.5.1
       type-is: 1.6.18
       unpipe: 1.0.0
+    transitivePeerDependencies:
+      - supports-color
     dev: false
 
   /boxen/5.1.2:
@@ -3240,6 +3244,8 @@ packages:
       on-headers: 1.0.2
       safe-buffer: 5.1.2
       vary: 1.1.2
+    transitivePeerDependencies:
+      - supports-color
     dev: false
 
   /compute-scroll-into-view/1.0.14:
@@ -3393,14 +3399,36 @@ packages:
 
   /debug/2.6.9:
     resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
     dependencies:
       ms: 2.0.0
 
   /debug/3.2.7:
     resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
     dependencies:
       ms: 2.1.3
 
+  /debug/3.2.7_supports-color@5.5.0:
+    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+    dependencies:
+      ms: 2.1.3
+      supports-color: 5.5.0
+    dev: true
+
   /debug/4.3.1:
     resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==}
     engines: {node: '>=6.0'}
@@ -3911,7 +3939,7 @@ packages:
     dependencies:
       confusing-browser-globals: 1.0.11
       eslint: 8.15.0
-      eslint-plugin-import: 2.26.0_eslint@8.15.0
+      eslint-plugin-import: 2.26.0_ffbagraxqjjjtz72imxnvni46e
       object.assign: 4.1.2
       object.entries: 1.1.5
       semver: 6.3.0
@@ -3925,7 +3953,7 @@ packages:
     dependencies:
       confusing-browser-globals: 1.0.11
       eslint: 8.12.0
-      eslint-plugin-import: 2.26.0_eslint@8.12.0
+      eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
       object.assign: 4.1.2
       object.entries: 1.1.5
       semver: 6.3.0
@@ -3943,7 +3971,7 @@ packages:
       '@typescript-eslint/parser': 5.22.0_hcfsmds2fshutdssjqluwm76uu
       eslint: 8.15.0
       eslint-config-airbnb-base: 15.0.0_gwd37gqv3vjv3xlpl7ju3ag2qu
-      eslint-plugin-import: 2.26.0_eslint@8.15.0
+      eslint-plugin-import: 2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy
     dev: true
 
   /eslint-config-airbnb-typescript/17.0.0_gwd37gqv3vjv3xlpl7ju3ag2qu:
@@ -3956,7 +3984,7 @@ packages:
     dependencies:
       eslint: 8.15.0
       eslint-config-airbnb-base: 15.0.0_gwd37gqv3vjv3xlpl7ju3ag2qu
-      eslint-plugin-import: 2.26.0_eslint@8.15.0
+      eslint-plugin-import: 2.26.0_ffbagraxqjjjtz72imxnvni46e
     dev: false
 
   /eslint-config-airbnb-typescript/17.0.0_r46exuh3jlhq2wmrnqx2ufqspa:
@@ -3971,7 +3999,7 @@ packages:
       '@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede
       eslint: 8.12.0
       eslint-config-airbnb-base: 15.0.0_m4t3vvrby3btqwe437vnsnvyim
-      eslint-plugin-import: 2.26.0_eslint@8.12.0
+      eslint-plugin-import: 2.26.0_hhyjdrupy4c2vgtpytri6cjwoy
     dev: true
 
   /eslint-config-next/12.1.4_e6a2zi6fqdwfehht5cxvkmo3zu:
@@ -3990,13 +4018,14 @@ packages:
       eslint: 8.12.0
       eslint-import-resolver-node: 0.3.4
       eslint-import-resolver-typescript: 2.4.0_l3k33lf43msdtqtpwrwceacqke
-      eslint-plugin-import: 2.25.2_eslint@8.12.0
+      eslint-plugin-import: 2.25.2_svocbphju65ulgskrkawser2je
       eslint-plugin-jsx-a11y: 6.5.1_eslint@8.12.0
       eslint-plugin-react: 7.29.1_eslint@8.12.0
       eslint-plugin-react-hooks: 4.3.0_eslint@8.12.0
       next: 12.1.6_talmm3uuvp6ssixt2qevhfgvue
       typescript: 4.6.4
     transitivePeerDependencies:
+      - eslint-import-resolver-webpack
       - supports-color
     dev: true
 
@@ -4016,11 +4045,12 @@ packages:
       eslint: 8.15.0
       eslint-import-resolver-node: 0.3.4
       eslint-import-resolver-typescript: 2.4.0_kqnlgcjmdttqxtgdjy6bx3rwne
-      eslint-plugin-import: 2.25.2_eslint@8.15.0
+      eslint-plugin-import: 2.25.2_rc7mrpfsszodo22cb5arsvsauy
       eslint-plugin-jsx-a11y: 6.5.1_eslint@8.15.0
       eslint-plugin-react: 7.29.1_eslint@8.15.0
       eslint-plugin-react-hooks: 4.3.0_eslint@8.15.0
     transitivePeerDependencies:
+      - eslint-import-resolver-webpack
       - supports-color
     dev: false
 
@@ -4037,12 +4067,16 @@ packages:
     dependencies:
       debug: 2.6.9
       resolve: 1.22.0
+    transitivePeerDependencies:
+      - supports-color
 
   /eslint-import-resolver-node/0.3.6:
     resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==}
     dependencies:
       debug: 3.2.7
       resolve: 1.22.0
+    transitivePeerDependencies:
+      - supports-color
 
   /eslint-import-resolver-typescript/2.4.0_gwd37gqv3vjv3xlpl7ju3ag2qu:
     resolution: {integrity: sha512-useJKURidCcldRLCNKWemr1fFQL1SzB3G4a0li6lFGvlc5xGe1hY343bvG07cbpCzPuM/lK19FIJB3XGFSkplA==}
@@ -4053,7 +4087,7 @@ packages:
     dependencies:
       debug: 4.3.4
       eslint: 8.15.0
-      eslint-plugin-import: 2.26.0_eslint@8.15.0
+      eslint-plugin-import: 2.26.0_ffbagraxqjjjtz72imxnvni46e
       glob: 7.2.0
       is-glob: 4.0.3
       resolve: 1.22.0
@@ -4071,7 +4105,7 @@ packages:
     dependencies:
       debug: 4.3.4
       eslint: 8.15.0
-      eslint-plugin-import: 2.25.2_eslint@8.15.0
+      eslint-plugin-import: 2.25.2_rc7mrpfsszodo22cb5arsvsauy
       glob: 7.2.0
       is-glob: 4.0.3
       resolve: 1.22.0
@@ -4089,7 +4123,7 @@ packages:
     dependencies:
       debug: 4.3.4
       eslint: 8.12.0
-      eslint-plugin-import: 2.25.2_eslint@8.12.0
+      eslint-plugin-import: 2.25.2_svocbphju65ulgskrkawser2je
       glob: 7.2.0
       is-glob: 4.0.3
       resolve: 1.22.0
@@ -4098,26 +4132,102 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-module-utils/2.7.3:
+  /eslint-module-utils/2.7.3_sysdrzuw2ki4kxpuwc4tznw2ha:
+    resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 5.10.1_eslint@8.15.0
+      debug: 3.2.7
+      eslint-import-resolver-node: 0.3.6
+      eslint-import-resolver-typescript: 2.4.0_kqnlgcjmdttqxtgdjy6bx3rwne
+      find-up: 2.1.0
+    transitivePeerDependencies:
+      - supports-color
+
+  /eslint-module-utils/2.7.3_v4b42wzyzkfip445mys4cuddlu:
     resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
     engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
     dependencies:
       debug: 3.2.7
+      eslint-import-resolver-node: 0.3.6
+      eslint-import-resolver-typescript: 2.4.0_gwd37gqv3vjv3xlpl7ju3ag2qu
       find-up: 2.1.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
 
-  /eslint-plugin-import/2.25.2_eslint@8.12.0:
+  /eslint-module-utils/2.7.3_wex3ustmkv4ospy3s77r6ihlwq:
+    resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede
+      debug: 3.2.7
+      eslint-import-resolver-node: 0.3.6
+      find-up: 2.1.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /eslint-plugin-import/2.25.2_rc7mrpfsszodo22cb5arsvsauy:
     resolution: {integrity: sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==}
     engines: {node: '>=4'}
     peerDependencies:
+      '@typescript-eslint/parser': '*'
       eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
     dependencies:
+      '@typescript-eslint/parser': 5.10.1_eslint@8.15.0
       array-includes: 3.1.5
       array.prototype.flat: 1.3.0
       debug: 2.6.9
       doctrine: 2.1.0
-      eslint: 8.12.0
+      eslint: 8.15.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3
+      eslint-module-utils: 2.7.3_sysdrzuw2ki4kxpuwc4tznw2ha
       has: 1.0.3
       is-core-module: 2.9.0
       is-glob: 4.0.3
@@ -4125,21 +4235,30 @@ packages:
       object.values: 1.1.5
       resolve: 1.22.0
       tsconfig-paths: 3.14.1
-    dev: true
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+    dev: false
 
-  /eslint-plugin-import/2.25.2_eslint@8.15.0:
+  /eslint-plugin-import/2.25.2_svocbphju65ulgskrkawser2je:
     resolution: {integrity: sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==}
     engines: {node: '>=4'}
     peerDependencies:
+      '@typescript-eslint/parser': '*'
       eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
     dependencies:
+      '@typescript-eslint/parser': 5.10.1_uhoeudlwl7kc47h4kncsfowede
       array-includes: 3.1.5
       array.prototype.flat: 1.3.0
       debug: 2.6.9
       doctrine: 2.1.0
-      eslint: 8.15.0
+      eslint: 8.12.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3
+      eslint-module-utils: 2.7.3_sysdrzuw2ki4kxpuwc4tznw2ha
       has: 1.0.3
       is-core-module: 2.9.0
       is-glob: 4.0.3
@@ -4147,21 +4266,30 @@ packages:
       object.values: 1.1.5
       resolve: 1.22.0
       tsconfig-paths: 3.14.1
-    dev: false
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+    dev: true
 
-  /eslint-plugin-import/2.26.0_eslint@8.12.0:
+  /eslint-plugin-import/2.26.0_6nacgdzqm4zbhelsxkmd2vkvxy:
     resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
     engines: {node: '>=4'}
     peerDependencies:
+      '@typescript-eslint/parser': '*'
       eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
     dependencies:
+      '@typescript-eslint/parser': 5.22.0_hcfsmds2fshutdssjqluwm76uu
       array-includes: 3.1.5
       array.prototype.flat: 1.3.0
       debug: 2.6.9
       doctrine: 2.1.0
-      eslint: 8.12.0
+      eslint: 8.15.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3
+      eslint-module-utils: 2.7.3_wex3ustmkv4ospy3s77r6ihlwq
       has: 1.0.3
       is-core-module: 2.9.0
       is-glob: 4.0.3
@@ -4169,13 +4297,21 @@ packages:
       object.values: 1.1.5
       resolve: 1.22.0
       tsconfig-paths: 3.14.1
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
     dev: true
 
-  /eslint-plugin-import/2.26.0_eslint@8.15.0:
+  /eslint-plugin-import/2.26.0_ffbagraxqjjjtz72imxnvni46e:
     resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
     engines: {node: '>=4'}
     peerDependencies:
+      '@typescript-eslint/parser': '*'
       eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
     dependencies:
       array-includes: 3.1.5
       array.prototype.flat: 1.3.0
@@ -4183,7 +4319,7 @@ packages:
       doctrine: 2.1.0
       eslint: 8.15.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3
+      eslint-module-utils: 2.7.3_v4b42wzyzkfip445mys4cuddlu
       has: 1.0.3
       is-core-module: 2.9.0
       is-glob: 4.0.3
@@ -4191,6 +4327,42 @@ packages:
       object.values: 1.1.5
       resolve: 1.22.0
       tsconfig-paths: 3.14.1
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+    dev: false
+
+  /eslint-plugin-import/2.26.0_hhyjdrupy4c2vgtpytri6cjwoy:
+    resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 5.22.0_uhoeudlwl7kc47h4kncsfowede
+      array-includes: 3.1.5
+      array.prototype.flat: 1.3.0
+      debug: 2.6.9
+      doctrine: 2.1.0
+      eslint: 8.12.0
+      eslint-import-resolver-node: 0.3.6
+      eslint-module-utils: 2.7.3_wex3ustmkv4ospy3s77r6ihlwq
+      has: 1.0.3
+      is-core-module: 2.9.0
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.values: 1.1.5
+      resolve: 1.22.0
+      tsconfig-paths: 3.14.1
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+    dev: true
 
   /eslint-plugin-jsx-a11y/6.5.1_eslint@8.12.0:
     resolution: {integrity: sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==}
@@ -4552,6 +4724,8 @@ packages:
       type-is: 1.6.18
       utils-merge: 1.0.1
       vary: 1.1.2
+    transitivePeerDependencies:
+      - supports-color
     dev: false
 
   /fast-deep-equal/3.1.3:
@@ -4616,6 +4790,8 @@ packages:
       parseurl: 1.3.3
       statuses: 2.0.1
       unpipe: 1.0.0
+    transitivePeerDependencies:
+      - supports-color
     dev: false
 
   /find-root/1.1.0:
@@ -6234,7 +6410,7 @@ packages:
     requiresBuild: true
     dependencies:
       chokidar: 3.5.3
-      debug: 3.2.7
+      debug: 3.2.7_supports-color@5.5.0
       ignore-by-default: 1.0.1
       minimatch: 3.1.2
       pstree.remy: 1.1.8
@@ -7075,6 +7251,8 @@ packages:
       on-finished: 2.4.1
       range-parser: 1.2.1
       statuses: 2.0.1
+    transitivePeerDependencies:
+      - supports-color
     dev: false
 
   /serve-static/1.15.0:
@@ -7085,6 +7263,8 @@ packages:
       escape-html: 1.0.3
       parseurl: 1.3.3
       send: 0.18.0
+    transitivePeerDependencies:
+      - supports-color
     dev: false
 
   /set-blocking/2.0.0:

+ 13 - 1
scripts/app.sh

@@ -78,10 +78,22 @@ fi
 compose() {
   local app="${1}"
   shift
-  
+
+  local architecture="$(uname -m)"
+
+  if [[ "$architecture" == "aarch64" ]]; then
+    architecture="arm64"
+  fi
+
   # App data folder
   local env_file="${ROOT_FOLDER}/.env"
   local app_compose_file="${app_dir}/docker-compose.yml"
+
+  # Pick arm architecture if running on arm and if the app has a docker-compose.arm.yml file
+  if [[ "$architecture" == "arm"* ]] && [[ -f "${app_dir}/docker-compose.arm.yml" ]]; then
+    app_compose_file="${app_dir}/docker-compose.arm.yml"
+  fi  
+
   local common_compose_file="${ROOT_FOLDER}/apps/docker-compose.common.yml"
   local app_dir="${ROOT_FOLDER}/apps/${app}"
 

+ 12 - 4
scripts/start.sh

@@ -13,6 +13,14 @@ STATE_FOLDER="${ROOT_FOLDER}/state"
 SED_ROOT_FOLDER="$(echo $ROOT_FOLDER | sed 's/\//\\\//g')"
 INTERNAL_IP="$(hostname -I | awk '{print $1}')"
 DNS_IP=9.9.9.9 # Default to Quad9 DNS
+ARCHITECTURE="$(uname -m)"
+USERNAME="$(id -nu 1000)"
+
+if [[ "$ARCHITECTURE" == "x86_64" ]]; then
+  ARCHITECTURE="amd64"
+elif [[ "$ARCHITECTURE" == "aarch64" ]]; then
+  ARCHITECTURE="arm64"
+fi
 
 # Get field from json file
 function get_json_field() {
@@ -37,8 +45,6 @@ function derive_entropy() {
   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)
 
@@ -65,7 +71,7 @@ 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" && chown -R "1000:1000" "${STATE_FOLDER}/users.json"
+  cp "${ROOT_FOLDER}/templates/apps-sample.json" "${STATE_FOLDER}/apps.json" && chown -R "1000:1000" "${STATE_FOLDER}/apps.json"
 fi
 
 # Copy the user state if it isn't here
@@ -102,6 +108,7 @@ ENV_FILE_SYSTEM_API="$ROOT_FOLDER/templates/.env-api"
 JWT_SECRET=$(derive_entropy "jwt")
 
 for template in "${ENV_FILE}" "${ENV_FILE_SYSTEM_API}"; do
+  # Replace placeholders with actual values
   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}"
@@ -109,12 +116,13 @@ for template in "${ENV_FILE}" "${ENV_FILE_SYSTEM_API}"; do
   sed -i "s/<tz>/${TZ}/g" "${template}"
   sed -i "s/<jwt_secret>/${JWT_SECRET}/g" "${template}"
   sed -i "s/<root_folder>/${SED_ROOT_FOLDER}/g" "${template}"
+  sed -i "s/<architecture>/${ARCHITECTURE}/g" "${template}"
 done
 
 mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
 mv -f "$ENV_FILE_SYSTEM_API" "$ROOT_FOLDER/packages/system-api/.env"
 
-ansible-playbook ansible/start.yml -i ansible/hosts -K -e username="$USER"
+ansible-playbook ansible/start.yml -i ansible/hosts -K -e username="$USERNAME"
 
 # Run docker-compose
 docker-compose --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {

+ 2 - 1
templates/env-api-sample

@@ -1,3 +1,4 @@
 ROOT_FOLDER=<root_folder>
 JWT_SECRET=<jwt_secret>
-INTERNAL_IP=<internal_ip>
+INTERNAL_IP=<internal_ip>
+ARCHITECTURE=<architecture>

+ 1 - 2
templates/env-sample

@@ -6,5 +6,4 @@ PUID=<puid>
 PGID=<pgid>
 INTERNAL_IP=<internal_ip>
 DNS_IP=<dns_ip>
-
-
+ARCHITECTURE=<architecture>