# Установка exchanger-web

{% tabs %}
{% tab title="Docker" %}

#### Prepare dependencies

```bash
apt install -y nano sudo curl wget
apt update
apt upgrade -y
```

#### 1. Install Docker and Docker Compose

```bash
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
```

#### 2. Create runner user and add it to sudoers <a href="#user-content-2-create-runner-user-and-add-it-to-sudoers" id="user-content-2-create-runner-user-and-add-it-to-sudoers"></a>

```bash
sudo adduser --disabled-password --gecos "" runner
sudo usermod -aG sudo runner
```

#### 3. Create docker group and add user to it <a href="#user-content-3-create-docker-group-and-add-user-to-it" id="user-content-3-create-docker-group-and-add-user-to-it"></a>

```bash
sudo usermod -aG docker runner
```

#### 4. Switch to a 'runner' user <a href="#user-content-4-switch-to-a-runner-user" id="user-content-4-switch-to-a-runner-user"></a>

```bash
sudo su runner
```

```bash
newgrp docker
```

#### 5. Create docker network <a href="#user-content-10-create-docker-network" id="user-content-10-create-docker-network"></a>

```bash
docker network create --subnet 10.1.0.0/24 exchanger-net
```

#### 6. Docker login

* Create a Personal Access Token in GitLab
* Make sure to tick the `read_registry` permission scope
* Create a reminder to update the PAT after expiration date, as once it expires you lose access for updates.\
  <https://git.boxexchanger.net/-/profile/personal_access_tokens>
* Login to docker read\_registry

  <pre class="language-bash"><code class="lang-bash">docker login rg.boxexchanger.net

  <strong># Username: your_gitlab_username
  </strong># Password: your_gitlab_pat
  </code></pre>

#### 7. Create required folders <a href="#user-content-7-create-required-folders" id="user-content-7-create-required-folders"></a>

```bash
mkdir -p /home/runner/web_server
mkdir -p /home/runner/web_server/config
mkdir -p /home/runner/web_server/public
mkdir -p /home/runner/web_server/nginx
cd /home/runner/web_server
```

#### 8. Place basic nginx config `server_names_hash_bucket_size.conf` <a href="#user-content-8-copy-the-files-to-homerunnerapi_server" id="user-content-8-copy-the-files-to-homerunnerapi_server"></a>

<pre class="language-bash"><code class="lang-bash"><strong>nano /home/runner/web_server/nginx/server_names_hash_bucket_size.conf
</strong></code></pre>

with content:&#x20;

```nginx
server_names_hash_bucket_size 64;
```

#### 9. Place basic nginx config `nginx_default.conf` <a href="#user-content-8-copy-the-files-to-homerunnerapi_server" id="user-content-8-copy-the-files-to-homerunnerapi_server"></a>

<pre class="language-bash"><code class="lang-bash"><strong>nano /home/runner/web_server/nginx/nginx_default.conf 
</strong></code></pre>

with content:&#x20;

```nginx
server {
    listen 80 default_server;
    server_name _;
    return 500;
}
```

#### 10. Place Nginx `nginx_admin.conf` config <a href="#user-content-8-copy-the-files-to-homerunnerapi_server" id="user-content-8-copy-the-files-to-homerunnerapi_server"></a>

{% hint style="info" %}
If you are using separate server for web and api change proxy\_pass <http://nginx-api:3000/service/>  to **<http://ip.your.api.serveri:3000/service/>** and expose port 3000 from your api server
{% endhint %}

```bash
nano /home/runner/web_server/nginx/nginx_admin.conf
```

```nginx
map $http_upgrade $connection_upgrade {
    default upgrade;
    ""      close;
}

server {
    listen 80;
    server_name admin.domain.name;

    location / {
        proxy_pass http://exchanger-admin-web:80;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
    
    location /service/ {
        proxy_pass http://nginx-api:3000/service/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
    location /ws/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://nginx-api:3000/ws/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_redirect    off;
    }
    
    access_log off;
    error_log  /var/log/nginx-admin-error.log error;
    sendfile off;
    client_max_body_size 100m;
}
```

#### 11.  Place Nginx `nginx_web.conf` config <a href="#user-content-8-copy-the-files-to-homerunnerapi_server" id="user-content-8-copy-the-files-to-homerunnerapi_server"></a>

```bash
nano /home/runner/web_server/nginx/nginx_web.conf
```

```nginx
map $http_upgrade $connection_upgrade {
    default upgrade;
    ""      close;
}
server {
    listen 80;
    server_name domain.name;
    return 301 https://www.domain.name$request_uri;
}

server {
    listen 80;
    server_name www.domain.name;
    location / {
        proxy_pass http://exchanger-client-web:80;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
    location /service/ {
        proxy_pass http://nginx-api:3000/service/;
        proxy_http_version 1.1;
        add_header CF-IPCountry $http_cf_ipcountry always;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
    location /ref/ {
        proxy_pass http://nginx-api:3000/service/ref/;
        proxy_http_version 1.1;
        add_header CF-IPCountry $http_cf_ipcountry always;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
    location /ws/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://nginx-api:3000/ws/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_redirect    off;
    }
        
    access_log off;
    error_log  /var/log/nginx-error.log error;
    sendfile off;
    client_max_body_size 100m;
}
```

