Proxy inverso nginx con contenedores acoplables y ubicaciones anidadas específicas

Proxy inverso nginx con contenedores acoplables y ubicaciones anidadas específicas

Me gustaría configurar nginx como un proxy inverso con múltiples aplicaciones en contenedores acoplables que residen permanentemente en ubicaciones específicas, por ejemplo:

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

En particular, quiero usar elimagen acoplable de mediawikijunto a otras aplicaciones. Este es mi 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:

El problema al que me enfrento es que con lo siguiente default.conf, puedo hacer proxy del contenedor mediawiki y de otras aplicaciones, pero ciertos enlaces y recursos devuelven 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;
    }
}

Sospecho que el motivo de este comportamiento se debe a que las URL relacionales, como <a href="/mw-config/index.php">complete the installation</a>, dirigen las solicitudes a la ubicación raíz en lugar de a la anidada. He probado muchas cosas, como rewrite(incluidas expresiones regulares), sub_filtery proxy_redirectmétodos proxy_set_header, pero lo mejor que se me ocurrió es:

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;
}

Como no puedo configurar una URL base para mediawiki (todavía), intenté enviar solicitudes entrantes en la ubicación raíz dependiendo del archivo http_referer. Esto funciona para todas las solicitudes GET iniciales realizadas en https://sub.example.com/wiki/y también para el enlace mencionado anteriormente.

Sin embargo, después de hacer clic en <a href="/mw-config/index.php">..., index.phprealiza más solicitudes, nuevamente dirigidas a https://sub.example.com/. Dado que la URL no se reescribe y el referente dice https://sub.example.com/mw-config/index.php, estas solicitudes devuelven 500.

Mi pregunta es: ¿Cómo puedo solucionar este comportamiento para que mis aplicaciones residan permanentemente en su ubicación respectiva? Lamentablemente no puedo cambiar el subdominio en este momento.

¡Cualquier ayuda es apreciada!

Editar:


Como quiero utilizar muchas otras aplicaciones que pueden encontrar problemas similares, me gustaría encontrar una solución más general. En algunos casos no tengo control sobre la URL base.

Respuesta1

Aquí suceden algunas cosas que debemos coordinar para que esto funcione:

  1. NGINXconfiguración: enrutamiento basado en ruta, proxy inverso
    • Probé tu configuración yCreo que tu configuración es correcta.
  2. apache2configuración: asigne correctamente URI a rutas de archivos y scripts
    • Utilice una directiva AliasMatch "^/wiki(.*)" "/var/www/html/$1"para eliminar /wikiy asignar correctamente las rutas de archivos internas
  3. MediosWikiconfiguración: agregue la /wikiruta para Nginxsaber dónde invertir el proxy de los enlaces y luego Apache2pueda eliminarlos /wikiy usar las rutas de archivos internas correctas.
    • Establezca $wgScriptPath = "/wiki";el LocalSettings.phparchivo creado después de ejecutar la configuración de MediaWiki y anule ese archivo en sudocker-compose.yml
  4. Composición acoplable: persista esos cambios montando nuestros archivos locales modificados en el mediawikicontenedor acoplable

apache2

Vamos a agregar AliasMatch "^/wiki(.*)" "/var/www/html/$1"a la configuración en /etc/apache2/sites-enabled/000-default.conf. También necesitarás anular el contenido de este archivo en tudocker-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>

Configuración de MediaWiki:

Este es sólo un fragmento del LocalSettings.phparchivo que debe modificarse. Es un poco grande incluir todo el valor predeterminado aquí. Parece que ya tiene una copia local LocalSettings.phpque está montando en el contenedor de la ventana acoplable usando docker-compose, así que simplemente modifique la $wgScriptPathvariable allí y reinicie su contenedor.

## 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";

Composición acoplable

AhoraModificaremos la sección de volúmenes.de la pieza de MediaWiki de docker-compose.yml paraanular la configuración de apache2archivo para el sitio 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

Respuesta2

Configurar la URL raíz es la única solución estable a este problema.

Busqué "URL raíz de mediawiki" y el segundo resultado señalóhttps://www.mediawiki.org/wiki/Topic:Ry90289pdqa86yrd, donde la primera respuesta indica cómo configurar la URL raíz en MediaWiki:

La URL de su wiki debe estar configurada en LocalSettings.php (al igual que, por ejemplo, $wgLogo, que también está configurada en ese archivo) y puede cambiarla configurando $wgServer con otro valor. Esto hará que MediaWiki genere URL que comiencen con el dominio que desea.

información relacionada