<!-- Note: This file is primarily defined to be used in the IXP documentation. However, it is also provided in the docker-deployment repository for reference. If you accessed this file from the docker-deployment repository, please be aware that the links used in this file may not work as expected. -->

## Deployment using Docker/Nginx

INJECT Exercise Platform provides a simplified deployment method via Docker
Compose. This method simplifies the deployment by creating necessary settings
and pairings between the frontend and backend. It also creates a singular
endpoint for accessing IXP.

### Docker Setup

This solution consists of 5 containers: frontend, backend, redict, database and
reverse proxy server. Frontend and backend are set up to communicate under a
single endpoint handled by the reverse-proxy server (Nginx). PostgreSQL database
handles the management of user/exercise data. Redict is used to allow multiple
workers on the backend. User-uploaded files, images and definition-related
content are stored on the backend. The reverse proxy forwards requests either to
frontend or backend.

Deployment is set up with persistent storage under two Docker Compose volumes
called `inject-data` and `inject-pgdata`. This volume contains any data
generated by IXP and the current configuration of the platform. At the current
state, the platform can be effectively backed up, assuming you back up both
volumes and the `INJECT_SECRET_KEY` environment variable.

### (Optional) Configuring Rootless Docker for Proper Client IP Logging

If you are using _Rootless Docker_ and want to ensure that backend logs
correctly reflect the client's IP address, you need to make the following
changes. Without these adjustments, backend logs may display incorrect IP
addresses, usually showing internal Docker addresses instead of the actual
requester's IP. This configuration is required **only** for _Rootless Docker_;
it is not needed for standard Docker.

#### Step 1: Update packages

Ensure all necessary packages are updated while running as the root user. This
step ensures that all dependencies are up to date and compatible with the
required configurations.

#### Step 2: Modify System Configuration

Since Rootless Docker operates without root privileges, you need to adjust the
network-level driver for the user-level docker.service in systemd to allow
proper traffic routing. To do this, create or update the following override
configuration file _~/.config/systemd/user/docker.service.d/override.conf_ with
the following content:

```
[Service]
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns"
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
```

Also, add `net.ipv4.ip_unprivileged_port_start=0` to _/etc/sysctl.conf_ (or
_/etc/sysctl.d_) and run `sudo sysctl --system`.

#### Step 3: Restart Docker Daemon

Once all the above configurations are in place, reload and restart the Docker
daemon to apply the changes:

```shell
systemctl --user daemon-reload
systemctl --user restart docker
```

#### Step 4: Update Nginx Configuration

To allow Nginx to properly resolve the internal Docker network and access
external client IPs, add the following lines under your Nginx service definition
in the _compose.yml_ file:

```yml
nginx:
  ...
  extra_hosts:
    - "host.docker.internal:host-gateway"
  ports:
    - target: 80
      published: 80
      protocol: tcp
      mode: host
    - target: 443
      published: 443
      protocol: tcp
      mode: host
  ...
```

This configuration ensures that the container correctly forwards traffic to and
from the host machine and that Nginx can resolve the host-gateway address,
allowing it to properly reflect the external IP addresses of incoming requests.

### Environment Variables

All the technical configuration is done with environment variables. Most are
prefixed under `INJECT_`. Some additional variables are included; however, these
are inferred from the `INJECT_` prefixed environment variables, which means that
these do not have to be changed manually.

The available variables are listed below:

**Domain & Security**

- `INJECT_DOMAIN` – The domain name where your IXP instance will be accessible
    (e.g., `example.com`).
- `INJECT_HOMEPAGE` – URL of the homepage or landing page for your IXP instance.
- `INJECT_SECRET_KEY` – A cryptographically secure string (minimum 50
    characters) used for signing and securing sessions. Keep this value private.
- `INJECT_HOST_ADDRESSES` – Comma-separated list of hostnames or IP addresses
    permitted to access the backend (e.g., `example.com,www.example.com`).
- `VITE_HTTPS_HOST` – The HTTPS URL or hostname that the frontend should use to
    connect to the backend service.
- `CORS_ALLOWED_ORIGINS` – Comma-separated list of origins allowed for
    Cross-Origin Resource Sharing (CORS), enabling secure API access from
    specified domains.
- `INJECT_REQUEST_TIMEOUT` – A number of seconds which should be set as the
    timeout value in NGINX.

**Email Configuration**

- `INJECT_EMAIL_HOST` – The SMTP server address used for sending emails (e.g.,
    `smtp.mailprovider.com`).
- `INJECT_EMAIL_PORT` – Port number for connecting to the SMTP server (commonly
    `25` for unencrypted, `465` for SSL, and `587` for TLS).
- `INJECT_EMAIL_HOST_USER` – Username for authenticating with the SMTP server.
- `INJECT_EMAIL_HOST_PASSWORD` – Password for the SMTP server user account. Used
    together with `INJECT_EMAIL_HOST_USER`.
- `INJECT_EMAIL_SENDER_ADDRESS` – Email address that appears as the sender in
    automated emails from the platform.
- `INJECT_EMAIL_PROTOCOL` – (Optional) Protocol for SMTP communication: `ssl` or
    `tls` (case-insensitive). Leave unset for unencrypted connections.

**Logging**

- `INJECT_LOGS` – Filesystem path where application logs will be stored (e.g.,
    `/var/log/inject.log`).

**Database**

- `INJECT_DB_HOST` – Hostname or IP address of the PostgreSQL database server.
- `INJECT_DB_USER` – Username for connecting to the database.
- `INJECT_DB_PASS` – Password for the database user.
- `INJECT_DB_MAX_CONNECTIONS` – Sets the maximum number of connections that PostgreSQL can accept.
    Approximate formula for how many connections will be used:
    `2 x INJECT_WORKER_COUNT +   maximum expected running synchronous exercise count +   maximum expected running team count in on-demand exercises`.
    For example, with 8 workers, 5 running synchronous exercises and 3 on-demand exercises with 20 teams each,
    the minimum number of connections is 81. It is recommended to leave some headroom.

**Redict (Backend Worker Management)**

- `INJECT_REDICT_HOST` – Host address for the Redict service. Set to enable
    Redict for backend worker management.
- `INJECT_WORKER_COUNT` – Number of backend worker processes to spawn. Adjust
    for optimal performance based on available resources.

**OpenSearch Integration**

- `INJECT_OPENSEARCH_HOST` – Host address for the OpenSearch service. Set to
    enable OpenSearch integration.
- `VITE_OPENSEARCH_HOST` – OpenSearch host address exposed to frontend clients.
- `INJECT_OPENSEARCH_PORT` – Port number for connecting to the OpenSearch
    service.
- `VITE_OPENSEARCH_PORT` – OpenSearch port number exposed to frontend clients.
- `INJECT_OPENSEARCH_USER` – Username for authenticating with OpenSearch.
- `INJECT_OPENSEARCH_PASSWORD` – Password for the OpenSearch user account.

You can use the default `.env` file to set up your configuration. Such a file is
included both in the [Let's Encrypt](./https/base-setup.md) and
[self-provided certificate](./https/owncert.md) setup guides.

<div class="navigation" markdown>
  [&larr; Installation overview](./overview.md){ .md-button }
</div>