#### 12. Create config file (.env) <a href="#user-content-8-copy-the-files-to-homerunnerapi_server" id="user-content-8-copy-the-files-to-homerunnerapi_server"></a>

```bash
nano /home/runner/web_server/.env
```

```bash
VCS_NAMESPACE=bx4/project-name
```

{% hint style="info" %}
If you would like to setup your branch please add variable to your .env file&#x20;

&#x20;`CLIENT_BRANCH` for client-web and

&#x20;`ADMIN_BRANCH` for admin-web
{% endhint %}

#### 12.  Create your docker-compose.yml <a href="#user-content-8-copy-the-files-to-homerunnerapi_server" id="user-content-8-copy-the-files-to-homerunnerapi_server"></a>

<pre class="language-bash"><code class="lang-bash"><strong>nano /home/runner/web_server/docker-compose.yml
</strong></code></pre>

```yaml
version: '3'
services:
  nginx-web:
    image: nginxinc/nginx-unprivileged:1.27-alpine
    read_only: true
    container_name: nginx-web
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    logging: *default-logging
    networks:
      exchanger-net:
        ipv4_address: 10.1.0.250
    volumes:
      - ./nginx/:/etc/nginx/conf.d:ro
      - type: tmpfs
        target: /docker-entrypoint.d/
        tmpfs:
          size: "100000"
      - type: tmpfs
        target: /tmp/
        tmpfs:
          size: "10000000"
  exchanger-admin-web:
    image: rg.boxexchanger.net/${VCS_NAMESPACE}/exchanger-admin-web:${ADMIN_BRANCH:-master}
    container_name: exchanger-admin-web
    restart: unless-stopped
    networks:
      exchanger-net:
        ipv4_address: 10.1.0.5
  exchanger-client-web:
    image: rg.boxexchanger.net/${VCS_NAMESPACE}/exchanger-client-web:${CLIENT_BRANCH:-box}
    container_name: exchanger-client-web
    restart: unless-stopped
    networks:
      exchanger-net:
        ipv4_address: 10.1.0.4
networks:
    exchanger-net:
        external: true
```

#### 13.  Start WEB server

```bash
docker compose up -d
```

{% hint style="info" %}
All web configuration and request for build project you find in your personal account on our website <https://licence.boxexchanger.net/licenses/>
{% endhint %}

{% hint style="warning" %}
**Server Side Render**:&#x20;

* **Attention!** This mod is not recommended for use; it creates a load on the server to build the project for each client, which greatly increases the delay in loading the site

To enable SSR mode add variable **`SSR = 1`** in your account <https://licence.boxexchanger.net/licenses/> then run pipeline for build project and fetch build on your server.
{% endhint %}
{% endtab %}

{% tab title="Source" %}

## 1. Подготовка окружения

После установки сервера к нему необходимо подключиться по SSH и настроить окружение

#### Установить пакеты сервера (nano git curl)

<pre class="language-bash"><code class="lang-bash">apt update
apt upgrade -y
<strong>apt-get install -y curl git nano wget sudo
</strong></code></pre>

#### Установить  Nginx:&#x20;

```bash
apt-get install -y nginx
```

#### Установить NodeJS:

{% content-ref url="/pages/Po9scEwrPiPdFfdk7zAR" %}
[Установка NodeJs](/dlya-razrabotchikov/ustanovka-proekta/ustanovka-po/ustanovka-nodejs.md)
{% endcontent-ref %}

## 2. Скачать ПО на сервер

#### Создаем SSH-ключ

Документация с github.com [Создание нового ключа SSH](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent)

Учебник по Linux

```bash
ssh-keygen -t rsa -b 4096
```

\> Enter x3

```bash
eval "$(ssh-agent -s)"
```

```bash
ssh-add ~/.ssh/id_rsa
```

Получить свой ключ:

```bash
cat ~/.ssh/id_rsa.pub
```

