Merge pull request #12 from inventaire/package-prod
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
inventaire
|
||||
.docker
|
||||
.env
|
||||
.eslintcache
|
||||
certbot
|
||||
data
|
||||
log
|
||||
configs/docker.ini
|
||||
|
||||
|
||||
227
README.md
227
README.md
@@ -1,202 +1,109 @@
|
||||
Run [Inventaire](https://github.com/inventaire/inventaire) in Docker
|
||||
# Inventaire Suite
|
||||
|
||||
This repository is meant to support running Inventaire for testing and development. For production, 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).
|
||||
|
||||
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/), 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).
|
||||
|
||||
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
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
|
||||
- [Requirements](#requirements)
|
||||
- [Install](#install)
|
||||
- [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)
|
||||
- [Tests](#tests)
|
||||
- [Push git commits](#push-git-commits)
|
||||
- [Rootless Docker](#rootless-docker)
|
||||
- [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)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## 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
|
||||
> 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
|
||||
```sh
|
||||
git clone https://github.com/inventaire/docker-inventaire.git
|
||||
git clone https://git.inventaire.io/docker-inventaire.git
|
||||
cd docker-inventaire
|
||||
```
|
||||
|
||||
Clone `inventaire` core application [server](https://github.com/inventaire/inventaire)
|
||||
### Initial configuration
|
||||
Copy the `dotenv` file to `.env`
|
||||
```sh
|
||||
cp dotenv .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)
|
||||
|
||||
#### Generate a TLS certificate
|
||||
> Ignore this section if you are just testing on your local machine
|
||||
|
||||
Generate the first TLS certificate with Let's Encrypt
|
||||
|
||||
```sh
|
||||
git clone https://github.com/inventaire/inventaire.git
|
||||
docker run -it --rm --name certbot -p 80:80 -v "$(pwd)/certbot/conf:/etc/letsencrypt" certbot/certbot certonly --standalone
|
||||
```
|
||||
|
||||
Build
|
||||
|
||||
```sh
|
||||
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
|
||||
```
|
||||
|
||||
Configure inventaire so that it can connect to CouchDB. For that, create a file `config/local.cjs` with the following command:
|
||||
|
||||
```sh
|
||||
echo "module.exports = {
|
||||
db: {
|
||||
username: 'yourcouchdbusername',
|
||||
password: 'yourcouchdbpassword'
|
||||
}
|
||||
}
|
||||
" > ./inventaire/config/local.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 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
|
||||
```
|
||||
|
||||
To also work on the [client](https://github.com/inventaire/inventaire-client), you need to also start the webpack dev server:
|
||||
Alternatively, to test locally, you can start only Inventaire and its dependencies (CouchDB and Elasticsearch) without Nginx, with the following command:
|
||||
```sh
|
||||
cd inventaire/client
|
||||
npm run watch
|
||||
docker compose up inventaire
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
### Fixtures
|
||||
|
||||
In case you would like to play with out-of-the-box data.
|
||||
|
||||
Run api tests to populate tests dbs (see Tests section)
|
||||
|
||||
```sh
|
||||
docker-compose -f docker-compose.yml -f docker-compose.test.yml exec inventaire npm run test-api
|
||||
```
|
||||
|
||||
- Replicate `*-tests` dbs documents into `*` dbs
|
||||
|
||||
```sh
|
||||
`docker-compose exec inventaire npm run replicate-tests-db`
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
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
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
|
||||
### 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`
|
||||
|
||||
@@ -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
|
||||
5
couchdb/Dockerfile.couchdb
Normal file
5
couchdb/Dockerfile.couchdb
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM couchdb:3.4.2
|
||||
|
||||
COPY local.ini /opt/couchdb/etc/local.d/local.ini
|
||||
|
||||
# Inherit ENTRYPOINT and CMD from couchdb image
|
||||
8
couchdb/local.ini
Normal file
8
couchdb/local.ini
Normal file
@@ -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
|
||||
@@ -1,28 +1,86 @@
|
||||
version: '3'
|
||||
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:/opt/inventaire
|
||||
logging:
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
restart: unless-stopped
|
||||
couchdb:
|
||||
image: couchdb:3.4.2
|
||||
ports:
|
||||
- "5984:5984"
|
||||
environment:
|
||||
COUCHDB_USER: "yourcouchdbusername"
|
||||
COUCHDB_PASSWORD: "yourcouchdbpassword"
|
||||
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/)
|
||||
# /!\ 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:
|
||||
- 'couchdb:/opt/couchdb/data'
|
||||
- './configs:/opt/couchdb/etc/local.d'
|
||||
tty: true
|
||||
restart: unless-stopped
|
||||
elasticsearch:
|
||||
image: elasticsearch:7.16.2
|
||||
image: elasticsearch:7.17.28
|
||||
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'
|
||||
- 'ES_JAVA_OPTS=-Xms1g -Xmx1g'
|
||||
# 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'
|
||||
ports :
|
||||
- '127.0.0.1:9200:9200'
|
||||
restart: unless-stopped
|
||||
nginx:
|
||||
build:
|
||||
context: ./nginx
|
||||
dockerfile: Dockerfile.nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/templates:/etc/nginx/templates/
|
||||
- ./nginx/snippets:/etc/nginx/snippets
|
||||
- inventaire-server:/opt/inventaire
|
||||
- certbot-www:/var/www/certbot
|
||||
- ./certbot/conf:/etc/letsencrypt
|
||||
env_file: .env
|
||||
depends_on:
|
||||
# Required to be able to define the `inventaire` host as an upstream
|
||||
- inventaire
|
||||
restart: unless-stopped
|
||||
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:
|
||||
elasticsearch:
|
||||
certbot-www:
|
||||
inventaire-server:
|
||||
|
||||
53
dotenv
Normal file
53
dotenv
Normal file
@@ -0,0 +1,53 @@
|
||||
# Your website domain name
|
||||
PUBLIC_HOSTNAME=an-inventaire-site.org
|
||||
|
||||
# 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
|
||||
|
||||
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'
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
########
|
||||
|
||||
NODE_ENV=production
|
||||
NODE_APP_INSTANCE=federated
|
||||
|
||||
# Conventional port for Inventaire server in federated mode
|
||||
INVENTAIRE_PORT=3016
|
||||
39
inventaire/Dockerfile.inventaire
Normal file
39
inventaire/Dockerfile.inventaire
Normal file
@@ -0,0 +1,39 @@
|
||||
FROM node:20-slim
|
||||
|
||||
RUN apt-get update \
|
||||
&& 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 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
|
||||
|
||||
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 \
|
||||
&& npm run build \
|
||||
&& 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
|
||||
|
||||
# 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
|
||||
|
||||
COPY docker-entrypoint.sh /opt/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 [ "/opt/docker-entrypoint.sh" ]
|
||||
61
inventaire/docker-entrypoint.sh
Executable file
61
inventaire/docker-entrypoint.sh
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
cd /opt/inventaire
|
||||
|
||||
# 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}',
|
||||
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',
|
||||
},
|
||||
mailer: {
|
||||
disabled: false,
|
||||
nodemailer: {
|
||||
host: '${MAILER_SMTP_HOST}',
|
||||
port: ${MAILER_SMTP_PORT},
|
||||
auth: {
|
||||
user: '${MAILER_SMTP_USERNAME}',
|
||||
pass: '${MAILER_SMTP_PASSWORD}'
|
||||
},
|
||||
},
|
||||
},
|
||||
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
|
||||
|
||||
./scripts/typescript/start_built_server.sh
|
||||
5
nginx/Dockerfile.nginx
Normal file
5
nginx/Dockerfile.nginx
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM nginx
|
||||
|
||||
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
|
||||
12
nginx/snippets/security_headers.conf
Executable file
12
nginx/snippets/security_headers.conf
Executable file
@@ -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;
|
||||
11
nginx/snippets/ssl.conf
Normal file
11
nginx/snippets/ssl.conf
Normal file
@@ -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;
|
||||
207
nginx/templates/default.conf.template
Executable file
207
nginx/templates/default.conf.template
Executable file
@@ -0,0 +1,207 @@
|
||||
# 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 inv {
|
||||
server inventaire:${INVENTAIRE_PORT} 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;
|
||||
listen [::]:443 ssl;
|
||||
|
||||
http2 on;
|
||||
|
||||
server_name ${PUBLIC_HOSTNAME};
|
||||
|
||||
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;
|
||||
|
||||
client_max_body_size 25M;
|
||||
|
||||
# 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
|
||||
# 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
|
||||
|
||||
# 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://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
|
||||
# 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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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://inv;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
20
scripts/docker_publish.sh
Executable file
20
scripts/docker_publish.sh
Executable file
@@ -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"
|
||||
Reference in New Issue
Block a user