обратный прокси-сервер nginx с контейнерами docker и определенными вложенными расположениями

обратный прокси-сервер nginx с контейнерами docker и определенными вложенными расположениями

Я хотел бы настроить nginx как обратный прокси-сервер с несколькими приложениями в контейнерах Docker, постоянно размещенными в определенных местах, например:

https://sub.example.com/wiki
https://sub.example.com/app1
https://sub.example.com/app2

В частности, я хочу использоватьизображение докера mediawikiрядом с другими приложениями. Это мой docker-compose.yml:

version: '3.5'
services:

  mediawiki:
    image: mediawiki
    restart: unless-stopped
    hostname: mediawiki
    ports:
      - "8080:80"
    links:
      - database
    volumes:
      - images:/var/www/html/images
      # - ./wiki/LocalSettings.php:/var/www/html/LocalSettings.php
    networks:
      - wiki
  
  database:
    image: mariadb
    restart: unless-stopped
    hostname: database
    environment:
      MYSQL_DATABASE: my_wiki
      MYSQL_USER: wikiuser
      MYSQL_PASSWORD: example
      MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
    volumes:
      - db:/var/lib/mysql
    networks:
      - wiki

  app1:
    # ...
    expose:
      - "4000"
    networks:
      - apps

  nginx:
    image: nginx:1.23-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./certbot/conf:/etc/nginx/ssl
      - ./certbot/data:/usr/share/nginx/html/letsencrypt
    depends_on:
      - app1
      - mediawiki
    networks:
      - apps
      - wiki

  certbot:
    image: certbot/certbot:latest
    # ...
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/logs:/var/log/letsencrypt
      - ./certbot/data:/usr/share/nginx/html/letsencrypt
    networks:
      - apps
      - wiki

networks:
  apps:
  wiki:

Проблема, с которой я столкнулся, заключается в том default.conf, что с помощью следующего я могу проксировать контейнер MediaWiki, а также другие приложения, но некоторые ссылки и ресурсы возвращают ошибку 404.

upstream testwiki {
    server mediawiki:80;
}

