diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..b3c3264 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,46 @@ +name: build and push docker image + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + + + build-tictactoe: + runs-on: ubuntu-20.04 + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Log in to the Container registry + uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc + with: + context: . + file: Dockerfile-nginx-mug + push: true + tags: ${{ steps.meta.outputs.tags }}-nginx + labels: ${{ steps.meta.outputs.labels }}-nginx diff --git a/Dockerfile-nginx-mug b/Dockerfile-nginx-mug new file mode 100644 index 0000000..dc8b1b7 --- /dev/null +++ b/Dockerfile-nginx-mug @@ -0,0 +1,4 @@ +FROM nginx +COPY nginx.conf /etc/nginx/nginx.conf +COPY conf-mug.d/* /etc/nginx/conf.d/ + diff --git a/README.md b/README.md index 1cd935d..9cfacec 100644 --- a/README.md +++ b/README.md @@ -80,5 +80,12 @@ To set up your database, indexes, and related components, follow these steps. invenio roles add admin@inveniordm.example.com admin ``` +## MUG +For this deployment, we have set up a new NGINX container without SSL enabled, which acts as a reverse proxy for both the UI and API containers. **MUG** should use port `8000` of this container to route requests through its own proxy server. +**update the environment variables.** [.env.temp](.env.temp) + +```bash +docker compose -f mug-compose.yml up -d +``` diff --git a/conf-mug.d/default.conf b/conf-mug.d/default.conf new file mode 100644 index 0000000..79227a3 --- /dev/null +++ b/conf-mug.d/default.conf @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020-2024 Graz University of Technology. +# + +upstream ui_server { + server web-ui:5000 fail_timeout=0; +} +upstream api_server { + server web-api:5000 fail_timeout=0; +} + +server { + listen 8000; # IPv4 + server_name _; + charset utf-8; + keepalive_timeout 5; + + + add_header Strict-Transport-Security "max-age=15768000"; # 6 months + + # Request ID tracing (allows end-to-end tracking of requests for better + # troubleshooting) + add_header X-Request-ID $request_id; + + # The request body is sent to the proxied server immediately as it is + # received + proxy_request_buffering off; + # Sets the HTTP protocol v1.1 for proxying in order to not use the buffer + # in case of chunked transfer encoding + proxy_http_version 1.1; + + # Proxying to the application server + ## UI server + location / { + uwsgi_pass ui_server; + include uwsgi_params; + uwsgi_buffering off; + uwsgi_request_buffering off; + uwsgi_param Host $host; + uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; + uwsgi_param X-Forwarded-Proto $scheme; + # Pass request id to the ui server + uwsgi_param X-Request-ID $request_id; + # X-Session-ID / X-User-ID is read by nginx and included in the logs, + # however we don't want to expose them to clients so we are hiding them. + uwsgi_hide_header X-Session-ID; + uwsgi_hide_header X-User-ID; + # Max upload size (except for files) is set to 100mb as default. + client_max_body_size 100m; + } + ## Most API + location /api { + uwsgi_pass api_server; + include uwsgi_params; + uwsgi_buffering off; + uwsgi_request_buffering off; + uwsgi_param Host $host; + uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; + uwsgi_param X-Forwarded-Proto $scheme; + # Pass request id to the api server + uwsgi_param X-Request-ID $request_id; + # X-Session-ID / X-User-ID is read by nginx and included in the logs, + # however we don't want to expose them to clients so we are hiding them. + uwsgi_hide_header X-Session-ID; + uwsgi_hide_header X-User-ID; + # Max upload size (except for files) is set to 100mb as default. + client_max_body_size 100m; + } + ## API files + # Another location is defined in order to allow large file uploads in the files + # API without exposing the other parts of the application to receive huge + # request bodies. + location ~ /api/records/.+/draft/files/.+/content { + gzip off; + uwsgi_pass api_server; + include uwsgi_params; + uwsgi_buffering off; + uwsgi_request_buffering off; + uwsgi_param Host $host; + uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for; + uwsgi_param X-Forwarded-Proto $scheme; + # Pass request id to api server + uwsgi_param X-Request-ID $request_id; + # X-Session-ID / X-User-ID is read by nginx and included in the logs, + # however we don't want to expose them to clients so we are hiding them. + uwsgi_hide_header X-Session-ID; + uwsgi_hide_header X-User-ID; + # Max upload size for files is set to 50GB (configure as needed). + client_max_body_size 50G; + } + # Static content is served directly by nginx and not the application server. + location /static { + alias /opt/invenio/var/instance/static; + autoindex off; + } + # Robots.txt file is served by nginx. + location /robots.txt { + alias /opt/invenio/var/instance/static/robots.txt; + autoindex off; + } +} diff --git a/mug-compose.yml b/mug-compose.yml new file mode 100644 index 0000000..83965a6 --- /dev/null +++ b/mug-compose.yml @@ -0,0 +1,115 @@ +services: + cache: + image: redis:7 + restart: "unless-stopped" + read_only: true + ports: + - "6379:6379" + volumes: + - redis_data:/data + + db: + image: postgres:14.13 + restart: "unless-stopped" + environment: + - "POSTGRES_USER=inveniordm" + - "POSTGRES_PASSWORD=inveniordm" + - "POSTGRES_DB=inveniordm" + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + + mq: + image: rabbitmq:3-management + restart: "unless-stopped" + ports: + - "15672:15672" + - "5672:5672" + volumes: + - rabbitmq_data:/var/lib/rabbitmq + + search: + image: opensearchproject/opensearch:2 + restart: "unless-stopped" + volumes: + - os_data:/usr/share/opensearch/data + environment: + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" + - "DISABLE_INSTALL_DEMO_CONFIG=true" + - "DISABLE_SECURITY_PLUGIN=true" + - "discovery.type=single-node" + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 + hard: 65536 + mem_limit: 2g + ports: + - "9200:9200" + - "9600:9600" + + frontend: + image: ghcr.io/sharedrdm/inveniordm-mug:main-nginx + depends_on: + - web-ui + - web-api + ports: + - "8000:8000" + volumes: + - static_data:/opt/invenio/var/instance/static + + web-ui: + command: ["uwsgi /opt/invenio/var/instance/uwsgi_ui.ini"] + pull_policy: always + image: ghcr.io/sharedrdm/instance:main-mug-v12 + env_file: .env.temp + depends_on: + - search + - cache + - mq + volumes: + - static_data:/opt/invenio/var/instance/static + - uploaded_data:/opt/invenio/var/instance/data + - archived_data:/opt/invenio/var/instance/archive + # ports: + # - "5000:5000" + + web-api: + command: ["uwsgi /opt/invenio/var/instance/uwsgi_rest.ini"] + pull_policy: always + image: ghcr.io/sharedrdm/instance:main-mug-v12 + env_file: .env.temp + depends_on: + - search + - cache + - mq + volumes: + - uploaded_data:/opt/invenio/var/instance/data + - archived_data:/opt/invenio/var/instance/archive + # ports: + # - "5000:5000" + + worker: + command: ["celery -A invenio_app.celery worker --beat --events --loglevel=INFO"] + image: ghcr.io/sharedrdm/instance:main-mug-v12 + pull_policy: always + env_file: .env.temp + depends_on: + - search + - cache + - mq + volumes: + - uploaded_data:/opt/invenio/var/instance/data + +volumes: + redis_data: + postgres_data: + rabbitmq_data: + static_data: + uploaded_data: + os_data: + archived_data: diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..c10c295 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2020-2024 Graz University of Technology. +# +# + +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Standard log format + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + # Request tracing log format - includes request id, session id, user id, + # and request timing. + log_format trace '$remote_addr - [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for" $request_id ' + '$msec $request_time ' + '$upstream_http_x_session_id $upstream_http_x_user_id'; + + access_log /var/log/nginx/access.log trace; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + + keepalive_timeout 65; + + gzip on; + gzip_disable "msie6"; + gzip_http_version 1.1; + gzip_comp_level 5; # or anything between 4-6 + gzip_min_length 100; + gzip_proxied any; + # We may need more mime-types here (eg. 'application/x-bibtex') + gzip_types + application/atom+xml + application/javascript + application/json + application/ld+json + application/manifest+json + application/octet-stream + application/rss+xml + application/vnd.geo+json + application/vnd.ms-fontobject + application/x-font-ttf + application/x-javascript + application/x-web-app-manifest+json + application/xhtml+xml + application/xml + application/xml+rss + font/opentype + image/bmp + image/svg+xml + image/x-icon + text/cache-manifest + text/css + text/javascript + text/plain + text/vcard + text/vnd.rim.location.xloc + text/vtt + text/x-component + text/x-cross-domain-policy + text/xml; + gzip_vary on; + + include /etc/nginx/conf.d/*.conf; +}