Search code examples
elasticsearchdocker-composecors

Dockerized Elasticsearch with CORS support


I'm trying to set up a local Elasticsearch instance for development purposes. So, I started with a basic docker-compose.yml file:

services:

  elasticsearch:
    image: elasticsearch:8.7.1
    ports:
      - 9200:9200
    environment:
      discovery.type: single-node # Runs as a single-node
      ES_JAVA_OPTS: '-Xms256m -Xmx256m'
      network.bind_host: 0.0.0.0
      xpack.security.enabled: 'false'
    volumes: # Stores elasticsearch data locally on the esdata Docker volume
      - esdata:/usr/share/elasticsearch/data
    networks:
      - internal
      - elastic

# Define the Docker volume named esdata for the Elasticsearch container.
volumes:
  esdata:
# Networks to use
networks:
  elastic:
    external: true
  internal:
    driver: bridge

This works fine, in order to test a WordPress plugin that uses Elasticsearch. However, now I need to avoid CORS related errors, so I tried to add parameters to the environment:

  http.cors.enabled: 'true'
  http.cors.allow-origin: "*"
  http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE
  http.cors.allow-headers: X-Requested-With, X-Auth-Token, Content-Type, Content-Length, Authorization, Access-Control-Allow-Headers, Accept
  http.cors.allow-credentials: 'true'

This doesn't work. The Elasticsearch refuses connections after applying the changes.

So, what I need is to have minimal security but allowing at the same time CORS request from anywhere.

Your suggestions will be greatly appreciated.


Solution

  • You're getting CORS errors due to the fact that the Autosuggest feature of Elasticpress is a frontend concept, and the backend URL doesn't match that of the frontend.

    You really should be keeping your Elasticsearch Cluster completely private, and keep communications with it limited to network requests.

    That said, since Autosuggest requires the use of a public-facing endpoint, we've gotten around this by proxying an endpoint using NGINX in the following way:

    location /es-search {
        limit_except POST {
            deny all;
        }
        rewrite ^/es-search <desired-es-index-here>/_search break;
        proxy_set_header Host $host;
        # Only enable if you're using Authentication with your ES Cluster
        # proxy_set_header Authorization "Basic <Base64EncodedPasswordHere>";
        proxy_pass https://elasticsearch:9200; # Whatever your internal DNS name or IP address is for your ES Cluster goes here
    }
    

    By doing it this way, we expose an /es-search endpoint for public consumption, and allow the server to authenticate with Elasticsearch itself. This way, all requests become internal, and there won't be any need for monkeying around with your CORS settings.

    Feel free to use this as a launchpad and fill in your network details for anything between the angle brackets.