From b0b5ab3c53af9a274c80c3fe64848e1fc03e1328 Mon Sep 17 00:00:00 2001 From: Philipp Fruck Date: Sun, 19 May 2024 16:11:04 +0200 Subject: [PATCH 1/6] remove crappy volume stuff --- compose.yml | 18 ++++-------------- sample.env | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/compose.yml b/compose.yml index dc7908c..b5c9c21 100644 --- a/compose.yml +++ b/compose.yml @@ -51,7 +51,7 @@ services: - POSTGRES_DB=${INVENTREE_DB_NAME:?You must provide the 'INVENTREE_DB_NAME' variable in the .env file} volumes: # Map 'data' volume such that postgres database is stored externally - - inventree_data:/var/lib/postgresql/data/:z + - ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/var/lib/postgresql/data/:z restart: unless-stopped # redis acts as database cache manager @@ -98,7 +98,7 @@ services: - inventree-db volumes: # Data volume must map to /home/inventree/data - - inventree_data:/home/inventree/data:z + - ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/home/inventree/data:z - ./plugins:/home/inventree/InvenTree/plugins:z restart: unless-stopped @@ -114,7 +114,7 @@ services: - .env volumes: # Data volume must map to /home/inventree/data - - inventree_data:/home/inventree/data:z + - ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/home/inventree/data:z restart: unless-stopped # nginx acts as a reverse proxy @@ -135,15 +135,5 @@ services: # Refer to the provided example file as a starting point - ./nginx.prod.conf:/etc/nginx/conf.d/default.conf:ro,Z # nginx proxy needs access to static and media files - - inventree_data:/var/www:z + - ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/var/www:z restart: unless-stopped - -volumes: - # Persistent data, stored external to the container(s) - inventree_data: - driver: local - driver_opts: - type: none - o: bind - # This directory specified where InvenTree data are stored "outside" the docker containers - device: ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!} diff --git a/sample.env b/sample.env index b22915b..1904bc9 100644 --- a/sample.env +++ b/sample.env @@ -5,7 +5,7 @@ COMPOSE_PROJECT_NAME=inventree # Note: You *must* un-comment this line, and point it to a path on your local machine # e.g. Linux -INVENTREE_EXT_VOLUME=data +INVENTREE_EXT_VOLUME=./data # e.g. Windows (docker desktop) #INVENTREE_EXT_VOLUME=c:/Users/me/inventree-data From c1c12cfa76fbf60cda62ee94181e8b0a82358193 Mon Sep 17 00:00:00 2001 From: Philipp Fruck Date: Sun, 19 May 2024 16:14:08 +0200 Subject: [PATCH 2/6] add new INVENTREE_SITE_URL variable --- sample.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample.env b/sample.env index 1904bc9..40df1e0 100644 --- a/sample.env +++ b/sample.env @@ -57,7 +57,7 @@ INVENTREE_DB_PASSWORD=password # Django configuration INVENTREE_SECRET_KEY=some-secret-key -ALLOWED_HOSTS=inventree.example.com,www.inventree.example.com +INVENTREE_SITE_URL=inventree.example.com,www.inventree.example.com # SSO Config INVENTREE_SOCIAL_BACKENDS=allauth.socialaccount.providers.openid_connect From 73383eff43f6bb87555129504c01749c9ecdc401 Mon Sep 17 00:00:00 2001 From: Philipp Fruck Date: Wed, 17 Sep 2025 13:33:03 +0200 Subject: [PATCH 3/6] cleanup deployment --- Makefile | 4 ++-- backup.sh | 6 ++++++ compose.yml | 15 --------------- 3 files changed, 8 insertions(+), 17 deletions(-) create mode 100644 backup.sh diff --git a/Makefile b/Makefile index a152205..11ba6f3 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,9 @@ psql: update: read -p "Update will cause downtime of the server. Are you sure you want to continue? Press Ctrl+c to abort!" _ - $(COMPOSE) down $(COMPOSE) pull - $(COMPOSE) run inventree-server invoke update + $(COMPOSE) down + $(COMPOSE) run --rm inventree-server invoke update $(COMPOSE) up -d data: # podman does not autocreate data folder diff --git a/backup.sh b/backup.sh new file mode 100644 index 0000000..81ad1e5 --- /dev/null +++ b/backup.sh @@ -0,0 +1,6 @@ +#!/bin/sh +time=$(date +"%Y-%m-%dT%H:%M:%S%z") +dir=backup +[ -d "${dir}" ] || mkdir -p "${dir}" +docker compose run --rm -u postgres inventree-db sh -c 'PGPASSWORD=$POSTGRES_PASSWORD pg_dump -h inventree-db -p 5432 -U $POSTGRES_USER inventree' > "${dir}/${time}.sql" +# to restore: pg_restore -d newdb db.dump diff --git a/compose.yml b/compose.yml index b5c9c21..efafa65 100644 --- a/compose.yml +++ b/compose.yml @@ -79,21 +79,6 @@ services: - 8000 env_file: - .env - environment: - INVENTREE_SOCIAL_PROVIDERS: | - { - "openid_connect": { - "SERVERS": [{ - "id": "oidc", - "name": "Hacknang SSO", - "server_url": "${HKNG_OIDC_URL:?You must provide the 'HKNG_OIDC_URL' variable in the .env file}", - "APP": { - "client_id": "${HKNG_OIDC_CLIENT_ID:?You must provide the 'HKNG_OIDC_CLIENT_ID' variable in the .env file}", - "secret": "${HKNG_OIDC_CLIENT_SECRET:?You must provide the 'HKNG_OIDC_CLIENT_SECRET' variable in the .env file}" - } - }] - } - } depends_on: - inventree-db volumes: From f310a238d5b8382911da1933147a159b877a3698 Mon Sep 17 00:00:00 2001 From: Philipp Fruck Date: Wed, 17 Sep 2025 14:26:21 +0200 Subject: [PATCH 4/6] adhere to upstream compose file for v1.0.0 --- Caddyfile | 77 ++++++++++++++++++++++++++++++++++++++++++ compose.yml | 72 +++++++++++++++++++-------------------- nginx.prod.conf | 64 ----------------------------------- sample.env | 90 +++++++++++++++++++++---------------------------- 4 files changed, 151 insertions(+), 152 deletions(-) create mode 100644 Caddyfile delete mode 100644 nginx.prod.conf diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..23268c6 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,77 @@ +# Example Caddyfile for InvenTree +# The following environment variables may be used: +# - INVENTREE_SITE_URL: The upstream URL of the InvenTree site (default: inventree.localhost) +# - INVENTREE_SERVER: The internal URL of the InvenTree container (default: http://inventree-server:8000) +# +# Note that while this file is a good starting point, it may need to be modified to suit your specific requirements +# +# Ref to the Caddyfile documentation: https://caddyserver.com/docs/caddyfile + + +# Logging configuration for Caddy +(log_common) { + log { + output file /var/log/caddy/{args[0]}.access.log + } +} + +# CORS headers control (used for static and media files) +(cors-headers) { + header Allow GET,HEAD,OPTIONS + header Access-Control-Allow-Origin * + header Access-Control-Allow-Methods GET,HEAD,OPTIONS + header Access-Control-Allow-Headers Authorization,Content-Type,User-Agent + + @cors_preflight{args[0]} method OPTIONS + + handle @cors_preflight{args[0]} { + respond "" 204 + } +} + +# The default server address is configured in the .env file +# If not specified, the default address is used - http://inventree.localhost +# If you need to listen on multiple addresses, or use a different port, you can modify this section directly +http://inventree.ctbk.de { + import log_common inventree + + encode gzip + + request_body { + max_size 100MB + } + + # Handle static request files + handle_path /static/* { + import cors-headers static + + root * /var/www/static + file_server + } + + # Handle media request files + handle_path /media/* { + import cors-headers media + + root * /var/www/media + file_server + + # Force download of media files (for security) + # Comment out this line if you do not want to force download + header Content-Disposition attachment + + # Authentication is handled by the forward_auth directive + # This is required to ensure that media files are only accessible to authenticated users + forward_auth {$INVENTREE_SERVER:"http://inventree-server:8000"} { + uri /auth/ + } + } + + # All other requests are proxied to the InvenTree server + reverse_proxy {$INVENTREE_SERVER:"http://inventree-server:8000"} { + + # If you are running behind another proxy, you may need to specify 'trusted_proxies' + # Ref: https://caddyserver.com/docs/json/apps/http/servers/trusted_proxies/ + # trusted_proxies ... + } +} diff --git a/compose.yml b/compose.yml index efafa65..f5af5c6 100644 --- a/compose.yml +++ b/compose.yml @@ -1,10 +1,8 @@ -version: "3.8" - # Docker compose recipe for a production-ready InvenTree setup, with the following containers: # - PostgreSQL as the database backend # - gunicorn as the InvenTree web server # - django-q as the InvenTree background worker process -# - nginx as a reverse proxy +# - Caddy as a reverse proxy # - redis as the cache manager (optional, disabled by default) # --------------------- @@ -34,16 +32,20 @@ version: "3.8" # INVENTREE_TAG=0.7.5 # +# ---------------------------- +# Docker compose customization +# ---------------------------- +# If you wish to customize the docker-compose script, you should only do so if you understand the stack! +# Do not expect support for customizations that are not part of the standard InvenTree setup! + services: # Database service # Use PostgreSQL as the database backend inventree-db: + image: postgres:13 container_name: inventree-db - image: ${POSTGRES_IMAGE:?You must provide the 'POSTGRES_IMAGE' variable in the .env file} expose: - ${INVENTREE_DB_PORT:-5432}/tcp - env_file: - - .env environment: - PGDATA=/var/lib/postgresql/data/pgdb - POSTGRES_USER=${INVENTREE_DB_USER:?You must provide the 'INVENTREE_DB_USER' variable in the .env file} @@ -55,43 +57,39 @@ services: restart: unless-stopped # redis acts as database cache manager - # only runs under the "redis" profile : https://docs.docker.com/compose/profiles/ inventree-cache: + image: redis:7-alpine container_name: inventree-cache - image: ${REDIS_IMAGE:?You must provide the 'REDIS_IMAGE' variable in the .env file} - depends_on: - - inventree-db env_file: - .env - profiles: - - redis expose: - - ${INVENTREE_CACHE_PORT:-6379} + - ${INVENTREE_CACHE_PORT:-6379} restart: always # InvenTree web server service # Uses gunicorn as the web server inventree-server: - container_name: inventree-server # If you wish to specify a particular InvenTree version, do so here - image: ${INVENTREE_IMAGE:?You must provide the 'INVENTREE_IMAGE' variable in the .env file} + image: inventree/inventree:${INVENTREE_TAG:-stable} + container_name: inventree-server + # Only change this port if you understand the stack. expose: - - 8000 - env_file: - - .env + - 8000 depends_on: - inventree-db + - inventree-cache + env_file: + - .env volumes: # Data volume must map to /home/inventree/data - - ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/home/inventree/data:z - - ./plugins:/home/inventree/InvenTree/plugins:z + - ${INVENTREE_EXT_VOLUME}:/home/inventree/data:z restart: unless-stopped # Background worker process handles long-running or periodic tasks inventree-worker: - container_name: inventree-worker # If you wish to specify a particular InvenTree version, do so here - image: ${INVENTREE_IMAGE:?You must provide the 'INVENTREE_IMAGE' variable in the .env file} + image: inventree/inventree:${INVENTREE_TAG:-stable} + container_name: inventree-worker command: invoke worker depends_on: - inventree-server @@ -99,26 +97,26 @@ services: - .env volumes: # Data volume must map to /home/inventree/data - - ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/home/inventree/data:z + - ${INVENTREE_EXT_VOLUME}:/home/inventree/data:z restart: unless-stopped - # nginx acts as a reverse proxy - # static files are served directly by nginx - # media files are served by nginx, although authentication is redirected to inventree-server - # web requests are redirected to gunicorn - # NOTE: You will need to provide a working nginx.conf file! + # caddy acts as reverse proxy and static file server + # https://hub.docker.com/_/caddy inventree-proxy: container_name: inventree-proxy - image: ${NGINX_IMAGE:?You must provide the 'NGINX_IMAGE' variable in the .env file} + image: caddy:alpine + restart: always depends_on: - inventree-server ports: - # Default web port is 1337 (can be changed in the .env file) - - ${INVENTREE_WEB_PORT:-1337}:8080 + - ${INVENTREE_WEB_PORT:-80}:80 + - 443:443 + env_file: + - .env volumes: - # Provide nginx configuration file to the container - # Refer to the provided example file as a starting point - - ./nginx.prod.conf:/etc/nginx/conf.d/default.conf:ro,Z - # nginx proxy needs access to static and media files - - ${INVENTREE_EXT_VOLUME:?You must specify the 'INVENTREE_EXT_VOLUME' variable in the .env file!}:/var/www:z - restart: unless-stopped + - ./Caddyfile:/etc/caddy/Caddyfile:ro,z + - ${INVENTREE_EXT_VOLUME}/static:/var/www/static:z + - ${INVENTREE_EXT_VOLUME}/media:/var/www/media:z + - ${INVENTREE_EXT_VOLUME}:/var/log:z + - ${INVENTREE_EXT_VOLUME}:/data:z + - ${INVENTREE_EXT_VOLUME}:/config:z diff --git a/nginx.prod.conf b/nginx.prod.conf deleted file mode 100644 index 1ebdcd2..0000000 --- a/nginx.prod.conf +++ /dev/null @@ -1,64 +0,0 @@ -server { - - # Listen for connection on (internal) port 8080 (unprivileged nginx) - listen 8080; - - real_ip_header proxy_protocol; - - location / { - - proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-By $server_addr:$server_port; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header CLIENT_IP $remote_addr; - - proxy_pass_request_headers on; - - proxy_redirect off; - - client_max_body_size 100M; - - proxy_buffering off; - proxy_request_buffering off; - - # Change 'inventree-server' to the name of the inventree server container, - # and '8000' to the INVENTREE_WEB_PORT (if not default) - proxy_pass http://inventree-server:8000; - } - - # Redirect any requests for static files - location /static/ { - alias /var/www/static/; - autoindex on; - - # Caching settings - expires 30d; - add_header Pragma public; - add_header Cache-Control "public"; - } - - # Redirect any requests for media files - location /media/ { - alias /var/www/media/; - - # Media files require user authentication - auth_request /auth; - - # Content header to force download - add_header Content-disposition "attachment"; - } - - # Use the 'user' API endpoint for auth - location /auth { - internal; - - proxy_pass http://inventree-server:8000/auth/; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - proxy_set_header X-Original-URI $request_uri; - } - -} diff --git a/sample.env b/sample.env index 40df1e0..859f58e 100644 --- a/sample.env +++ b/sample.env @@ -1,67 +1,55 @@ -# InvenTree environment variables for a postgresql production setup +# InvenTree environment variables for docker compose deployment +# For a full list of the available configuration options, refer to the InvenTree documentation: +# https://docs.inventree.org/en/stable/start/config/ + +# Specify the name of the docker-compose project COMPOSE_PROJECT_NAME=inventree -# Location of persistent database data (stored external to the docker containers) -# Note: You *must* un-comment this line, and point it to a path on your local machine +# InvenTree version tag (e.g. 'stable' / 'latest' / 'x.x.x') +INVENTREE_TAG=stable -# e.g. Linux -INVENTREE_EXT_VOLUME=./data +# InvenTree server URL - update this to match your server URL +INVENTREE_SITE_URL="http://inventree.localhost" +#INVENTREE_SITE_URL="http://192.168.1.2" # You can specify a local IP address here +#INVENTREE_SITE_URL="https://inventree.my-domain.com" # Or a public domain name (which you control) -# e.g. Windows (docker desktop) -#INVENTREE_EXT_VOLUME=c:/Users/me/inventree-data - -# Default web port for the InvenTree server -INVENTREE_WEB_PORT=8080 +# Specify the location of the external data volume +# By default, placed in local directory 'inventree-data' +INVENTREE_EXT_VOLUME=./inventree-data # Ensure debug is false for a production setup -INVENTREE_DEBUG=False INVENTREE_LOG_LEVEL=WARNING +# Enable custom plugins? +INVENTREE_PLUGINS_ENABLED=True + +# Run migrations automatically? +INVENTREE_AUTO_UPDATE=True + +# InvenTree superuser account details +# Un-comment (and complete) these lines to auto-create an admin account +#INVENTREE_ADMIN_USER= +#INVENTREE_ADMIN_PASSWORD= +#INVENTREE_ADMIN_EMAIL= + # Database configuration options -# Note: The example setup is for a PostgreSQL database +# DO NOT CHANGE THESE SETTINGS (unless you really know what you are doing) INVENTREE_DB_ENGINE=postgresql INVENTREE_DB_NAME=inventree INVENTREE_DB_HOST=inventree-db INVENTREE_DB_PORT=5432 -# Redis cache setup (disabled by default) -# Un-comment the following lines to enable Redis cache -# Note that you will also have to run docker-compose with the --profile redis command -# Refer to settings.py for other cache options -#INVENTREE_CACHE_HOST=inventree-cache -#INVENTREE_CACHE_PORT=6379 +# Database credentials - These should be changed from the default values! +# Note: These are *NOT* the InvenTree server login credentials, +# they are the credentials for the PostgreSQL database +INVENTREE_DB_USER=pguser +INVENTREE_DB_PASSWORD=pgpassword + +# Redis cache setup +# Refer to the documentation for other cache options +INVENTREE_CACHE_ENABLED=True +INVENTREE_CACHE_HOST=inventree-cache +INVENTREE_CACHE_PORT=6379 # Options for gunicorn server -INVENTREE_GUNICORN_TIMEOUT=30 - -# Enable custom plugins? -INVENTREE_PLUGINS_ENABLED=False - -# Image tag that should be used -INVENTREE_IMAGE=inventree/inventree:0.11.3 -REDIS_IMAGE=redis:7.0-alpine -NGINX_IMAGE=nginxinc/nginx-unprivileged:stable-alpine -# Postgres image must match version of pgdump in inventree image -POSTGRES_IMAGE=postgres:13-alpine - -# InvenTree admin account details -# make sure to use secure credentials these lines to auto-create an admin acount -INVENTREE_ADMIN_USER=admin -INVENTREE_ADMIN_PASSWORD=password -INVENTREE_ADMIN_EMAIL=admin@inventree.example - -# Database credentials - These must be configured before running -# Change from the default values! -INVENTREE_DB_USER=inventree -INVENTREE_DB_PASSWORD=password - -# Django configuration -INVENTREE_SECRET_KEY=some-secret-key -INVENTREE_SITE_URL=inventree.example.com,www.inventree.example.com - -# SSO Config -INVENTREE_SOCIAL_BACKENDS=allauth.socialaccount.providers.openid_connect - -HKNG_OIDC_URL=https://keycloak.example.com/realms/master/.well-known/openid-configuration -HKNG_OIDC_CLIENT_ID=example-client -HKNG_OIDC_SECRET=example-secret +INVENTREE_GUNICORN_TIMEOUT=90 From 1b130a48ef723fdbf24251a451d74af0ec953bcc Mon Sep 17 00:00:00 2001 From: Philipp Fruck Date: Wed, 17 Sep 2025 14:40:23 +0200 Subject: [PATCH 5/6] upgrade postgres to 17 --- compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose.yml b/compose.yml index f5af5c6..ff4f7a4 100644 --- a/compose.yml +++ b/compose.yml @@ -42,7 +42,7 @@ services: # Database service # Use PostgreSQL as the database backend inventree-db: - image: postgres:13 + image: postgres:17 container_name: inventree-db expose: - ${INVENTREE_DB_PORT:-5432}/tcp From 85f5d6c4ab7854192031b6670705525682f9f3b6 Mon Sep 17 00:00:00 2001 From: Philipp Fruck Date: Wed, 17 Sep 2025 14:50:00 +0200 Subject: [PATCH 6/6] switch to alpine version of postgres --- compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose.yml b/compose.yml index ff4f7a4..8f80693 100644 --- a/compose.yml +++ b/compose.yml @@ -42,7 +42,7 @@ services: # Database service # Use PostgreSQL as the database backend inventree-db: - image: postgres:17 + image: postgres:17-alpine container_name: inventree-db expose: - ${INVENTREE_DB_PORT:-5432}/tcp