Скопируйте результат и установите данный ключ в своей учётной записи [git.boxexchanger.net](https://git.boxexchanger.net/-/profile/keys)&#x20;

{% content-ref url="/pages/lxzi4kPvGuwQJojMrdnE" %}
[Доступ к исходному коду](/dlya-razrabotchikov/dostup-k-iskhodnomu-kodu.md)
{% endcontent-ref %}

#### Клонируем репозитории

```bash
cd /var/www/
```

```bash
git clone git@ssh.boxexchanger.net:bx4/NAME_SPACE/exchanger-client-web.git
```

```bash
git clone git@ssh.boxexchanger.net:bx4/NAME_SPACE/exchanger-admin-web.git
```

## 3. Сборка админ панели

```bash
cd /var/www/exchanger-admin-web/
```

```bash
npm i
```

```bash
npm run configure
```

Сконфигурируйте конфигурацию:&#x20;

```bash
nano .env
```

```bash
ADMIN_BASE_URL="https://admin.domain.name"
EXCHANGE_URL="https://www.domain.name"
PROXY_REST_API="http://localhost:3010/"
```

Сборка проекта:

```bash
npm run generate
```

## 4. Сборка веб-панели

```bash
cd /var/www/exchanger-client-web/
```

```bash
npm i
```

```bash
npm run configure
```

Сконфигурируйте конфигурацию: (при возникновении затруднений обратитесь в техподдержку <support@boxexchanger.net>)

```bash
nano config/app.json
```

Сборка проекта:

```bash
npm run generate
```

## 5. Применяем Nginx конфигурацию

{% hint style="info" %}
Вам необходимо заменить&#x20;

* домен **domain.com**&#x20;
* админ домен: **admin.domain.com**
* IP адрес **API сервера**\
  при аренде он доступен в [личном кабинете](https://licence.boxexchanger.net/) пользователя\
  если у вас API находится на вашем сервере оставьте его `127.0.0.1`
  {% endhint %}

```bash
nano /etc/nginx/sites-enabled/domain.com.conf
```

{% code title="/etc/nginx/sites-enabled/domain.conf" lineNumbers="true" %}

```nginx
map $http_upgrade $connection_upgrade {
    default upgrade;
    ""      close;
}
server {
    listen 80;
    server_name domain.com;    return 301 https://www.domain.com$request_uri;
}
server {
    listen 80;
    server_name www.domain.com;
    root "/var/www/exchanger-client-web";
    gzip on;
    gzip_comp_level 9;
    gzip_disable "msie6";
    gzip_types application/javascript text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    index index.html;
    charset utf-8;

    add_header "X-Frame-Options" "SAMEORIGIN";
    add_header "X-XSS-Protection" "1; mode=block";
    add_header "X-Content-Type-Options" "nosniff";

    location / {
        root /var/www/exchanger-client-web/dist/client;
        rewrite ^([^.]*[^/])$ $1/ permanent;
        try_files $uri $uri/ /200.html;
        # expires 7d;
    }
    access_log off;
    error_log  /var/www/exchanger-client-web/nginx-error.log error;
    sendfile off;
    client_max_body_size 100m;


    location /service/ {
        proxy_pass http://127.0.0.1:3010/;
        proxy_http_version 1.1;
        add_header CF-IPCountry $http_cf_ipcountry always;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
    location /ref/ {
        proxy_pass http://nginx-api:3010/ref/;
        proxy_http_version 1.1;
        add_header CF-IPCountry $http_cf_ipcountry always;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }

    location /service/fs {
        alias /var/www/exchanger-api/public;
    }

    location /tg/ {
        proxy_pass http://127.0.0.1:3003/;
        proxy_http_version 1.1;
        add_header CF-IPCountry $http_cf_ipcountry always;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }
    #location /service/fs {
    #    alias /var/www/exchanger-api/public;
    #}
    location /ws/ {
        proxy_http_version 1.1;
        add_header CF-IPCountry $http_cf_ipcountry always;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://127.0.0.1:3011/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_redirect    off;
    }
}


server {
    listen 80;
    server_name admin.domain.com;
    root "/var/www/exchanger-admin-web";
    gzip on;
    gzip_comp_level 9;
    gzip_disable "msie6";
    gzip_types application/javascript text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    index index.html index.htm index.php;
    charset utf-8;

    add_header "X-Frame-Options" "DENY";
    add_header "X-XSS-Protection" "1; mode=block";
    add_header "X-Content-Type-Options" "nosniff";

    location / {
        root /var/www/exchanger-admin-web/dist/admin;
        try_files $uri $uri/ /index.html;
    }

    access_log off;
    error_log  /var/www/exchanger-admin-web/nginx-error.log error;
    sendfile off;
    client_max_body_size 100m;

    location /service/ {
        proxy_pass http://127.0.0.1:3010/;
        proxy_http_version 1.1;
        add_header CF-IPCountry $http_cf_ipcountry always;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_redirect off;
    }

    location /service/fs {
        alias /var/www/exchanger-api/public;
    }
}
```

{% endcode %}

Тестируем nginx конфигурацию:

```bash
nginx -t 
```

Применяем изменения:&#x20;

```bash
service nginx restart
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://manual.boxexchanger.net/dlya-razrabotchikov/ustanovka-proekta/ustanovka-po/ustanovka-exchanger-web.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
