Publicar geoserver en la raíz de un dominio

Por defecto cuando publicamos un servicio geoserver este estará escuchando en el puerto 8080 del servidor, pero además por el diseño de tomcat/jetty observaremos que cada URL de geoserver tiene por prefijo /geoserver. Esto no es ideal. Por ejemplo podríamos querer que nuestro servicio geoserver esté alojado en la raíz de un subdominio de nuestro dominio principal, por ejemplo en geoserver.example.com.

Se puede lograr esto haciendo uso de configuraciones astutas dentro de geoserver y en nginx, que estaré usando como proxy en este ejemplo.

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

   server_name geoserver.example.com;

   root /var/www/geoserver;

   location /.well-known/ {
   }

   location / {
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header Host $http_host;

       proxy_pass http://localhost:8080/geoserver/;
       proxy_cookie_path /geoserver /;
       proxy_redirect http://geoserver.example.com/geoserver/ /;
       proxy_redirect /geoserver/ /;
       proxy_redirect / /;
   }
}

En esta configuración destacan cosas muy simples como el directorio raíz y el nombre del servidor (dominio) donde hospedaremos geoserver. Pero lo realmente interesante está abajo en los bloques location.

Las primeras líneas del segundo bloque location establecen algunas cabeceras útiles para que el servicio subyacente (geoserver) entienda las peticiones que le llegan. Nada del otro mundo ahí.

El verdadero trabajo lo hace la directiva proxy_pass, que especifica que las peticiones que caigan en este bloque location deben ser transmitidas a esa dirección con URI. Resultando que si por ejemplo visitas la dirección http://example.com/index.html nginx la convierta en una petición a http://localhost:8080/geoserver/index.html.

Sin embargo geoserver (o quizá jetty/tomcat) muchas veces genera redirecciones tratando de forzar la presencia de /geoserver en la URI, para lo cual se utiliza la directiva proxy_redirect que indica que cada vez que exista una cabecera Location: URI devuelta por geoserver, nginx sustituirá el texto http://geoserver.example.com/geoserver/ por http://geoserver.example.com/ (yo usé una forma abreviada que da el mismo resultado). Dos otras apariciones de esta directiva aseguran respectivamente que si geoserver manda una redirección sin host (que lo hace) a esta se le quite la parte de /geoserver y que en todo caso cualquier redirección incluya el nombre del host.

Además de las redirecciones otra cosa que geoserver devuelve asociado al prefijo /geoserver son las cookies de sesión (cabecera Set-Cookie). Para eso es la directiva proxy_cookie_path que sustituye las apariciones de /geoserver por /.

El primer bloque location no es estrictamente necesario, pero ayuda en caso de utilizar certbot para obtener un certificado SSL, atrapando las peticiones que comiencen con .well-known y permitiendo la lógica de búsqueda de archivos normal de nginx.

Finalmente para que geoserver juegue bien con nginx es necesario ajustar la dirección del proxy en dos lugares:

En data_dir/global.xml como sigue:

<proxyBaseUrl>http://geoserver.example.com</proxyBaseUrl>

Y en webapps/geoserver/WEB-INF/web.xml como sigue:

<context-param>
  <param-name>PROXY_BASE_URL</param-name>
  <param-value>http://geoserver.example.com</param-value>
</context-param>

<context-param>
  <param-name>GEOSERVER_CSRF_WHITELIST</param-name>
  <param-value>geoserver.example.com</param-value>
</context-param>