server {
    listen 80;
    listen [::]:80;

    server_name sub.example.com;

    location / {
        return 301 https://$server_name$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    
    server_name sub.example.com;

    ssl_certificate /etc/nginx/ssl/live/sub.example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/sub.example.com/privkey.pem;

    location /wiki/ {
        proxy_pass http://testwiki/;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }
}

Я подозреваю, что причина такого поведения кроется в реляционных URL, таких как <a href="/mw-config/index.php">complete the installation</a>, направляющих запросы в корневое местоположение вместо вложенного. Я перепробовал много вещей, таких как rewrite(включая regex), sub_filter, proxy_redirectи proxy_set_headerметоды, но лучшее, что я придумал, это:

location /wiki/ {
    proxy_pass http://mediawiki:80/;
    proxy_set_header   Host $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Host $server_name;
}

location /app1/ {
    proxy_pass http://app1:4000/;
    proxy_set_header   Host $host;
    proxy_set_header   X-Real-IP $remote_addr;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Host $server_name;
}


if ($http_referer = "https://sub.example.com/wiki/") {
    set $proxypass http://mediawiki:80;
}
if ($http_referer = "https://sub.example.com/app1/") {
    set $proxypass http://app1:4000;
}
    
location / {
    proxy_pass $proxypass;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Поскольку я не могу настроить baseurl для mediawiki (пока), я попытался проксировать входящие запросы в корневом расположении в зависимости от http_referer. Это работает для всех начальных запросов GET, сделанных в , https://sub.example.com/wiki/а также для ссылки, упомянутой выше.

Однако после нажатия <a href="/mw-config/index.php">..., index.phpделает дальнейшие запросы - снова направленные на https://sub.example.com/. Поскольку URL не перезаписывается и реферер говорит https://sub.example.com/mw-config/index.php, эти запросы возвращают 500.

Мой вопрос: как исправить это поведение, чтобы мои приложения постоянно находились в соответствующем месте? К сожалению, на данный момент я не могу изменить поддомен.

Любая помощь приветствуется!

Редактировать:


Поскольку я хочу использовать несколько других приложений, которые могут столкнуться с похожими проблемами, я хотел бы предложить более общее решение. В некоторых случаях у меня нет контроля над базовым URL.

решение1

Здесь есть несколько вещей, по которым нам нужно прийти к единому мнению, чтобы это сработало:

  1. NGINXконфигурация: маршрутизация на основе пути, обратный прокси-сервер
    • Я попробовал вашу конфигурацию, иЯ считаю, что ваша конфигурация правильная.
  2. Apache2конфигурация: правильно сопоставлять URI с путями к файлам и скриптами
    • Используйте директиву AliasMatch "^/wiki(.*)" "/var/www/html/$1"для правильного удаления /wikiи сопоставления с внутренними путями файлов
  3. МедиаВикинастройки: добавьте /wikiпуть, чтобы Nginxзнать, куда следует перенаправлять ссылки через прокси-сервер, а затем Apache2можно удалить /wikiи использовать правильные внутренние пути к файлам.
    • Установите $wgScriptPath = "/wiki";файл LocalSettings.php, созданный после запуска установки MediaWiki, и переопределите этот файл в вашемdocker-compose.yml
  4. Docker-композитор: Сохраните эти изменения, смонтировав наши измененные локальные файлы в mediawikiконтейнер Docker.

Apache2

Мы собираемся добавить AliasMatch "^/wiki(.*)" "/var/www/html/$1"в конфигурацию в /etc/apache2/sites-enabled/000-default.conf. Вам также нужно будет переопределить содержимое этого файла в вашемdocker-compose.yml

#/etc/apache2/sites-enabled/000-default.conf 
<VirtualHost *:80>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        #ServerName www.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        AliasMatch "^/wiki(.*)" "/var/www/html/$1"

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
        AllowEncodedSlashes NoDecode
</VirtualHost>

Настройки MediaWiki:

Это всего лишь фрагмент файла LocalSettings.php, который нужно изменить. Он немного великоват, чтобы включать здесь все значение по умолчанию. Похоже, у вас уже есть локальная копия, LocalSettings.phpкоторую вы монтируете в контейнер docker с помощью docker-compose, поэтому просто измените $wgScriptPathтам переменную и перезапустите контейнер.

## The URL base path to the directory containing the wiki;
## defaults for all runtime URL paths are based off of this.
## For more information on customizing the URLs
## (like /w/index.php/Page_title to /wiki/Page_title) please see:
## https://www.mediawiki.org/wiki/Manual:Short_URL
$wgScriptPath = "/wiki";

Docker-композитор

Сейчасмы изменим раздел томовчасти MediaWiki docker-compose.yml впереопределить конфигурацию apache2файл для сайта MediaWiki.

  mediawiki:
    image: mediawiki
    restart: unless-stopped
    hostname: mediawiki
    ports:
      - "8080:80"
    links:
      - database
    volumes:
      - ./images:/var/www/html/images
      - ./wiki/LocalSettings.php:/var/www/html/LocalSettings.php
      - ./apache2/000-default.conf:/etc/apache2/sites-enabled/000-default.conf
    networks:
      - wiki

решение2

Единственным стабильным решением этой проблемы является установка корневого URL-адреса.

Я искал «корневой URL mediawiki», и второе совпадение указало наhttps://www.mediawiki.org/wiki/Тема:Ry90289pdqa86yrd, где первый ответ рассказывает, как установить корневой URL в MediaWiki:

URL вашей вики должен быть установлен в LocalSettings.php (как, например, $wgLogo, который также установлен в этом файле), и вы можете изменить его, установив $wgServer на другое значение. Это заставит MediaWiki выводить URL, начинающиеся с нужного вам домена.

Связанный контент