From c3cc37714914a4bd7d59da6f4ce101caddf2c871 Mon Sep 17 00:00:00 2001 From: jums Date: Sun, 23 Feb 2025 08:40:05 +0100 Subject: [PATCH 01/48] README.md: update documentation --- README.md | 100 ++++++++++++++---------------------------------------- 1 file changed, 26 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 56be882..6de1e08 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,11 @@ This repository is meant to support running Inventaire for testing and developme - [Requirements](#requirements) - [Install](#install) +- [Webserver](#webserver) - [Usage](#usage) - [Tips](#tips) - [Fixtures](#fixtures) - - [Tests](#tests) - - [Push git commits](#push-git-commits) - - [Rootless Docker](#rootless-docker) + - [Path autocomplete](#path-autocomplete) - [Run inventaire server and client outside of Docker](#run-inventaire-server-and-client-outside-of-docker) - [Troubleshooting](#troubleshooting) - [Elasticsearch errors](#elasticsearch-errors) @@ -34,6 +33,13 @@ git clone https://github.com/inventaire/docker-inventaire.git cd docker-inventaire ``` +Rename `dotenv` file to `.env`, and customize the variables (mainly adding the domain name, and a couchdb password): + +```sh +cp dotenv .env +vim .env +``` + Clone `inventaire` core application [server](https://github.com/inventaire/inventaire) ```sh @@ -49,36 +55,34 @@ docker-compose build Download Node dependencies and install the [client repository](https://github.com/inventaire/inventaire-client): ```sh -docker-compose run --rm inventaire npm install +cd inventaire +npm install tsx && npm install +cd .. ``` -Configure inventaire so that it can connect to CouchDB. For that, create a file `config/local.cjs` with the following command: +Configure inventaire so that it can connect to CouchDB. For that, create a file `config/local-production.cjs` with the following command: ```sh echo "module.exports = { db: { - username: 'yourcouchdbusername', - password: 'yourcouchdbpassword' + hostname: 'couchdb', + }, + elasticsearch: { + origin: 'http://elasticsearch:9200', } } -" > ./inventaire/config/local.cjs +" > ./inventaire/config/local-production.cjs ``` NB: Those username and password should match the `COUCHDB_USER` and `COUCHDB_PASSWORD` environment variables set in `docker-compose.yml` ## Usage -Start CouchDB, Elasticsearch, and the Inventaire [server](https://github.com/inventaire/inventaire) in development mode (modifications to the server files will reload the server), by default on port 3006 +Start CouchDB, Elasticsearch, and the Inventaire [server](https://github.com/inventaire/inventaire) in production mode ```sh docker-compose up ``` -To also work on the [client](https://github.com/inventaire/inventaire-client), you need to also start the webpack dev server: -```sh -cd inventaire/client -npm run watch -``` - ## Tips General tips on how to run Inventaire can be found in the [server repository docs](https://github.com/inventaire/inventaire/tree/main/docs). Here after are some additional Docker-specific tips. @@ -87,10 +91,10 @@ General tips on how to run Inventaire can be found in the [server repository doc In case you would like to play with out-of-the-box data. -Run api tests to populate tests dbs (see Tests section) +Run API tests to populate tests dbs ```sh -docker-compose -f docker-compose.yml -f docker-compose.test.yml exec inventaire npm run test-api +docker-compose -f docker-compose.yml exec inventaire npm run test-api ``` - Replicate `*-tests` dbs documents into `*` dbs @@ -99,27 +103,9 @@ docker-compose -f docker-compose.yml -f docker-compose.test.yml exec inventaire `docker-compose exec inventaire npm run replicate-tests-db` ``` -### Tests +### Path autocomplete -Start services with test environnement with [multiple compose files](https://docs.docker.com/compose/extends/#understanding-multiple-compose-files) - -```sh -docker-compose -f docker-compose.yml -f docker-compose.test.yml up -``` - -Execute tests script - -```sh -docker-compose exec inventaire npm run test-api -``` - -or execute directly the test command - -```sh -docker-compose exec inventaire npm test /opt/inventaire/path/to/test/file -``` - -Tip : create a symbolic link on your machine between the inventaire folder and docker working directory on your machine at `/opt/`, in order to autocomplete path to test file to execute +Create a symbolic link on your machine between the inventaire folder and docker working directory on your machine at `/opt/`, in order to autocomplete path to test file to execute ```sh sudo ln ~/path/to/inventaire-docker/inventaire /opt -s @@ -132,45 +118,9 @@ mkdir /supervisor/path/to/inventaire ln -s /opt/ /supervisor/path/to/inventaire ``` -### Push git commits - -To keep things simple, this installation steps above clone repositories in https, but if you want to push to a branch with ssh, you will probably need to change the repositories `origin`: -```sh -cd inventaire -git remote set-url origin git@github.com:inventaire/inventaire.git -cd client -git remote set-url origin git@github.com:inventaire/inventaire-client.git -``` - -### Rootless Docker - -Docker Engine v20.10 is now available in rootless mode. If you would like to try it, you may follow the [official guide](https://docs.docker.com/engine/security/rootless/) (including command `export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock`). - -Start the inventaire install steps above, before installing dependencies, make sure that the owner of inventaire folder is the same as the owner inside the container. - -Delete `network_host` occurences from `docker-compose.yml` and adapt the `config/local.cjs` in consequence: - -```js -module.exports = { - protocol: 'http', - port: 3006, - host: 'inventaire', - db: { - username: 'couchdb', - password: 'password', - protocol: 'http', - hostname: 'couch' - }, - elasticsearch: { - host:'http://elasticsearch:9200' - } -} -``` - ### Run inventaire server and client outside of Docker -It can sometimes be more convenient to keep CouchDB and Elasticsearch in Docker, but to run the Inventaire server and client outside. For this you will need to: -- have [NodeJS](https://nodejs.org/) >= v16 installed on your machine, which should make both `node` and `npm` executables accessible in your terminal +It can sometimes be more convenient to keep CouchDB and Elasticsearch in Docker, but to run the Inventaire server and client outside. For this, you will need to have [NodeJS](https://nodejs.org/) >= v16 installed on your machine, which should make both `node` and `npm` executables accessible in your terminal Then you can start CouchDB and Elasticsearch in the background ```sh @@ -192,11 +142,13 @@ npm run watch ## Troubleshooting ### Elasticsearch errors + - `max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]`: fix by running the command `sudo sysctl -w vm.max_map_count=262144` on your host machine See also [Elasticsearch with Docker](https://www.elastic.co/guide/en/elasticsearch/reference/7.9/docker.html) ### Quieting CouchDB notice + CouchDB may warn constantly that `_users` database does not exist, [as documented](https://docs.couchdb.org/en/latest/setup/single-node.html), you can create de database with: `curl -X PUT http://127.0.0.1:5984/_users` From 75fa3ffa18ec93b89877654f4041fad9d8899d95 Mon Sep 17 00:00:00 2001 From: jums Date: Sun, 23 Feb 2025 08:41:04 +0100 Subject: [PATCH 02/48] make docker-compose.yml production ready --- .gitignore | 1 + Dockerfile.inventaire | 12 ++++++++++++ README.md | 2 +- docker-compose.yml | 33 ++++++++++++++++++++++++++++----- dotenv | 12 ++++++++++++ 5 files changed, 54 insertions(+), 6 deletions(-) create mode 100755 Dockerfile.inventaire create mode 100644 dotenv diff --git a/.gitignore b/.gitignore index 82ba10d..593157c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ inventaire +.env data log configs/docker.ini diff --git a/Dockerfile.inventaire b/Dockerfile.inventaire new file mode 100755 index 0000000..953ebee --- /dev/null +++ b/Dockerfile.inventaire @@ -0,0 +1,12 @@ +FROM node:20 + +RUN apt-get update \ + && apt-get install -y curl zsh git graphicsmagick inotify-tools jq \ + && apt-get clean + +# Default to the same user as the host (override from command lin if needed) +# Known benefits: +# - allows to handle leveldb with level-party from both the host and container at the same time +USER 1000:1000 + +CMD ["npm", "run", "start"] diff --git a/README.md b/README.md index 6de1e08..1a68b73 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Run [Inventaire](https://github.com/inventaire/inventaire) in Docker -This repository is meant to support running Inventaire for testing and development. For production, see [inventaire-deploy](https://github.com/inventaire/inventaire-deploy). +This repository is packaging Inventaire for Docker production environement. To run it for production outside Docker, see [inventaire-deploy](https://github.com/inventaire/inventaire-deploy). ## Summary diff --git a/docker-compose.yml b/docker-compose.yml index 682c185..35e26f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,36 @@ version: '3' services: + inventaire: + build: + context: ./. + dockerfile: Dockerfile.inventaire + ports: + - "3006:3006" + volumes: + - ./inventaire:${PROJECT_ROOT} + working_dir: ${PROJECT_ROOT} + environment: + NODE_ENV: 'production' + COUCHDB_USER: ${COUCHDB_USER} + COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} + PUBLIC_HOSTNAME: ${PUBLIC_HOSTNAME} + depends_on: + - elasticsearch + tty: true + logging: + options: + max-size: "10m" + max-file: "3" couchdb: image: couchdb:3.4.2 ports: - "5984:5984" - environment: - COUCHDB_USER: "yourcouchdbusername" - COUCHDB_PASSWORD: "yourcouchdbpassword" volumes: - 'couchdb:/opt/couchdb/data' - './configs:/opt/couchdb/etc/local.d' + environment: + COUCHDB_USER: ${COUCHDB_USER} + COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} tty: true elasticsearch: image: elasticsearch:7.16.2 @@ -18,11 +39,13 @@ services: - 'transport.host=127.0.0.1' # See https://www.elastic.co/guide/en/elasticsearch/reference/7.16/docker.html - 'discovery.type=single-node' + # Limit memory usage to 1Go, + # See https://www.elastic.co/guide/en/elasticsearch/reference/current/advanced-configuration.html - 'ES_JAVA_OPTS=-Xms1g -Xmx1g' volumes: - 'elasticsearch:/usr/share/elasticsearch/data' ports : - - '127.0.0.1:9200:9200' + - '9200:9200' volumes: couchdb: - elasticsearch: \ No newline at end of file + elasticsearch: diff --git a/dotenv b/dotenv new file mode 100644 index 0000000..3878077 --- /dev/null +++ b/dotenv @@ -0,0 +1,12 @@ +# Your website domain name +PUBLIC_HOSTNAME=an-inventaire-site.org + +# Root path within docker container +PROJECT_ROOT=/opt/inventaire + +# Generic user, to modify only for good reason +COUCHDB_USER=couchdb + +# Consider passwords with no less than 32 charracters, for example: +# cat /dev/urandom | tr -dc A-Za-z0-9-_ | head -c 32 +COUCHDB_PASSWORD=your_password From c14c486a358917bece32d29cc518588e1065d457 Mon Sep 17 00:00:00 2001 From: jums Date: Sun, 23 Feb 2025 08:42:09 +0100 Subject: [PATCH 03/48] package and document reverse proxy configuration --- README.md | 46 ++++++- nginx/snippets/security_headers.conf | 12 ++ nginx/snippets/ssl.conf | 11 ++ nginx/templates/default.conf.template | 174 ++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 2 deletions(-) create mode 100755 nginx/snippets/security_headers.conf create mode 100644 nginx/snippets/ssl.conf create mode 100755 nginx/templates/default.conf.template diff --git a/README.md b/README.md index 1a68b73..1b9cfa8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This repository is packaging Inventaire for Docker production environement. To r - [Requirements](#requirements) - [Install](#install) -- [Webserver](#webserver) +- [Reverse proxy configuration](#reverse-proxy-configuration) - [Usage](#usage) - [Tips](#tips) - [Fixtures](#fixtures) @@ -74,7 +74,49 @@ echo "module.exports = { " > ./inventaire/config/local-production.cjs ``` -NB: Those username and password should match the `COUCHDB_USER` and `COUCHDB_PASSWORD` environment variables set in `docker-compose.yml` +## Reverse proxy configuration + +Inventaire only provides configuration files for Nginx. + +Run dependencies: + +```sh +sudo mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets +``` + +Install nginx and certbot + +Copy the nginx configuration template + +```sh +PUBLIC_HOSTNAME=$(grep -oP 'PUBLIC_HOSTNAME=\K.*' .env) PROJECT_ROOT=$(grep -oP 'PROJECT_ROOT=\K.*' .env) envsubst < nginx/templates/default.conf.template > nginx/default +sudo mv nginx/default /etc/nginx/sites-available/default +``` + +Activate the configuration file + +```sh +sudo ln -s /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf +``` + +To generate the certificate for your domain as required to make https work, you can use Let's Encrypt: + +```sh +sudo systemctl stop nginx +sudo certbot certonly --standalone --post-hook "systemctl restart nginx" +sudo systemctl restart nginx +``` + +When certbot is done, you may uncomment lines starting with `# ssl_certificate` and `# ssl_certificate_key` in `/etc/nginx/sites-available/default.conf` and restart nginx. + +Certbot should have installed a cron to automatically renew your certificate. +Since nginx template supports webroot renewal, we suggest you to update the renewal config file to use the webroot authenticator: + +```sh +# Replace authenticator = standalone by authenticator = webroot +# Add webroot_path = /var/www/certbot +sudo vim /etc/letsencrypt/renewal/your-domain.com.conf +``` ## Usage diff --git a/nginx/snippets/security_headers.conf b/nginx/snippets/security_headers.conf new file mode 100755 index 0000000..7614ecc --- /dev/null +++ b/nginx/snippets/security_headers.conf @@ -0,0 +1,12 @@ +# add_header from parent blocks are ignored when the current block also calls add_header +# Thus the need for this snippet, to redefine the same headers in many blocks +# See http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header +add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; +# opt out Google Floc see: https://plausible.io/blog/google-floc#how-to-opt-out-of-floc-as-a-web-developer-set-a-permissions-policy +add_header Permissions-Policy interest-cohort=(); +# source: https://gist.github.com/plentz/6737338 +add_header X-Frame-Options "SAMEORIGIN" always; +# source: https://scotthelme.co.uk/hardening-your-http-response-headers/#x-content-type-options +add_header X-Content-Type-Options 'nosniff' always; +# source: https://scotthelme.co.uk/a-new-security-header-referrer-policy/ +add_header Referrer-Policy 'strict-origin' always; diff --git a/nginx/snippets/ssl.conf b/nginx/snippets/ssl.conf new file mode 100644 index 0000000..434b7f7 --- /dev/null +++ b/nginx/snippets/ssl.conf @@ -0,0 +1,11 @@ +# Recommended by https://ssl-config.mozilla.org/#server=nginx&version=1.18.0&config=intermediate&openssl=1.1.1f&guideline=5.6 + +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:50m; +ssl_session_tickets off; +ssl_protocols TLSv1.2 TLSv1.3; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; +ssl_prefer_server_ciphers on; +ssl_stapling on; +ssl_stapling_verify on; +ssl_dhparam /etc/nginx/dhparam.pem; diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template new file mode 100755 index 0000000..99194cc --- /dev/null +++ b/nginx/templates/default.conf.template @@ -0,0 +1,174 @@ +# PROJECT_ROOT and PUBLIC_HOSTNAME are set with nginx image function, which will extract environment variables before nginx starts +# See https://hub.docker.com/_/nginx + +upstream inventaire { + server 127.0.0.1:3006 fail_timeout=5s; +} + +# Using error_page as a way to have a named location that can +# then be shared between several locations, see: +# https://serverfault.com/questions/908086/nginx-directly-send-from-location-to-another-named-location +# https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/#what-to-do-instead +# Contrary to what the documentation says, the HTTP verbs aren't all converted to GET +# http://nginx.org/en/docs/http/ngx_http_core_module.html#error_page +error_page 543 = @invserver; + +server { + listen 80; + listen [::]:80; + + # Required to be able to run `certbot -w /var/www/html/` + location /.well-known/ { + root /var/www/html/; + } + + location / { + return 301 https://$host$request_uri; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name ${PUBLIC_HOSTNAME}; + + # ssl_certificate /etc/nginx/ssl/live/${PUBLIC_HOSTNAME}/fullchain.pem; + # ssl_certificate_key /etc/nginx/ssl/live/${PUBLIC_HOSTNAME}/privkey.pem; + + include /etc/nginx/snippets/ssl.conf; + + client_max_body_size 25M; + + # As long as no secret/sensible data are passed in the body, the BREACH exploit on TLS+compression shouldn't be a concern. Right? + # https://en.wikipedia.org/wiki/BREACH_(security_exploit)#Mitigation + # http://security.stackexchange.com/questions/39925/breach-a-new-attack-against-http-what-can-be-done + # It could be that it was solved by HTTP/2 \o/ https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2 + gzip on; + gzip_types *; + + # On-The-Fly Image Resizer + + # URLs look like /img/users/300x1200/8185d4e039f52b4faa06a1c277133e9a8232551b + # for locally hosted images + # or /img/remote/300x1200/630022006?href=http%3A%2F%2Fescaped.url + # for remote images, with 630022006 being the hash of the passed href + # generated by [hashCode](https://github.com/inventaire/inventaire/blob/35b1e63/server/lib/utils/base.js#L69-L80) + + # The hack: I couldn't make the proxy_store work: it never hits the cache, but + # it does put the resized images in /tmp/nginx/resize, so using a try_files + # directive instead + + # Sometimes, for some unidentified reason, the cached files end up empty, so it can be useful to add a root cron to remove those files: + # 0 4 * * * /usr/bin/find /tmp/nginx -type f -size 0 -delete + + # Do not remove the (.*) capture group as it seems to be required by the try_files + location ~ ^/img/(groups|users|entities|assets)/(.*) { + include /etc/nginx/snippets/security_headers.conf; + root /tmp/nginx/resize; + default_type "image/jpeg"; + add_header Cache-Control "public, max-age=31536000, immutable"; + add_header X-File-Cache "hit"; + add_header Content-Security-Policy "sandbox"; + try_files $uri @invimg; + limit_except GET { + deny all; + } + } + + # Same as above, but without the immutable + location ~ ^/img/remote/(.*) { + include /etc/nginx/snippets/security_headers.conf; + root /tmp/nginx/resize; + default_type "image/jpeg"; + add_header X-File-Cache "hit"; + add_header Content-Security-Policy "sandbox"; + try_files $uri @invimg; + limit_except GET { + deny all; + } + } + + # following aliases made in order to respect the url structure + # the server alone would follow: especially, mounting /static on /public + root ${PROJECT_ROOT}/inventaire/client; + location /public/ { + include /etc/nginx/snippets/security_headers.conf; + limit_except GET { + deny all; + } + gzip_static on; + # Let resources that can't be cache busted + # - such as opensearch.xml or robots.txt - + # out of this caching policy + if ($uri ~ "^/public/(dist|fonts)/" ) { + include /etc/nginx/snippets/security_headers.conf; + add_header Cache-Control "public, max-age=31536000, immutable"; + # All headers that aren't in the last block won't be taken in account + # thus the need to have CORS headers here too + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET' always; + } + } + + # Pass the request to the node.js server + # with some correct headers for proxy-awareness + location /api { + return 543; + } + + location /.well-known/webfinger { + return 543; + } + + # Let the API server handle all but /public JSON and RSS requests + location ~ "^/[^p].*\.(json|rss)$" { + limit_except GET { + deny all; + } + return 543; + } + + location @invserver { + include /etc/nginx/snippets/security_headers.conf; + # Let the server decide when CORS headers should be added + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $host; + + # Set a large value to let the API determine the appropriate + # timeout per endpoint + # http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout + proxy_read_timeout 3600; + proxy_redirect off; + proxy_http_version 1.1; + proxy_pass http://inventaire; + } + + location = /favicon.ico { + include /etc/nginx/snippets/security_headers.conf; + try_files /public/$uri /public/images/$uri; + expires 30d; + add_header Cache-Control "public"; + } + + location = /robots.txt { + include /etc/nginx/snippets/security_headers.conf; + gzip_static on; + try_files /public/$uri /$uri; + expires 1d; + add_header Cache-Control "public"; + } + + # Prevent exposing git folders such as /public/i18n/.git + # For why this rule takes precedence over location /public/ + # see http://stackoverflow.com/a/34262192/3324977 + location ~ /\.git { + deny all; + } + + location ^~ '/.well-known/acme-challenge' { + include /etc/nginx/snippets/security_headers.conf; + default_type "text/plain"; + root /var/www/certbot; + } +} From 82d94e73da7ce93315dd9a3220b880e205c2fba8 Mon Sep 17 00:00:00 2001 From: jums Date: Sun, 23 Feb 2025 09:03:09 +0100 Subject: [PATCH 04/48] README.md: add hub.docker.com image link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1b9cfa8..cdedf46 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Run [Inventaire](https://github.com/inventaire/inventaire) in Docker This repository is packaging Inventaire for Docker production environement. To run it for production outside Docker, see [inventaire-deploy](https://github.com/inventaire/inventaire-deploy). +You may also check the official [Docker image](https://hub.docker.com/repository/docker/inventaire/inventaire/general) + ## Summary From ba42f2e009183d1a6a897f84c25c63670e111181 Mon Sep 17 00:00:00 2001 From: jums Date: Wed, 25 Dec 2024 13:09:48 +0100 Subject: [PATCH 05/48] package reverse proxy in docker-compose --- README.md | 69 ++++++++++++++++++------------------------ docker-compose.yml | 51 ++++++++++++++++++++++++------- nginx/Dockerfile.nginx | 3 ++ 3 files changed, 73 insertions(+), 50 deletions(-) create mode 100644 nginx/Dockerfile.nginx diff --git a/README.md b/README.md index cdedf46..c986770 100644 --- a/README.md +++ b/README.md @@ -76,57 +76,45 @@ echo "module.exports = { " > ./inventaire/config/local-production.cjs ``` +Set the email server by editing the file `config/local-production.cjs`. For example: + +```js +mailer: { + disabled: false, + nodemailer: { + host: 'smtp.an-email-provider.net', + port: 587, + auth: { + user: 'user', + pass: 'password' + }, + }, +}, +``` + ## Reverse proxy configuration -Inventaire only provides configuration files for Nginx. - -Run dependencies: +Generate the first SSL certificate with Let's Encrypt ```sh -sudo mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets -``` - -Install nginx and certbot - -Copy the nginx configuration template - -```sh -PUBLIC_HOSTNAME=$(grep -oP 'PUBLIC_HOSTNAME=\K.*' .env) PROJECT_ROOT=$(grep -oP 'PROJECT_ROOT=\K.*' .env) envsubst < nginx/templates/default.conf.template > nginx/default -sudo mv nginx/default /etc/nginx/sites-available/default -``` - -Activate the configuration file - -```sh -sudo ln -s /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf -``` - -To generate the certificate for your domain as required to make https work, you can use Let's Encrypt: - -```sh -sudo systemctl stop nginx -sudo certbot certonly --standalone --post-hook "systemctl restart nginx" -sudo systemctl restart nginx -``` - -When certbot is done, you may uncomment lines starting with `# ssl_certificate` and `# ssl_certificate_key` in `/etc/nginx/sites-available/default.conf` and restart nginx. - -Certbot should have installed a cron to automatically renew your certificate. -Since nginx template supports webroot renewal, we suggest you to update the renewal config file to use the webroot authenticator: - -```sh -# Replace authenticator = standalone by authenticator = webroot -# Add webroot_path = /var/www/certbot -sudo vim /etc/letsencrypt/renewal/your-domain.com.conf +docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/certbot/conf:/etc/letsencrypt" certbot/certbot certonly --standalone ``` ## Usage -Start CouchDB, Elasticsearch, and the Inventaire [server](https://github.com/inventaire/inventaire) in production mode +Start CouchDB, Elasticsearch, Nginx and the Inventaire [server](https://github.com/inventaire/inventaire) in production mode ```sh docker-compose up ``` +Go to the sign up page (`https://DOMAIN_NAME/signup`) and create a user + +Make the newly created user an admin (replace `your_username` in the command below by the user username) : + +```sh +docker exec $(docker ps -f name=_inventaire --format "{{.ID}}") npm run db-actions:update-user-role-from-username your_username add admin +``` + ## Tips General tips on how to run Inventaire can be found in the [server repository docs](https://github.com/inventaire/inventaire/tree/main/docs). Here after are some additional Docker-specific tips. @@ -196,3 +184,6 @@ See also [Elasticsearch with Docker](https://www.elastic.co/guide/en/elasticsear CouchDB may warn constantly that `_users` database does not exist, [as documented](https://docs.couchdb.org/en/latest/setup/single-node.html), you can create de database with: `curl -X PUT http://127.0.0.1:5984/_users` + +`docker exec $(docker ps -f name=couchdb --format "{{.ID}}") curl -H 'Content-Type:application/json' -H 'Accept: application/json' -XPUT "http://couchdb:password@localhost:5984/_users"` + diff --git a/docker-compose.yml b/docker-compose.yml index 35e26f3..828aba3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,13 +4,12 @@ services: build: context: ./. dockerfile: Dockerfile.inventaire - ports: - - "3006:3006" volumes: - ./inventaire:${PROJECT_ROOT} working_dir: ${PROJECT_ROOT} environment: NODE_ENV: 'production' + NODE_APP_INSTANCE: 'federated' COUCHDB_USER: ${COUCHDB_USER} COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} PUBLIC_HOSTNAME: ${PUBLIC_HOSTNAME} @@ -21,22 +20,22 @@ services: options: max-size: "10m" max-file: "3" + restart: "always" couchdb: image: couchdb:3.4.2 - ports: - - "5984:5984" - volumes: - - 'couchdb:/opt/couchdb/data' - - './configs:/opt/couchdb/etc/local.d' environment: COUCHDB_USER: ${COUCHDB_USER} COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} + volumes: + - 'couchdb:/opt/couchdb/data' + - './configs:/opt/couchdb/etc/local.d' tty: true + restart: "always" elasticsearch: image: elasticsearch:7.16.2 environment: - - 'http.host=0.0.0.0' - - 'transport.host=127.0.0.1' + - 'http.host=elasticsearch' + - 'transport.host=elasticsearch' # See https://www.elastic.co/guide/en/elasticsearch/reference/7.16/docker.html - 'discovery.type=single-node' # Limit memory usage to 1Go, @@ -44,8 +43,38 @@ services: - 'ES_JAVA_OPTS=-Xms1g -Xmx1g' volumes: - 'elasticsearch:/usr/share/elasticsearch/data' - ports : - - '9200:9200' + restart: "always" + nginx: + build: + context: ./nginx + dockerfile: Dockerfile.nginx + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx/templates:/etc/nginx/templates/ + - ./nginx/snippets:/etc/nginx/snippets + - ./inventaire:${PROJECT_ROOT} + - certbot-www:/var/www/certbot + - ./certbot/conf:/etc/letsencrypt + environment: + PROJECT_ROOT: ${PROJECT_ROOT} + PUBLIC_HOSTNAME: ${PUBLIC_HOSTNAME} + INVENTAIRE_PORT: ${INVENTAIRE_PORT} + depends_on: + - inventaire + restart: "always" + certbot: + image: certbot/certbot:latest + volumes: + - ./certbot/conf:/etc/letsencrypt + - certbot-www:/var/www/certbot + restart: unless-stopped + entrypoint: /bin/sh -c "trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;" + depends_on: + - nginx + volumes: couchdb: elasticsearch: + certbot-www: diff --git a/nginx/Dockerfile.nginx b/nginx/Dockerfile.nginx new file mode 100644 index 0000000..5a990d6 --- /dev/null +++ b/nginx/Dockerfile.nginx @@ -0,0 +1,3 @@ +FROM nginx + +RUN mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets From a6568e99800280a74ec79cb5e171873cd287c3ea Mon Sep 17 00:00:00 2001 From: jums Date: Wed, 26 Feb 2025 07:39:01 +0100 Subject: [PATCH 06/48] docker-compose: document ports in comment to ease admin access to the db --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 828aba3..d9399ac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -26,6 +26,10 @@ services: environment: COUCHDB_USER: ${COUCHDB_USER} COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} + # Uncomment ports to get access to the db + # ie. for database transformation, querying, UI access (http://localhost:5984/_utils/) + # ports: + # - "5984:5984" volumes: - 'couchdb:/opt/couchdb/data' - './configs:/opt/couchdb/etc/local.d' From 0dd617d3a6fd82a425610540169db17262b3a125 Mon Sep 17 00:00:00 2001 From: maxlath Date: Wed, 26 Feb 2025 19:09:29 +0100 Subject: [PATCH 07/48] Dockerfile.inventaire: install dependencies and build client --- Dockerfile.inventaire | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/Dockerfile.inventaire b/Dockerfile.inventaire index 953ebee..b2744e7 100755 --- a/Dockerfile.inventaire +++ b/Dockerfile.inventaire @@ -1,12 +1,34 @@ -FROM node:20 +FROM node:20-slim RUN apt-get update \ - && apt-get install -y curl zsh git graphicsmagick inotify-tools jq \ - && apt-get clean + && apt-get install -y curl git graphicsmagick inotify-tools jq \ + && apt-get clean && rm -rf /var/lib/apt/lists/* \ + && mkdir -p /opt/inventaire \ + && chown -R 1000:1000 /opt -# Default to the same user as the host (override from command lin if needed) +# Default to the same user as the host (override from command line if needed) # Known benefits: # - allows to handle leveldb with level-party from both the host and container at the same time USER 1000:1000 -CMD ["npm", "run", "start"] +WORKDIR /opt/inventaire + +# - Create the client folder to prevent the server postinstall to run `npm run install-client` as it does it with the wrong workdir and env +# - Create the public/sitemaps folder to prevent the client postinstall to run `npm run generate-sitemaps` (which needs to be updated to support non-inventaire.io instances) +RUN git clone http://github.com/inventaire/inventaire --depth 1 . \ + && mkdir -p /opt/inventaire/client \ + && npm ci --omit=dev \ + && git clone https://github.com/inventaire/inventaire-client.git ./client --branch docker --depth 1 \ + && mkdir -p /opt/inventaire/client/public/sitemaps + +WORKDIR /opt/inventaire/client + +# Include dev dependencies (webpack, svelte-checks) at first to be able to build during the postinstall script +RUN npm ci \ + && rm -rf node_modules \ + && npm ci --omit=dev --ignore-scripts \ + && npm cache clean --force + +WORKDIR /opt/inventaire + +CMD [ "npm", "start" ] From 9187c32c009c5c04da21a3ce48f82220dad907c5 Mon Sep 17 00:00:00 2001 From: maxlath Date: Wed, 26 Feb 2025 19:45:04 +0100 Subject: [PATCH 08/48] Dockerfile.inventaire: use the built server instead of JIT tsx compilation --- Dockerfile.inventaire | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dockerfile.inventaire b/Dockerfile.inventaire index b2744e7..a4dabc9 100755 --- a/Dockerfile.inventaire +++ b/Dockerfile.inventaire @@ -18,6 +18,7 @@ WORKDIR /opt/inventaire RUN git clone http://github.com/inventaire/inventaire --depth 1 . \ && mkdir -p /opt/inventaire/client \ && npm ci --omit=dev \ + && npm run build \ && git clone https://github.com/inventaire/inventaire-client.git ./client --branch docker --depth 1 \ && mkdir -p /opt/inventaire/client/public/sitemaps @@ -31,4 +32,6 @@ RUN npm ci \ WORKDIR /opt/inventaire -CMD [ "npm", "start" ] +# Avoid using npm script to start the server +# See https://adambrodziak.pl/dockerfile-good-practices-for-node-and-npm#heading-use-node-not-npm-to-start-the-server +CMD [ "./scripts/typescript/start_built_server.sh" ] From 69db3e1a8632274e9f8a3c9adfaaa9bc048a1d3e Mon Sep 17 00:00:00 2001 From: maxlath Date: Wed, 26 Feb 2025 20:55:53 +0100 Subject: [PATCH 09/48] docker-compose.yml: use a pre-build inventaire image and env_file=.env and customize CouchDB entrypoint script to fix the issue of the missing _users database --- Dockerfile.inventaire | 0 couchdb/Dockerfile.couchdb | 14 +++++++++++ couchdb/docker-custom-entrypoint.sh | 3 +++ couchdb/init_users_db.sh | 12 +++++++++ docker-compose.yml | 38 +++++++++++------------------ dotenv | 5 ++++ 6 files changed, 48 insertions(+), 24 deletions(-) mode change 100755 => 100644 Dockerfile.inventaire create mode 100644 couchdb/Dockerfile.couchdb create mode 100755 couchdb/docker-custom-entrypoint.sh create mode 100755 couchdb/init_users_db.sh diff --git a/Dockerfile.inventaire b/Dockerfile.inventaire old mode 100755 new mode 100644 diff --git a/couchdb/Dockerfile.couchdb b/couchdb/Dockerfile.couchdb new file mode 100644 index 0000000..ad7666e --- /dev/null +++ b/couchdb/Dockerfile.couchdb @@ -0,0 +1,14 @@ +FROM couchdb:3.4.2 + +COPY docker-custom-entrypoint.sh /usr/local/bin/docker-custom-entrypoint.sh +COPY init_users_db.sh /usr/local/bin/init_users_db.sh + +ENTRYPOINT ["tini", "--", "/usr/local/bin/docker-custom-entrypoint.sh"] + +EXPOSE 5984 + +# Copied from the couchdb image Dockerfile +# https://github.com/apache/couchdb-docker/blob/734c61f/3.4.2/Dockerfile#L104 +# as it would have been otherwise reset to an empty string +# See https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact +CMD ["/opt/couchdb/bin/couchdb"] diff --git a/couchdb/docker-custom-entrypoint.sh b/couchdb/docker-custom-entrypoint.sh new file mode 100755 index 0000000..d0dd298 --- /dev/null +++ b/couchdb/docker-custom-entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash +/usr/local/bin/init_users_db.sh & +tini -- /docker-entrypoint.sh "$@" \ No newline at end of file diff --git a/couchdb/init_users_db.sh b/couchdb/init_users_db.sh new file mode 100755 index 0000000..254300e --- /dev/null +++ b/couchdb/init_users_db.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +while :; do { + echo "[init_users_db.sh] Waiting for CouchDB to be online to initialize the _users database" + curl http://localhost:5984 && { + echo "[init_users_db.sh] CouchDB is online! Trying to initialize _users database" + curl --user "$COUCHDB_USER:$COUCHDB_PASSWORD" -XPUT http://localhost:5984/_users + break + } || { + sleep 1 + } +}; done diff --git a/docker-compose.yml b/docker-compose.yml index d9399ac..04f38e8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,31 +1,23 @@ -version: '3' services: inventaire: - build: - context: ./. - dockerfile: Dockerfile.inventaire + image: inventaire:latest volumes: - - ./inventaire:${PROJECT_ROOT} - working_dir: ${PROJECT_ROOT} - environment: - NODE_ENV: 'production' - NODE_APP_INSTANCE: 'federated' - COUCHDB_USER: ${COUCHDB_USER} - COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} - PUBLIC_HOSTNAME: ${PUBLIC_HOSTNAME} + - ./inventaire:/opt/inventaire + env_file: .env depends_on: + - couchdb - elasticsearch tty: true logging: options: max-size: "10m" max-file: "3" - restart: "always" + restart: unless-stopped couchdb: - image: couchdb:3.4.2 - environment: - COUCHDB_USER: ${COUCHDB_USER} - COUCHDB_PASSWORD: ${COUCHDB_PASSWORD} + build: + context: ./couchdb + dockerfile: Dockerfile.couchdb + env_file: .env # Uncomment ports to get access to the db # ie. for database transformation, querying, UI access (http://localhost:5984/_utils/) # ports: @@ -34,7 +26,7 @@ services: - 'couchdb:/opt/couchdb/data' - './configs:/opt/couchdb/etc/local.d' tty: true - restart: "always" + restart: unless-stopped elasticsearch: image: elasticsearch:7.16.2 environment: @@ -47,7 +39,7 @@ services: - 'ES_JAVA_OPTS=-Xms1g -Xmx1g' volumes: - 'elasticsearch:/usr/share/elasticsearch/data' - restart: "always" + restart: unless-stopped nginx: build: context: ./nginx @@ -61,13 +53,11 @@ services: - ./inventaire:${PROJECT_ROOT} - certbot-www:/var/www/certbot - ./certbot/conf:/etc/letsencrypt - environment: - PROJECT_ROOT: ${PROJECT_ROOT} - PUBLIC_HOSTNAME: ${PUBLIC_HOSTNAME} - INVENTAIRE_PORT: ${INVENTAIRE_PORT} + env_file: .env depends_on: + # Required to be able to define the `inventaire` host as an upstream - inventaire - restart: "always" + restart: unless-stopped certbot: image: certbot/certbot:latest volumes: diff --git a/dotenv b/dotenv index 3878077..baa84c7 100644 --- a/dotenv +++ b/dotenv @@ -10,3 +10,8 @@ COUCHDB_USER=couchdb # Consider passwords with no less than 32 charracters, for example: # cat /dev/urandom | tr -dc A-Za-z0-9-_ | head -c 32 COUCHDB_PASSWORD=your_password + +NODE_ENV=production +NODE_APP_INSTANCE=federated +# Matching the port defined in inventaire/config/production-federated.cjs +INVENTAIRE_PORT=3016 From 1b94320cb2ec8a3a67867feb962693069b7c2ac8 Mon Sep 17 00:00:00 2001 From: maxlath Date: Wed, 26 Feb 2025 23:30:54 +0100 Subject: [PATCH 10/48] readme: wip --- README.md | 105 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index c986770..18c034a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,18 @@ -Run [Inventaire](https://github.com/inventaire/inventaire) in Docker +# Inventaire Suite -This repository is packaging Inventaire for Docker production environement. To run it for production outside Docker, see [inventaire-deploy](https://github.com/inventaire/inventaire-deploy). +The Inventaire Suite is a containerized, production-ready Inventaire system that allows you to self-host a knowledge graph similar to [inventaire.io](https://inventaire.io). -You may also check the official [Docker image](https://hub.docker.com/repository/docker/inventaire/inventaire/general) +It is composed of several services: +* **[Inventaire](https://hub.docker.com/r/inventaire/inventaire)**: a Docker image packaging the Inventaire [server](https://github.com/inventaire/inventaire/) and [client](https://github.com/inventaire/inventaire-client/) +* **[CouchDB](https://hub.docker.com/_/couchdb)**: the primary database used by the Inventaire server +* **[Elasticsearch](https://hub.docker.com/_/elasticsearch)**: a secondary database used by Inventaire for text and geographic search features +* **[Nginx](https://hub.docker.com/_/nginx)**: a reverse proxy with TLS termination thank to Let's Encrypt [certbot](https://hub.docker.com/r/certbot/certbot). + +The service orchestration is implemented using Docker Compose. + +> 🔧 This document is for people wanting to self-host the full Inventaire Suite. If you are looking for the individual Inventaire image, head over to [hub.docker.com/r/inventaire/inventaire](https://hub.docker.com/r/inventaire/inventaire). + +> 💡 This document presumes familiarity with basic Linux administration tasks and with Docker and Docker Compose. ## Summary @@ -23,18 +33,30 @@ You may also check the official [Docker image](https://hub.docker.com/repository -## Requirements +## Quickstart +### Requirements +#### Hardware +* Network connection with a public IP address +* 4 GB RAM +* 10 GB free disk space -- [docker-compose](https://docs.docker.com/compose/gettingstarted/) up and ready -- git +#### Software +* [Docker](https://docs.docker.com/get-started/get-docker/) >= v22.0 +* [Docker compose](https://docs.docker.com/compose/gettingstarted/) >= v2 +* [git](https://git-scm.com/) -## Install +#### Domain name +You need a DNS records that resolves to your machine's public IP address +## Initial setup + +### Download this repository ```sh git clone https://github.com/inventaire/docker-inventaire.git cd docker-inventaire ``` +### Initial configuration Rename `dotenv` file to `.env`, and customize the variables (mainly adding the domain name, and a couchdb password): ```sh @@ -76,45 +98,57 @@ echo "module.exports = { " > ./inventaire/config/local-production.cjs ``` -Set the email server by editing the file `config/local-production.cjs`. For example: - -```js -mailer: { - disabled: false, - nodemailer: { - host: 'smtp.an-email-provider.net', - port: 587, - auth: { - user: 'user', - pass: 'password' - }, - }, -}, -``` - ## Reverse proxy configuration -Generate the first SSL certificate with Let's Encrypt +Inventaire only provides configuration files for Nginx. + +Run dependencies: ```sh -docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/certbot/conf:/etc/letsencrypt" certbot/certbot certonly --standalone +sudo mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets +``` + +Install nginx and certbot + +Copy the nginx configuration template + +```sh +PUBLIC_HOSTNAME=$(grep -oP 'PUBLIC_HOSTNAME=\K.*' .env) PROJECT_ROOT=$(grep -oP 'PROJECT_ROOT=\K.*' .env) envsubst < nginx/templates/default.conf.template > nginx/default +sudo mv nginx/default /etc/nginx/sites-available/default +``` + +Activate the configuration file + +```sh +sudo ln -s /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf +``` + +To generate the certificate for your domain as required to make https work, you can use Let's Encrypt: + +```sh +sudo systemctl stop nginx +sudo certbot certonly --standalone --post-hook "systemctl restart nginx" +sudo systemctl restart nginx +``` + +When certbot is done, you may uncomment lines starting with `# ssl_certificate` and `# ssl_certificate_key` in `/etc/nginx/sites-available/default.conf` and restart nginx. + +Certbot should have installed a cron to automatically renew your certificate. +Since nginx template supports webroot renewal, we suggest you to update the renewal config file to use the webroot authenticator: + +```sh +# Replace authenticator = standalone by authenticator = webroot +# Add webroot_path = /var/www/certbot +sudo vim /etc/letsencrypt/renewal/your-domain.com.conf ``` ## Usage -Start CouchDB, Elasticsearch, Nginx and the Inventaire [server](https://github.com/inventaire/inventaire) in production mode +Start CouchDB, Elasticsearch, and the Inventaire [server](https://github.com/inventaire/inventaire) in production mode ```sh docker-compose up ``` -Go to the sign up page (`https://DOMAIN_NAME/signup`) and create a user - -Make the newly created user an admin (replace `your_username` in the command below by the user username) : - -```sh -docker exec $(docker ps -f name=_inventaire --format "{{.ID}}") npm run db-actions:update-user-role-from-username your_username add admin -``` - ## Tips General tips on how to run Inventaire can be found in the [server repository docs](https://github.com/inventaire/inventaire/tree/main/docs). Here after are some additional Docker-specific tips. @@ -184,6 +218,3 @@ See also [Elasticsearch with Docker](https://www.elastic.co/guide/en/elasticsear CouchDB may warn constantly that `_users` database does not exist, [as documented](https://docs.couchdb.org/en/latest/setup/single-node.html), you can create de database with: `curl -X PUT http://127.0.0.1:5984/_users` - -`docker exec $(docker ps -f name=couchdb --format "{{.ID}}") curl -H 'Content-Type:application/json' -H 'Accept: application/json' -XPUT "http://couchdb:password@localhost:5984/_users"` - From 80b8985198ddc01b475b001690ee79aff569e8f6 Mon Sep 17 00:00:00 2001 From: maxlath Date: Wed, 26 Feb 2025 23:32:20 +0100 Subject: [PATCH 11/48] inventaire service: use a custom entrypoint script to initialize the local config from env variables --- .gitignore | 1 - docker-compose.yml | 4 +-- dotenv | 13 ++++++++-- .../Dockerfile.inventaire | 4 ++- inventaire/docker-entrypoint.sh | 26 +++++++++++++++++++ 5 files changed, 41 insertions(+), 7 deletions(-) rename Dockerfile.inventaire => inventaire/Dockerfile.inventaire (94%) create mode 100755 inventaire/docker-entrypoint.sh diff --git a/.gitignore b/.gitignore index 593157c..db5a89d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -inventaire .env data log diff --git a/docker-compose.yml b/docker-compose.yml index 04f38e8..c2b7484 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,6 @@ services: inventaire: - image: inventaire:latest - volumes: - - ./inventaire:/opt/inventaire + image: inventaire/inventaire:latest env_file: .env depends_on: - couchdb diff --git a/dotenv b/dotenv index baa84c7..88235c0 100644 --- a/dotenv +++ b/dotenv @@ -6,12 +6,21 @@ PROJECT_ROOT=/opt/inventaire # Generic user, to modify only for good reason COUCHDB_USER=couchdb - # Consider passwords with no less than 32 charracters, for example: # cat /dev/urandom | tr -dc A-Za-z0-9-_ | head -c 32 COUCHDB_PASSWORD=your_password NODE_ENV=production NODE_APP_INSTANCE=federated -# Matching the port defined in inventaire/config/production-federated.cjs + +# Conventional port for Inventaire server in federated mode INVENTAIRE_PORT=3016 + +INSTANCE_NAME='My Inventaire Instance' + +# Will be displayed on landing screen +ORG_NAME='Example Organization' +ORG_URL='https://inventaire.example.org' + +# Users receiving emails from the instance can reply to this +CONTACT_ADDRESS='contact@inventaire.example.org' diff --git a/Dockerfile.inventaire b/inventaire/Dockerfile.inventaire similarity index 94% rename from Dockerfile.inventaire rename to inventaire/Dockerfile.inventaire index a4dabc9..ca32c40 100644 --- a/Dockerfile.inventaire +++ b/inventaire/Dockerfile.inventaire @@ -32,6 +32,8 @@ RUN npm ci \ WORKDIR /opt/inventaire +COPY docker-entrypoint.sh docker-entrypoint.sh + # Avoid using npm script to start the server # See https://adambrodziak.pl/dockerfile-good-practices-for-node-and-npm#heading-use-node-not-npm-to-start-the-server -CMD [ "./scripts/typescript/start_built_server.sh" ] +ENTRYPOINT [ "./docker-entrypoint.sh" ] diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh new file mode 100755 index 0000000..bc80676 --- /dev/null +++ b/inventaire/docker-entrypoint.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -eu + +# Overwrite the local config with environment variables every time the container is restarted +cat > ./config/local.cjs << EOF +module.exports = { + port: '${INVENTAIRE_PORT}', + publicHostname: '${PUBLIC_HOSTNAME}', + instanceName: '${INSTANCE_NAME}', + orgName: '${ORG_NAME}', + orgUrl: '${ORG_URL}', + contactAddress: '${CONTACT_ADDRESS}', + + db: { + username: '${COUCHDB_USER}', + password: '${COUCHDB_PASSWORD}', + hostname: 'couchdb', + }, + elasticsearch: { + origin: 'http://elasticsearch:9200', + } +} +EOF + +./scripts/typescript/start_built_server.sh From 81181578fca9619b207771ba72247b1128584859 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 00:17:20 +0100 Subject: [PATCH 12/48] couchdb: set single_node=true to remove the need to check if the _users database was created --- configs/0_local.ini | 6 ------ couchdb/Dockerfile.couchdb | 13 ++----------- couchdb/docker-custom-entrypoint.sh | 3 --- couchdb/init_users_db.sh | 12 ------------ couchdb/local.ini | 8 ++++++++ docker-compose.yml | 1 - 6 files changed, 10 insertions(+), 33 deletions(-) delete mode 100644 configs/0_local.ini delete mode 100755 couchdb/docker-custom-entrypoint.sh delete mode 100755 couchdb/init_users_db.sh create mode 100644 couchdb/local.ini diff --git a/configs/0_local.ini b/configs/0_local.ini deleted file mode 100644 index c9cc7e4..0000000 --- a/configs/0_local.ini +++ /dev/null @@ -1,6 +0,0 @@ -; CouchDB configuration file, named to have a lower priority than ./docker.ini -; See https://docs.couchdb.org/en/stable/config/index.html - -[fabric] -; Prevent "No DB shards could be opened" errors, see https://github.com/apache/couchdb/issues/4497 -shard_timeout_min_msec = 5000 diff --git a/couchdb/Dockerfile.couchdb b/couchdb/Dockerfile.couchdb index ad7666e..bfb5c62 100644 --- a/couchdb/Dockerfile.couchdb +++ b/couchdb/Dockerfile.couchdb @@ -1,14 +1,5 @@ FROM couchdb:3.4.2 -COPY docker-custom-entrypoint.sh /usr/local/bin/docker-custom-entrypoint.sh -COPY init_users_db.sh /usr/local/bin/init_users_db.sh +COPY local.ini /opt/couchdb/etc/local.d/local.ini -ENTRYPOINT ["tini", "--", "/usr/local/bin/docker-custom-entrypoint.sh"] - -EXPOSE 5984 - -# Copied from the couchdb image Dockerfile -# https://github.com/apache/couchdb-docker/blob/734c61f/3.4.2/Dockerfile#L104 -# as it would have been otherwise reset to an empty string -# See https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact -CMD ["/opt/couchdb/bin/couchdb"] +# Inherit ENTRYPOINT and CMD from couchdb image diff --git a/couchdb/docker-custom-entrypoint.sh b/couchdb/docker-custom-entrypoint.sh deleted file mode 100755 index d0dd298..0000000 --- a/couchdb/docker-custom-entrypoint.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -/usr/local/bin/init_users_db.sh & -tini -- /docker-entrypoint.sh "$@" \ No newline at end of file diff --git a/couchdb/init_users_db.sh b/couchdb/init_users_db.sh deleted file mode 100755 index 254300e..0000000 --- a/couchdb/init_users_db.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -while :; do { - echo "[init_users_db.sh] Waiting for CouchDB to be online to initialize the _users database" - curl http://localhost:5984 && { - echo "[init_users_db.sh] CouchDB is online! Trying to initialize _users database" - curl --user "$COUCHDB_USER:$COUCHDB_PASSWORD" -XPUT http://localhost:5984/_users - break - } || { - sleep 1 - } -}; done diff --git a/couchdb/local.ini b/couchdb/local.ini new file mode 100644 index 0000000..92f6b96 --- /dev/null +++ b/couchdb/local.ini @@ -0,0 +1,8 @@ +[couchdb] +; Automatically create the system databases on startup (in particular `_users`) +; see https://docs.couchdb.org/en/stable/config/couchdb.html#couchdb/single_node +single_node = true + +[fabric] +; Prevent "No DB shards could be opened" errors, see https://github.com/apache/couchdb/issues/4497 +shard_timeout_min_msec = 5000 diff --git a/docker-compose.yml b/docker-compose.yml index c2b7484..e7882b4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,7 +22,6 @@ services: # - "5984:5984" volumes: - 'couchdb:/opt/couchdb/data' - - './configs:/opt/couchdb/etc/local.d' tty: true restart: unless-stopped elasticsearch: From 376da92bd327ff3f78ea83e067572e60ae70a33b Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 00:21:49 +0100 Subject: [PATCH 13/48] elasticsearch: update version --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e7882b4..d980391 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ services: tty: true restart: unless-stopped elasticsearch: - image: elasticsearch:7.16.2 + image: elasticsearch:7.17.28 environment: - 'http.host=elasticsearch' - 'transport.host=elasticsearch' From d3467f1945d425de39675cc728243d41d0099b5a Mon Sep 17 00:00:00 2001 From: jums Date: Thu, 27 Feb 2025 09:48:33 +0100 Subject: [PATCH 14/48] improve README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 18c034a..bc93491 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,10 @@ The Inventaire Suite is a containerized, production-ready Inventaire system that allows you to self-host a knowledge graph similar to [inventaire.io](https://inventaire.io). It is composed of several services: -* **[Inventaire](https://hub.docker.com/r/inventaire/inventaire)**: a Docker image packaging the Inventaire [server](https://github.com/inventaire/inventaire/) and [client](https://github.com/inventaire/inventaire-client/) +* **[Inventaire](https://hub.docker.com/r/inventaire/inventaire)**: a Docker image packaging: + * the Inventaire [server](https://github.com/inventaire/inventaire/) + * the [client](https://github.com/inventaire/inventaire-client/) + * the embeded database: LevelDB * **[CouchDB](https://hub.docker.com/_/couchdb)**: the primary database used by the Inventaire server * **[Elasticsearch](https://hub.docker.com/_/elasticsearch)**: a secondary database used by Inventaire for text and geographic search features * **[Nginx](https://hub.docker.com/_/nginx)**: a reverse proxy with TLS termination thank to Let's Encrypt [certbot](https://hub.docker.com/r/certbot/certbot). From 93d7955d9987be288f46808379ce46034c9ac9d9 Mon Sep 17 00:00:00 2001 From: jums Date: Thu, 27 Feb 2025 09:49:21 +0100 Subject: [PATCH 15/48] split dotenv between what must be changed, and okay default variables --- README.md | 2 +- dotenv | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index bc93491..96a585d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It is composed of several services: * **[Inventaire](https://hub.docker.com/r/inventaire/inventaire)**: a Docker image packaging: * the Inventaire [server](https://github.com/inventaire/inventaire/) * the [client](https://github.com/inventaire/inventaire-client/) - * the embeded database: LevelDB + * the embedded database: LevelDB * **[CouchDB](https://hub.docker.com/_/couchdb)**: the primary database used by the Inventaire server * **[Elasticsearch](https://hub.docker.com/_/elasticsearch)**: a secondary database used by Inventaire for text and geographic search features * **[Nginx](https://hub.docker.com/_/nginx)**: a reverse proxy with TLS termination thank to Let's Encrypt [certbot](https://hub.docker.com/r/certbot/certbot). diff --git a/dotenv b/dotenv index 88235c0..2b739cb 100644 --- a/dotenv +++ b/dotenv @@ -1,21 +1,12 @@ # Your website domain name PUBLIC_HOSTNAME=an-inventaire-site.org -# Root path within docker container -PROJECT_ROOT=/opt/inventaire - # Generic user, to modify only for good reason COUCHDB_USER=couchdb # Consider passwords with no less than 32 charracters, for example: # cat /dev/urandom | tr -dc A-Za-z0-9-_ | head -c 32 COUCHDB_PASSWORD=your_password -NODE_ENV=production -NODE_APP_INSTANCE=federated - -# Conventional port for Inventaire server in federated mode -INVENTAIRE_PORT=3016 - INSTANCE_NAME='My Inventaire Instance' # Will be displayed on landing screen @@ -24,3 +15,18 @@ ORG_URL='https://inventaire.example.org' # Users receiving emails from the instance can reply to this CONTACT_ADDRESS='contact@inventaire.example.org' + + +######## +# Everything below is a default configuration +# Modify if you know what you are doing +######## + +# Root path within docker container +PROJECT_ROOT=/opt/inventaire + +NODE_ENV=production +NODE_APP_INSTANCE=federated + +# Conventional port for Inventaire server in federated mode +INVENTAIRE_PORT=3016 From e077f29cba4e152eb11c4821fe3dd6b5fa24b132 Mon Sep 17 00:00:00 2001 From: jums Date: Thu, 27 Feb 2025 09:56:05 +0100 Subject: [PATCH 16/48] make agnostic forge links --- README.md | 16 ++++++++-------- inventaire/Dockerfile.inventaire | 2 +- nginx/templates/default.conf.template | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 96a585d..fa528e1 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ The Inventaire Suite is a containerized, production-ready Inventaire system that It is composed of several services: * **[Inventaire](https://hub.docker.com/r/inventaire/inventaire)**: a Docker image packaging: - * the Inventaire [server](https://github.com/inventaire/inventaire/) - * the [client](https://github.com/inventaire/inventaire-client/) + * the Inventaire [server](https://git.inventaire.io/inventaire/) + * the [client](https://git.inventaire.io/inventaire-client/) * the embedded database: LevelDB * **[CouchDB](https://hub.docker.com/_/couchdb)**: the primary database used by the Inventaire server * **[Elasticsearch](https://hub.docker.com/_/elasticsearch)**: a secondary database used by Inventaire for text and geographic search features @@ -55,7 +55,7 @@ You need a DNS records that resolves to your machine's public IP address ### Download this repository ```sh -git clone https://github.com/inventaire/docker-inventaire.git +git clone https://git.inventaire.io/docker-inventaire.git cd docker-inventaire ``` @@ -67,10 +67,10 @@ cp dotenv .env vim .env ``` -Clone `inventaire` core application [server](https://github.com/inventaire/inventaire) +Clone `inventaire` core application [server](https://git.inventaire.io/inventaire) ```sh -git clone https://github.com/inventaire/inventaire.git +git clone https://git.inventaire.io/inventaire.git ``` Build @@ -79,7 +79,7 @@ Build docker-compose build ``` -Download Node dependencies and install the [client repository](https://github.com/inventaire/inventaire-client): +Download Node dependencies and install the [client repository](https://git.inventaire.io/inventaire-client): ```sh cd inventaire @@ -147,14 +147,14 @@ sudo vim /etc/letsencrypt/renewal/your-domain.com.conf ## Usage -Start CouchDB, Elasticsearch, and the Inventaire [server](https://github.com/inventaire/inventaire) in production mode +Start CouchDB, Elasticsearch, and the Inventaire [server](https://git.inventaire.io/inventaire) in production mode ```sh docker-compose up ``` ## Tips -General tips on how to run Inventaire can be found in the [server repository docs](https://github.com/inventaire/inventaire/tree/main/docs). Here after are some additional Docker-specific tips. +General tips on how to run Inventaire can be found in the [server repository docs](https://git.inventaire.io/inventaire/tree/main/docs). Here after are some additional Docker-specific tips. ### Fixtures diff --git a/inventaire/Dockerfile.inventaire b/inventaire/Dockerfile.inventaire index ca32c40..09156b1 100644 --- a/inventaire/Dockerfile.inventaire +++ b/inventaire/Dockerfile.inventaire @@ -19,7 +19,7 @@ RUN git clone http://github.com/inventaire/inventaire --depth 1 . \ && mkdir -p /opt/inventaire/client \ && npm ci --omit=dev \ && npm run build \ - && git clone https://github.com/inventaire/inventaire-client.git ./client --branch docker --depth 1 \ + && git clone https://git.inventaire.io/inventaire-client.git ./client --branch docker --depth 1 \ && mkdir -p /opt/inventaire/client/public/sitemaps WORKDIR /opt/inventaire/client diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 99194cc..4c1daa5 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -52,7 +52,7 @@ server { # for locally hosted images # or /img/remote/300x1200/630022006?href=http%3A%2F%2Fescaped.url # for remote images, with 630022006 being the hash of the passed href - # generated by [hashCode](https://github.com/inventaire/inventaire/blob/35b1e63/server/lib/utils/base.js#L69-L80) + # generated by [hashCode](https://git.inventaire.io/inventaire/blob/35b1e63/server/lib/utils/base.js#L69-L80) # The hack: I couldn't make the proxy_store work: it never hits the cache, but # it does put the resized images in /tmp/nginx/resize, so using a try_files From 9df0d0ebd52fb8142670ab21f8968abfd9d9a302 Mon Sep 17 00:00:00 2001 From: jums Date: Thu, 27 Feb 2025 10:00:57 +0100 Subject: [PATCH 17/48] docker-entrypoint: overwrite ./config/local-production.cjs to let the user free of overwriting those variables in local.cjs (aka the autority file) --- inventaire/docker-entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh index bc80676..f36f044 100755 --- a/inventaire/docker-entrypoint.sh +++ b/inventaire/docker-entrypoint.sh @@ -2,8 +2,8 @@ set -eu -# Overwrite the local config with environment variables every time the container is restarted -cat > ./config/local.cjs << EOF +# Overwrite the local-production config with environment variables every time the container is restarted +cat > ./config/local-production.cjs << EOF module.exports = { port: '${INVENTAIRE_PORT}', publicHostname: '${PUBLIC_HOSTNAME}', From 34db3704a4617dc9473d84ff1f8329d67ef7a924 Mon Sep 17 00:00:00 2001 From: jums Date: Thu, 27 Feb 2025 10:04:13 +0100 Subject: [PATCH 18/48] update gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index db5a89d..5aee0ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .env data log -configs/docker.ini - +.eslintcache From 3845f4eddb186d89ba3f82ecc4d362ea83b0b423 Mon Sep 17 00:00:00 2001 From: jums Date: Wed, 25 Dec 2024 13:09:48 +0100 Subject: [PATCH 19/48] docker-compose: propose alternatives to admins who want to tweak some code --- docker-compose.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index d980391..72da459 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,16 @@ services: inventaire: image: inventaire/inventaire:latest env_file: .env + # You may also build image from sources with: + # build: + # context: ./inventaire + # dockerfile: Dockerfile.inventaire depends_on: - couchdb - elasticsearch + # Uncomment if you want to access the code: + # volumes: + # - ./inventaire/server:${PROJECT_ROOT} tty: true logging: options: From fa0b91eef19de6f93a72f1ace2e5fbb7b2347f6d Mon Sep 17 00:00:00 2001 From: jums Date: Thu, 27 Feb 2025 10:21:21 +0100 Subject: [PATCH 20/48] README: replace nginx obsolete documentation since packaged in compose --- README.md | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index fa528e1..404fd45 100644 --- a/README.md +++ b/README.md @@ -103,46 +103,10 @@ echo "module.exports = { ## Reverse proxy configuration -Inventaire only provides configuration files for Nginx. - -Run dependencies: +Generate the first SSL certificate with Let's Encrypt ```sh -sudo mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets -``` - -Install nginx and certbot - -Copy the nginx configuration template - -```sh -PUBLIC_HOSTNAME=$(grep -oP 'PUBLIC_HOSTNAME=\K.*' .env) PROJECT_ROOT=$(grep -oP 'PROJECT_ROOT=\K.*' .env) envsubst < nginx/templates/default.conf.template > nginx/default -sudo mv nginx/default /etc/nginx/sites-available/default -``` - -Activate the configuration file - -```sh -sudo ln -s /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf -``` - -To generate the certificate for your domain as required to make https work, you can use Let's Encrypt: - -```sh -sudo systemctl stop nginx -sudo certbot certonly --standalone --post-hook "systemctl restart nginx" -sudo systemctl restart nginx -``` - -When certbot is done, you may uncomment lines starting with `# ssl_certificate` and `# ssl_certificate_key` in `/etc/nginx/sites-available/default.conf` and restart nginx. - -Certbot should have installed a cron to automatically renew your certificate. -Since nginx template supports webroot renewal, we suggest you to update the renewal config file to use the webroot authenticator: - -```sh -# Replace authenticator = standalone by authenticator = webroot -# Add webroot_path = /var/www/certbot -sudo vim /etc/letsencrypt/renewal/your-domain.com.conf +docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/certbot/conf:/etc/letsencrypt" certbot/certbot certonly --standalone ``` ## Usage From 10e33f919e6625ffced130231c1d412899d67b1b Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 11:47:36 +0100 Subject: [PATCH 21/48] inventaire: docker-entrypoint.sh: adapt the edited local config file to the used NODE_ENV Everything is this docker-compose.yml is done with NODE_ENV=production in mind, but if someone wants to play with other environments, that should now work too --- inventaire/docker-entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh index f36f044..897f062 100755 --- a/inventaire/docker-entrypoint.sh +++ b/inventaire/docker-entrypoint.sh @@ -2,8 +2,8 @@ set -eu -# Overwrite the local-production config with environment variables every time the container is restarted -cat > ./config/local-production.cjs << EOF +# Overwrite the local-${NODE_ENV} config with environment variables every time the container is restarted +cat > "./config/local-${NODE_ENV}.cjs" << EOF module.exports = { port: '${INVENTAIRE_PORT}', publicHostname: '${PUBLIC_HOSTNAME}', From fd2fce9147266042c01ee2dc919564161b7496e5 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 12:18:56 +0100 Subject: [PATCH 22/48] docker-compose: remove tty=true as it seems unnecessary for our use-case See https://docs.docker.com/reference/compose-file/services/#tty and https://docs.docker.com/reference/cli/docker/container/run/#tty --- docker-compose.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 72da459..be6eabc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,6 @@ services: # Uncomment if you want to access the code: # volumes: # - ./inventaire/server:${PROJECT_ROOT} - tty: true logging: options: max-size: "10m" @@ -29,7 +28,6 @@ services: # - "5984:5984" volumes: - 'couchdb:/opt/couchdb/data' - tty: true restart: unless-stopped elasticsearch: image: elasticsearch:7.17.28 From 353d8b381d8a5f05c548a42271e2c5e60ec85391 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 13:06:51 +0100 Subject: [PATCH 23/48] readme: further rework --- README.md | 142 ++++++++++++------------------------------------------ 1 file changed, 32 insertions(+), 110 deletions(-) diff --git a/README.md b/README.md index 404fd45..7040aa9 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,8 @@ The Inventaire Suite is a containerized, production-ready Inventaire system that It is composed of several services: * **[Inventaire](https://hub.docker.com/r/inventaire/inventaire)**: a Docker image packaging: - * the Inventaire [server](https://git.inventaire.io/inventaire/) - * the [client](https://git.inventaire.io/inventaire-client/) - * the embedded database: LevelDB + * the Inventaire [server](https://git.inventaire.io/inventaire/), which comes with its embedded database: LevelDB + * the Inventaire [client](https://git.inventaire.io/inventaire-client/) * **[CouchDB](https://hub.docker.com/_/couchdb)**: the primary database used by the Inventaire server * **[Elasticsearch](https://hub.docker.com/_/elasticsearch)**: a secondary database used by Inventaire for text and geographic search features * **[Nginx](https://hub.docker.com/_/nginx)**: a reverse proxy with TLS termination thank to Let's Encrypt [certbot](https://hub.docker.com/r/certbot/certbot). @@ -22,17 +21,20 @@ The service orchestration is implemented using Docker Compose. -- [Requirements](#requirements) -- [Install](#install) -- [Reverse proxy configuration](#reverse-proxy-configuration) +- [Quickstart](#quickstart) + - [Requirements](#requirements) + - [Hardware](#hardware) + - [Software](#software) + - [Domain name](#domain-name) + - [Open ports](#open-ports) +- [Initial setup](#initial-setup) + - [Download this repository](#download-this-repository) + - [Initial configuration](#initial-configuration) + - [Generate a TLS certificate](#generate-a-tls-certificate) - [Usage](#usage) - [Tips](#tips) - - [Fixtures](#fixtures) - - [Path autocomplete](#path-autocomplete) - - [Run inventaire server and client outside of Docker](#run-inventaire-server-and-client-outside-of-docker) - [Troubleshooting](#troubleshooting) - [Elasticsearch errors](#elasticsearch-errors) - - [Quieting CouchDB notice](#quieting-couchdb-notice) @@ -49,8 +51,15 @@ The service orchestration is implemented using Docker Compose. * [git](https://git-scm.com/) #### Domain name +> Ignore this section if you are just testing on your local machine + You need a DNS records that resolves to your machine's public IP address +#### Open ports +> Ignore this section if you are just testing on your local machine + +Your machine's firewall should let the http ports (`80` and `443`) open. + ## Initial setup ### Download this repository @@ -60,50 +69,16 @@ cd docker-inventaire ``` ### Initial configuration -Rename `dotenv` file to `.env`, and customize the variables (mainly adding the domain name, and a couchdb password): - +Copy the `dotenv` file to `.env` ```sh cp dotenv .env -vim .env ``` +and open this new `.env` file with a text editor to customize the variables (mainly adding your own domain name, and setup a couchdb password) -Clone `inventaire` core application [server](https://git.inventaire.io/inventaire) +#### Generate a TLS certificate +> Ignore this section if you are just testing on your local machine -```sh -git clone https://git.inventaire.io/inventaire.git -``` - -Build - -```sh -docker-compose build -``` - -Download Node dependencies and install the [client repository](https://git.inventaire.io/inventaire-client): - -```sh -cd inventaire -npm install tsx && npm install -cd .. -``` - -Configure inventaire so that it can connect to CouchDB. For that, create a file `config/local-production.cjs` with the following command: - -```sh -echo "module.exports = { - db: { - hostname: 'couchdb', - }, - elasticsearch: { - origin: 'http://elasticsearch:9200', - } -} -" > ./inventaire/config/local-production.cjs -``` - -## Reverse proxy configuration - -Generate the first SSL certificate with Let's Encrypt +Generate the first TLS certificate with Let's Encrypt ```sh docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/certbot/conf:/etc/letsencrypt" certbot/certbot certonly --standalone @@ -111,66 +86,19 @@ docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/certbot/conf:/etc/letsenc ## Usage -Start CouchDB, Elasticsearch, and the Inventaire [server](https://git.inventaire.io/inventaire) in production mode +Start all the services (Nginx, CouchDB, Elasticsearch, and the Inventaire [server](https://git.inventaire.io/inventaire)) in production mode: ```sh -docker-compose up +docker-compose up -d +``` + +Alternatively, to test locally, you can start only Inventaire and its dependencies (CouchDB and Elasticsearch) without Nginx, with the following command: +```sh +docker-compose up inventaire ``` ## Tips -General tips on how to run Inventaire can be found in the [server repository docs](https://git.inventaire.io/inventaire/tree/main/docs). Here after are some additional Docker-specific tips. - -### Fixtures - -In case you would like to play with out-of-the-box data. - -Run API tests to populate tests dbs - -```sh -docker-compose -f docker-compose.yml exec inventaire npm run test-api -``` - -- Replicate `*-tests` dbs documents into `*` dbs - -```sh -`docker-compose exec inventaire npm run replicate-tests-db` -``` - -### Path autocomplete - -Create a symbolic link on your machine between the inventaire folder and docker working directory on your machine at `/opt/`, in order to autocomplete path to test file to execute - -```sh -sudo ln ~/path/to/inventaire-docker/inventaire /opt -s -``` - -Alternatively, as root in inventaire container: - -```sh -mkdir /supervisor/path/to/inventaire -ln -s /opt/ /supervisor/path/to/inventaire -``` - -### Run inventaire server and client outside of Docker - -It can sometimes be more convenient to keep CouchDB and Elasticsearch in Docker, but to run the Inventaire server and client outside. For this, you will need to have [NodeJS](https://nodejs.org/) >= v16 installed on your machine, which should make both `node` and `npm` executables accessible in your terminal - -Then you can start CouchDB and Elasticsearch in the background -```sh -docker-compose up couchdb elasticsearch -d -``` - -Start the Inventaire server in development mode -```sh -cd inventaire -npm run watch -``` - -And in another terminal, start the client Webpack dev server -```sh -cd inventaire/client -npm run watch -``` +General tips on how to run Inventaire can be found in the [server repository docs](https://git.inventaire.io/inventaire/tree/main/docs). ## Troubleshooting @@ -179,9 +107,3 @@ npm run watch - `max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]`: fix by running the command `sudo sysctl -w vm.max_map_count=262144` on your host machine See also [Elasticsearch with Docker](https://www.elastic.co/guide/en/elasticsearch/reference/7.9/docker.html) - -### Quieting CouchDB notice - -CouchDB may warn constantly that `_users` database does not exist, [as documented](https://docs.couchdb.org/en/latest/setup/single-node.html), you can create de database with: - -`curl -X PUT http://127.0.0.1:5984/_users` From 06979f1a46f478e0e1ba0528d9c09ad2cac879d0 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 14:23:36 +0100 Subject: [PATCH 24/48] gitignore: add .docker to be able to use per-directory docker config See https://stackoverflow.com/a/51610644 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5aee0ab..37128c7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ data log .eslintcache +.docker From edfcc2494a09fc75f8b288e3ed34f420c1aafa0f Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 16:07:07 +0100 Subject: [PATCH 25/48] + scripts/docker_publish.sh --- scripts/docker_publish.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 scripts/docker_publish.sh diff --git a/scripts/docker_publish.sh b/scripts/docker_publish.sh new file mode 100755 index 0000000..4ca0c58 --- /dev/null +++ b/scripts/docker_publish.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -eu + +cwd="$PWD" + +cd ./inventaire + +echo -n "Enter version number (ex: 3.0.0-beta): " +read -r version + +docker build -t inventaire -f ./Dockerfile.inventaire . + +docker tag inventaire "inventaire/inventaire:${version}" +docker tag inventaire inventaire/inventaire:latest + +docker push "inventaire/inventaire:${version}" +docker push inventaire/inventaire:latest + +cd "$cwd" From 1450ac5888d9542679a3f17ff163388216c3e52b Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 17:21:04 +0100 Subject: [PATCH 26/48] readme: udpate docker compose commands to v2 syntax See https://docs.docker.com/compose/releases/migrate/ --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7040aa9..48115b5 100644 --- a/README.md +++ b/README.md @@ -88,12 +88,12 @@ docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/certbot/conf:/etc/letsenc Start all the services (Nginx, CouchDB, Elasticsearch, and the Inventaire [server](https://git.inventaire.io/inventaire)) in production mode: ```sh -docker-compose up -d +docker compose up -d ``` Alternatively, to test locally, you can start only Inventaire and its dependencies (CouchDB and Elasticsearch) without Nginx, with the following command: ```sh -docker-compose up inventaire +docker compose up inventaire ``` ## Tips From a224610d283b2557667a40d842e55fd7f25537db Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 17:21:46 +0100 Subject: [PATCH 27/48] docker-compose.yml: add warning on port binding in prod --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index be6eabc..a07f974 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,6 +24,10 @@ services: env_file: .env # Uncomment ports to get access to the db # ie. for database transformation, querying, UI access (http://localhost:5984/_utils/) + # /!\ Beware that exposing container ports like this might bypass your firewall rules + # See https://docs.docker.com/engine/install/ubuntu/#firewall-limitations + # Keeping it bound to localhost (which is the default) should be safe though + # (that is, contrary to binding to 0.0.0.0) # ports: # - "5984:5984" volumes: From 02454e39cfd420bf79b5eb01ed802855125ea236 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 17:22:05 +0100 Subject: [PATCH 28/48] nginx Dockerfile: generate dhparam.pem --- nginx/Dockerfile.nginx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nginx/Dockerfile.nginx b/nginx/Dockerfile.nginx index 5a990d6..ccd99fc 100644 --- a/nginx/Dockerfile.nginx +++ b/nginx/Dockerfile.nginx @@ -1,3 +1,5 @@ FROM nginx RUN mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets + +RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 \ No newline at end of file From b4b0ddab6f729f070b577ead72f834ee643f2c4e Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 17:22:41 +0100 Subject: [PATCH 29/48] nginx: fix ssl_certificate* paths --- nginx/templates/default.conf.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 4c1daa5..e935b19 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -32,8 +32,8 @@ server { listen [::]:443 ssl http2; server_name ${PUBLIC_HOSTNAME}; - # ssl_certificate /etc/nginx/ssl/live/${PUBLIC_HOSTNAME}/fullchain.pem; - # ssl_certificate_key /etc/nginx/ssl/live/${PUBLIC_HOSTNAME}/privkey.pem; + ssl_certificate /etc/letsencrypt/live/${PUBLIC_HOSTNAME}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${PUBLIC_HOSTNAME}/privkey.pem; include /etc/nginx/snippets/ssl.conf; From f2ddb13bc7832c223592ce5b2edbc25f15b15ca2 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 17:59:22 +0100 Subject: [PATCH 30/48] inventaire: allow to customize the mailer config --- dotenv | 4 ++++ inventaire/docker-entrypoint.sh | 14 +++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/dotenv b/dotenv index 2b739cb..758d87d 100644 --- a/dotenv +++ b/dotenv @@ -16,6 +16,10 @@ ORG_URL='https://inventaire.example.org' # Users receiving emails from the instance can reply to this CONTACT_ADDRESS='contact@inventaire.example.org' +MAILER_SMTP_HOST=smtp.example.org +MAILER_SMTP_PORT=587 +MAILER_SMTP_USERNAME=your_username_on_smtp.example.org +MAILER_SMTP_PASSWORD=your_password_on_smtp.example.org ######## # Everything below is a default configuration diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh index 897f062..bc1810c 100755 --- a/inventaire/docker-entrypoint.sh +++ b/inventaire/docker-entrypoint.sh @@ -19,7 +19,19 @@ module.exports = { }, elasticsearch: { origin: 'http://elasticsearch:9200', - } + }, + mailer: { + disabled: false, + nodemailer: { + host: '${MAILER_SMTP_HOST}', + port: ${MAILER_SMTP_PORT}, + auth: { + user: '${MAILER_SMTP_USERNAME}', + pass: '${MAILER_SMTP_PASSWORD}' + }, + }, + }, + } EOF From 5e408aad2bcdfd7267dcf2ded36623482a81e5d6 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 18:17:33 +0100 Subject: [PATCH 31/48] nginx: disable compression to mitigate BREACH exploit --- nginx/templates/default.conf.template | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index e935b19..7e247b7 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -39,12 +39,11 @@ server { client_max_body_size 25M; - # As long as no secret/sensible data are passed in the body, the BREACH exploit on TLS+compression shouldn't be a concern. Right? + # Disabling compression to mitigate BREACH exploit # https://en.wikipedia.org/wiki/BREACH_(security_exploit)#Mitigation # http://security.stackexchange.com/questions/39925/breach-a-new-attack-against-http-what-can-be-done - # It could be that it was solved by HTTP/2 \o/ https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2 - gzip on; - gzip_types *; + # until we can confidently say that HTTP/2 solves the issue? https://blog.cloudflare.com/hpack-the-silent-killer-feature-of-http-2 + gzip off; # On-The-Fly Image Resizer From 095293b0a54b9b5580a520436e5dd26de0fa8180 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 18:19:25 +0100 Subject: [PATCH 32/48] nginx: recover access to the inventaire files and API --- docker-compose.yml | 6 +++--- dotenv | 3 --- nginx/templates/default.conf.template | 7 ++++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a07f974..1057539 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,8 +10,8 @@ services: - couchdb - elasticsearch # Uncomment if you want to access the code: - # volumes: - # - ./inventaire/server:${PROJECT_ROOT} + volumes: + - ./inventaire/server:/opt/inventaire logging: options: max-size: "10m" @@ -56,7 +56,7 @@ services: volumes: - ./nginx/templates:/etc/nginx/templates/ - ./nginx/snippets:/etc/nginx/snippets - - ./inventaire:${PROJECT_ROOT} + - ./inventaire/server:/opt/inventaire - certbot-www:/var/www/certbot - ./certbot/conf:/etc/letsencrypt env_file: .env diff --git a/dotenv b/dotenv index 758d87d..9f59e75 100644 --- a/dotenv +++ b/dotenv @@ -26,9 +26,6 @@ MAILER_SMTP_PASSWORD=your_password_on_smtp.example.org # Modify if you know what you are doing ######## -# Root path within docker container -PROJECT_ROOT=/opt/inventaire - NODE_ENV=production NODE_APP_INSTANCE=federated diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 7e247b7..5f33e43 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -1,8 +1,9 @@ -# PROJECT_ROOT and PUBLIC_HOSTNAME are set with nginx image function, which will extract environment variables before nginx starts +# The INVENTAIRE_PORT and PUBLIC_HOSTNAME variables are set with nginx image function, +# which will extract environment variables before nginx starts # See https://hub.docker.com/_/nginx upstream inventaire { - server 127.0.0.1:3006 fail_timeout=5s; + server inventaire:${INVENTAIRE_PORT} fail_timeout=5s; } # Using error_page as a way to have a named location that can @@ -89,7 +90,7 @@ server { # following aliases made in order to respect the url structure # the server alone would follow: especially, mounting /static on /public - root ${PROJECT_ROOT}/inventaire/client; + root /opt/inventaire/client; location /public/ { include /etc/nginx/snippets/security_headers.conf; limit_except GET { From abbfa8216d7033e269c9c95ca281498c2d930770 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 18:25:32 +0100 Subject: [PATCH 33/48] nginx template: rename the upstream to avoid confusions with the container name --- nginx/templates/default.conf.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 5f33e43..eb46823 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -2,7 +2,7 @@ # which will extract environment variables before nginx starts # See https://hub.docker.com/_/nginx -upstream inventaire { +upstream inv { server inventaire:${INVENTAIRE_PORT} fail_timeout=5s; } @@ -141,7 +141,7 @@ server { proxy_read_timeout 3600; proxy_redirect off; proxy_http_version 1.1; - proxy_pass http://inventaire; + proxy_pass http://inv; } location = /favicon.ico { From f30a03a304d37c50a040028c547226fd5deb8cf0 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 19:18:02 +0100 Subject: [PATCH 34/48] docker-compose.yml: share inventaire files with nginx through a named volume as using a host path seems to result in that path being empty o_O Possibly has to do with https://forums.docker.com/t/docker-volume-deleting-content-from-container-when-started/28168 --- docker-compose.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1057539..db32e73 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: - elasticsearch # Uncomment if you want to access the code: volumes: - - ./inventaire/server:/opt/inventaire + - inventaire-server:/opt/inventaire logging: options: max-size: "10m" @@ -56,7 +56,7 @@ services: volumes: - ./nginx/templates:/etc/nginx/templates/ - ./nginx/snippets:/etc/nginx/snippets - - ./inventaire/server:/opt/inventaire + - inventaire-server:/opt/inventaire - certbot-www:/var/www/certbot - ./certbot/conf:/etc/letsencrypt env_file: .env @@ -78,3 +78,4 @@ volumes: couchdb: elasticsearch: certbot-www: + inventaire-server: From 4cffed239d968d0607120e91df40bbde3bedd5e6 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 19:19:42 +0100 Subject: [PATCH 35/48] inventaire container: move docker-entrypoint.sh outside of /opt/inventaire to avoid undesired interactions with the shared inventaire-server volume --- inventaire/Dockerfile.inventaire | 6 +++--- inventaire/docker-entrypoint.sh | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/inventaire/Dockerfile.inventaire b/inventaire/Dockerfile.inventaire index 09156b1..888c9b6 100644 --- a/inventaire/Dockerfile.inventaire +++ b/inventaire/Dockerfile.inventaire @@ -30,10 +30,10 @@ RUN npm ci \ && npm ci --omit=dev --ignore-scripts \ && npm cache clean --force -WORKDIR /opt/inventaire +COPY docker-entrypoint.sh /opt/docker-entrypoint.sh -COPY docker-entrypoint.sh docker-entrypoint.sh +WORKDIR /opt/inventaire # Avoid using npm script to start the server # See https://adambrodziak.pl/dockerfile-good-practices-for-node-and-npm#heading-use-node-not-npm-to-start-the-server -ENTRYPOINT [ "./docker-entrypoint.sh" ] +ENTRYPOINT [ "/opt/docker-entrypoint.sh" ] diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh index bc1810c..f637fc5 100755 --- a/inventaire/docker-entrypoint.sh +++ b/inventaire/docker-entrypoint.sh @@ -2,6 +2,8 @@ set -eu +cd /opt/inventaire + # Overwrite the local-${NODE_ENV} config with environment variables every time the container is restarted cat > "./config/local-${NODE_ENV}.cjs" << EOF module.exports = { From 238f2c51d0dab1b9de811cbcf4444062947a0f5d Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 19:38:20 +0100 Subject: [PATCH 36/48] nginx: use http2 directive following the deprecation warning in the logs See http://nginx.org/en/docs/http/ngx_http_v2_module.html --- nginx/templates/default.conf.template | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index eb46823..3212299 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -29,8 +29,11 @@ server { } server { - listen 443 ssl http2; - listen [::]:443 ssl http2; + listen 443 ssl; + listen [::]:443 ssl; + + http2 on; + server_name ${PUBLIC_HOSTNAME}; ssl_certificate /etc/letsencrypt/live/${PUBLIC_HOSTNAME}/fullchain.pem; From 8479151e636cda39e42d08bb30a0b9b947a6f16f Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 20:00:27 +0100 Subject: [PATCH 37/48] docker-compose.yml: elasticsearch: reduce default RAM use --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index db32e73..269dccd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,9 +40,9 @@ services: - 'transport.host=elasticsearch' # See https://www.elastic.co/guide/en/elasticsearch/reference/7.16/docker.html - 'discovery.type=single-node' - # Limit memory usage to 1Go, + # Limit memory usage to 512MB, that should be enough at first # See https://www.elastic.co/guide/en/elasticsearch/reference/current/advanced-configuration.html - - 'ES_JAVA_OPTS=-Xms1g -Xmx1g' + - 'ES_JAVA_OPTS=-Xms512m -Xmx512m' volumes: - 'elasticsearch:/usr/share/elasticsearch/data' restart: unless-stopped From e5a71bd9eac85dcfe830acdf628decb921e841b6 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 20:08:20 +0100 Subject: [PATCH 38/48] docker-compose.yml: elasticsearch: add some more options inspired by https://github.com/elastic/elasticsearch/issues/85463#issuecomment-2299705984 --- docker-compose.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 269dccd..191810a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,6 +43,11 @@ services: # Limit memory usage to 512MB, that should be enough at first # See https://www.elastic.co/guide/en/elasticsearch/reference/current/advanced-configuration.html - 'ES_JAVA_OPTS=-Xms512m -Xmx512m' + - 'xpack.security.enabled=false' + - 'ingest.geoip.downloader.enabled=false' + - 'logger.org.elasticsearch=ERROR' + - 'logger.com.azure.core=ERROR' + - 'logger.org.apache=ERROR' volumes: - 'elasticsearch:/usr/share/elasticsearch/data' restart: unless-stopped From 19383ebc299ce5f37c9506071b59895d5ea83ebf Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 20:24:21 +0100 Subject: [PATCH 39/48] nginx: removing obsolete comment relative to aliases http://nginx.org/en/docs/http/ngx_http_core_module.html#alias which aren't used in this config --- nginx/templates/default.conf.template | 2 -- 1 file changed, 2 deletions(-) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 3212299..ecffb76 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -91,8 +91,6 @@ server { } } - # following aliases made in order to respect the url structure - # the server alone would follow: especially, mounting /static on /public root /opt/inventaire/client; location /public/ { include /etc/nginx/snippets/security_headers.conf; From 4d61613826fbd53b40d567b98fcb50412c2b16f9 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 20:36:40 +0100 Subject: [PATCH 40/48] inventaire: local config: fix hostname inventaire being the server hostname within the docker container --- inventaire/docker-entrypoint.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh index f637fc5..49afbe4 100755 --- a/inventaire/docker-entrypoint.sh +++ b/inventaire/docker-entrypoint.sh @@ -7,6 +7,7 @@ cd /opt/inventaire # Overwrite the local-${NODE_ENV} config with environment variables every time the container is restarted cat > "./config/local-${NODE_ENV}.cjs" << EOF module.exports = { + hostname: 'inventaire', port: '${INVENTAIRE_PORT}', publicHostname: '${PUBLIC_HOSTNAME}', instanceName: '${INSTANCE_NAME}', From 8f14a6eea147b6824f98b99262e32690a02809de Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 20:39:29 +0100 Subject: [PATCH 41/48] inventaire: local config: document config overwrites --- inventaire/docker-entrypoint.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh index 49afbe4..76e1763 100755 --- a/inventaire/docker-entrypoint.sh +++ b/inventaire/docker-entrypoint.sh @@ -4,8 +4,11 @@ set -eu cd /opt/inventaire -# Overwrite the local-${NODE_ENV} config with environment variables every time the container is restarted -cat > "./config/local-${NODE_ENV}.cjs" << EOF +# Overwrites the local config with environment variables every time the container is restarted +# This file can be itself overwritten either by ./config/local-production.cjs (assuming NODE_ENV=production) or by NODE_CONFIG +# See https://github.com/node-config/node-config/wiki/Configuration-Files#file-load-order +# and https://github.com/node-config/node-config/wiki/Environment-Variables#node_config +cat > "./config/local.cjs" << EOF module.exports = { hostname: 'inventaire', port: '${INVENTAIRE_PORT}', From f128298778659ec7bcd33fcfd2e2e3969667f214 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 21:00:00 +0100 Subject: [PATCH 42/48] nginx: recover catch all (aka client router) location --- nginx/templates/default.conf.template | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index ecffb76..da1c54c 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -92,7 +92,7 @@ server { } root /opt/inventaire/client; - location /public/ { + location /public { include /etc/nginx/snippets/security_headers.conf; limit_except GET { deny all; @@ -172,4 +172,19 @@ server { default_type "text/plain"; root /var/www/certbot; } + + location / { + include /etc/nginx/snippets/security_headers.conf; + gzip_static on; + limit_except GET { + deny all; + } + # index.html should always be fresh out of the server + # time is negative => “Cache-Control: no-cache” + # http://nginx.org/en/docs/http/ngx_http_headers_module.html + # Those headers should be set here and not at "location /" as they would be ignored (cf http://serverfault.com/a/786248) + expires -1; + # The remaining routes (/users, /entity, etc) should be handled by the client router + rewrite .* /public/index.html break; + } } From b4d42a83e5dd318254402a8f733ba53a15919fba Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 22:27:06 +0100 Subject: [PATCH 43/48] nginx: recover location @invimg --- nginx/templates/default.conf.template | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index da1c54c..17df5ff 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -91,6 +91,23 @@ server { } } + location ~ ^/img/ { + return 404; + } + + location @invimg { + include /etc/nginx/snippets/security_headers.conf; + default_type "image/jpeg"; + # add_header Content-Type "image/jpeg"; + add_header X-File-Cache "miss"; + add_header Content-Security-Policy "sandbox"; + proxy_temp_path /tmp/nginx/tmp; + proxy_store /tmp/nginx/resize/$uri; + proxy_store_access user:rw group:rw all:r; + proxy_http_version 1.1; + proxy_pass http://inv; + } + root /opt/inventaire/client; location /public { include /etc/nginx/snippets/security_headers.conf; From 0d17fb551d61de3f3e8b849c9079078113e314a3 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 22:39:16 +0100 Subject: [PATCH 44/48] inventaire: add map tiles, analytics, and media storage configuration --- dotenv | 20 ++++++++++++++++++++ inventaire/docker-entrypoint.sh | 19 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/dotenv b/dotenv index 9f59e75..c70bda5 100644 --- a/dotenv +++ b/dotenv @@ -21,6 +21,26 @@ MAILER_SMTP_PORT=587 MAILER_SMTP_USERNAME=your_username_on_smtp.example.org MAILER_SMTP_PASSWORD=your_password_on_smtp.example.org +# Required to use MapBox tiles within leaflet maps +# See https://console.mapbox.com/account/access-tokens/ +MAP_TILES_ACCESS_TOKEN='youraccesstoken' + +# [OPTIONAL] Setup Matomo analytics https://matomo.org/ +MOTOMO_ENABLED=false +MOTOMO_ENDPOINT=https://yourmatomoendpoint/matomo.php +MOTOMO_IDSITE=1 +MOTOMO_REC=1 + +MEDIA_STORAGE_MODE=local +# Set MEDIA_STORAGE_MODE=swift and the following variables +# to store users and groups images in an OpenStack Swift container +SWIFT_USERNAME=customizedInLocalConfig +SWIFT_PASSWORD=customizedInLocalConfig +SWIFT_AUTH_URL=https://openstackEndpointToCustomize +SWIFT_PUBLIC_URL=https://swiftPublicURL +SWIFT_TENANT_NAME=12345678 +SWIFT_REGION=SBG-1 + ######## # Everything below is a default configuration # Modify if you know what you are doing diff --git a/inventaire/docker-entrypoint.sh b/inventaire/docker-entrypoint.sh index 76e1763..f1cbd75 100755 --- a/inventaire/docker-entrypoint.sh +++ b/inventaire/docker-entrypoint.sh @@ -17,7 +17,6 @@ module.exports = { orgName: '${ORG_NAME}', orgUrl: '${ORG_URL}', contactAddress: '${CONTACT_ADDRESS}', - db: { username: '${COUCHDB_USER}', password: '${COUCHDB_PASSWORD}', @@ -37,6 +36,24 @@ module.exports = { }, }, }, + mapTilesAccessToken: '${MAP_TILES_ACCESS_TOKEN}', + matomo: { + enabled: ${MOTOMO_ENABLED}, + endpoint: '${MOTOMO_ENDPOINT}', + idsite: ${MOTOMO_IDSITE}, + rec: ${MOTOMO_REC}, + }, + mediaStorage: { + mode: '${MEDIA_STORAGE_MODE}', + swift: { + username: '${SWIFT_USERNAME}', + password: '${SWIFT_PASSWORD}', + authUrl: '${SWIFT_AUTH_URL}', + publicURL: '${SWIFT_PUBLIC_URL}', + tenantName: '${SWIFT_TENANT_NAME}', + region: '${SWIFT_REGION}', + }, + }, } EOF From f91ad3c8a3042d5dd72bde44761a8c51921c6341 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 22:50:54 +0100 Subject: [PATCH 45/48] nginx: fix proxy_store --- nginx/templates/default.conf.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 17df5ff..ffbcd04 100755 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -102,7 +102,7 @@ server { add_header X-File-Cache "miss"; add_header Content-Security-Policy "sandbox"; proxy_temp_path /tmp/nginx/tmp; - proxy_store /tmp/nginx/resize/$uri; + proxy_store /tmp/nginx/resize$uri; proxy_store_access user:rw group:rw all:r; proxy_http_version 1.1; proxy_pass http://inv; From 51092715298af4af34a966b9abfed5d452942e87 Mon Sep 17 00:00:00 2001 From: maxlath Date: Thu, 27 Feb 2025 23:02:01 +0100 Subject: [PATCH 46/48] nginx: fix /tmp/nginx permission issues --- nginx/Dockerfile.nginx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx/Dockerfile.nginx b/nginx/Dockerfile.nginx index ccd99fc..385865d 100644 --- a/nginx/Dockerfile.nginx +++ b/nginx/Dockerfile.nginx @@ -1,5 +1,5 @@ FROM nginx -RUN mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets +RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 -RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 \ No newline at end of file +RUN mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets && chown -R nginx:nginx /tmp/nginx From a3b10d26743fe25ac402b9ae1aad2dbb9f01cdda Mon Sep 17 00:00:00 2001 From: jums Date: Fri, 28 Feb 2025 08:04:29 +0100 Subject: [PATCH 47/48] gitignore: add certbot folder to untrack the autogenerated certbot config folder, created when running certonly --- .gitignore | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 37128c7..c7924ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ +.docker .env +.eslintcache +certbot data log -.eslintcache -.docker From ab286b496834fe6371fd46d5b70afb8f91b9be41 Mon Sep 17 00:00:00 2001 From: jums Date: Fri, 28 Feb 2025 08:17:38 +0100 Subject: [PATCH 48/48] Dockerfile.nginx: only generate pem key if the file does not exist --- nginx/Dockerfile.nginx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx/Dockerfile.nginx b/nginx/Dockerfile.nginx index 385865d..5d4c89f 100644 --- a/nginx/Dockerfile.nginx +++ b/nginx/Dockerfile.nginx @@ -1,5 +1,5 @@ FROM nginx -RUN openssl dhparam -out /etc/nginx/dhparam.pem 2048 +RUN [ ! -f /etc/nginx/dhparam.pem ] && openssl dhparam -out /etc/nginx/dhparam.pem 2048 RUN mkdir -p /tmp/nginx/tmp /tmp/nginx/resize/img/users /tmp/nginx/resize/img/groups /tmp/nginx/resize/img/entities /tmp/nginx/resize/img/remote /tmp/nginx/resize/img/assets && chown -R nginx:nginx /tmp/nginx