From 17aefd2f2712f3813d964e973e57ff4f447c3294 Mon Sep 17 00:00:00 2001 From: kwoodland Date: Sun, 28 Dec 2025 23:44:54 +0100 Subject: [PATCH] feat: add kitchenowl app --- ct/kitchenowl.sh | 84 +++++++++++++++++ frontend/public/json/kitchenowl.json | 35 ++++++++ install/kitchenowl-install.sh | 130 +++++++++++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 ct/kitchenowl.sh create mode 100644 frontend/public/json/kitchenowl.json create mode 100644 install/kitchenowl-install.sh diff --git a/ct/kitchenowl.sh b/ct/kitchenowl.sh new file mode 100644 index 000000000..25d54663f --- /dev/null +++ b/ct/kitchenowl.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2025 community-scripts ORG +# Author: snazzybean +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/TomBursch/kitchenowl + +APP="KitchenOwl" +var_tags="${var_tags:-food;recipes}" +var_cpu="${var_cpu:-1}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-6}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { + header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/kitchenowl ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + + if check_for_gh_release "kitchenowl" "TomBursch/kitchenowl"; then + msg_info "Stopping Service" + systemctl stop kitchenowl + msg_ok "Stopped Service" + + if [[ -d /opt/kitchenowl_backup/data ]]; then + msg_ok "Using existing backup from previous update attempt" + else + msg_info "Backing up KitchenOwl" + mkdir -p /opt/kitchenowl_backup + cp -r /opt/kitchenowl/data /opt/kitchenowl_backup/ + cp -f /opt/kitchenowl/kitchenowl.env /opt/kitchenowl_backup/ + msg_ok "Backed up KitchenOwl" + fi + + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl" "TomBursch/kitchenowl" "tarball" "latest" "/opt/kitchenowl" + sed -i 's/default=True/default=False/' /opt/kitchenowl/backend/wsgi.py + CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl-web" "TomBursch/kitchenowl" "prebuild" "latest" "/opt/kitchenowl/web" "kitchenowl_Web.tar.gz" + + msg_info "Restoring KitchenOwl data" + cp -r /opt/kitchenowl_backup/data /opt/kitchenowl/ + cp -f /opt/kitchenowl_backup/kitchenowl.env /opt/kitchenowl/ + rm -rf /opt/kitchenowl_backup + msg_ok "Restored KitchenOwl data" + + msg_info "Installing Dependencies" + cd /opt/kitchenowl/backend + $STD uv sync --frozen + msg_ok "Dependencies installed" + + msg_info "Running Database Migrations" + cd /opt/kitchenowl/backend + set -a + source /opt/kitchenowl/kitchenowl.env + set +a + $STD uv run flask db upgrade + msg_ok "Database Migrations Complete" + + msg_info "Starting Service" + systemctl start kitchenowl + msg_ok "Started Service" + msg_ok "Updated Successfully" + fi +} + +start +build_container +description + +msg_ok "Completed Successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:80${CL}" diff --git a/frontend/public/json/kitchenowl.json b/frontend/public/json/kitchenowl.json new file mode 100644 index 000000000..e6c150616 --- /dev/null +++ b/frontend/public/json/kitchenowl.json @@ -0,0 +1,35 @@ +{ + "name": "KitchenOwl", + "slug": "kitchenowl", + "categories": [ + 13 + ], + "date_created": "2025-12-28", + "type": "ct", + "updateable": true, + "privileged": false, + "interface_port": 80, + "documentation": "https://docs.kitchenowl.org/", + "website": "https://kitchenowl.org/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/kitchenowl.webp", + "config_path": "/opt/kitchenowl/kitchenowl.env", + "description": "KitchenOwl is a smart self-hosted grocery list and recipe manager with real-time synchronization, recipe management, meal planning, and expense tracking.", + "install_methods": [ + { + "type": "default", + "script": "ct/kitchenowl.sh", + "resources": { + "cpu": 1, + "ram": 2048, + "hdd": 6, + "os": "Debian", + "version": "13" + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [] +} diff --git a/install/kitchenowl-install.sh b/install/kitchenowl-install.sh new file mode 100644 index 000000000..9a7d2da3e --- /dev/null +++ b/install/kitchenowl-install.sh @@ -0,0 +1,130 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2025 community-scripts ORG +# Author: snazzybean +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://github.com/TomBursch/kitchenowl + +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + nginx \ + build-essential \ + libpq-dev \ + libffi-dev \ + libssl-dev +msg_ok "Installed Dependencies" + +PYTHON_VERSION="3.12" setup_uv + +CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl" "TomBursch/kitchenowl" "tarball" "latest" "/opt/kitchenowl" +rm -rf /opt/kitchenowl/web +CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kitchenowl-web" "TomBursch/kitchenowl" "prebuild" "latest" "/opt/kitchenowl/web" "kitchenowl_Web.tar.gz" + +msg_info "Setting up KitchenOwl" +cd /opt/kitchenowl/backend +$STD uv sync --frozen +sed -i 's/default=True/default=False/' /opt/kitchenowl/backend/wsgi.py +mkdir -p /nltk_data +$STD uv run python -m nltk.downloader -d /nltk_data averaged_perceptron_tagger_eng punkt_tab +JWT_SECRET=$(openssl rand -hex 32) +import_local_ip +mkdir -p /opt/kitchenowl/data +cat </opt/kitchenowl/kitchenowl.env +STORAGE_PATH=/opt/kitchenowl/data +JWT_SECRET_KEY=${JWT_SECRET} +NLTK_DATA=/nltk_data +FRONT_URL=http://${LOCAL_IP} +FLASK_APP=wsgi.py +FLASK_ENV=production +EOF +set -a +source /opt/kitchenowl/kitchenowl.env +set +a +$STD uv run flask db upgrade +msg_ok "Set up KitchenOwl" + +msg_info "Creating Systemd Service" +cat </etc/systemd/system/kitchenowl.service +[Unit] +Description=KitchenOwl Backend +After=network.target + +[Service] +Type=simple +User=root +WorkingDirectory=/opt/kitchenowl/backend +EnvironmentFile=/opt/kitchenowl/kitchenowl.env +ExecStart=/usr/local/bin/uv run wsgi.py +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target +EOF +systemctl enable -q --now kitchenowl +msg_ok "Created and Started Service" + +msg_info "Configuring Nginx" +rm -f /etc/nginx/sites-enabled/default +cat <<'EOF' >/etc/nginx/sites-available/kitchenowl.conf +server { + listen 80; + server_name _; + + root /opt/kitchenowl/web; + index index.html; + + client_max_body_size 100M; + + # Security Headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_pass http://127.0.0.1:5000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location /socket.io { + proxy_pass http://127.0.0.1:5000; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + # WebSocket Timeouts - allow long-lived connections + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + } +} +EOF +ln -sf /etc/nginx/sites-available/kitchenowl.conf /etc/nginx/sites-enabled/ +$STD systemctl reload nginx +msg_ok "Configured Nginx" + +motd_ssh +customize +cleanup_lxc