geonode icon indicating copy to clipboard operation
geonode copied to clipboard

How to install geonode the docker way +nginx reverse proxy?

Open fishfree opened this issue 2 years ago • 3 comments

There is already Nginx installed in my server, I can't uninstall it. So I want to install geonode with Docker, only reverse proxy to public with Nginx. This is my modifed docker-compose.yml:

version: '3.9'

# Common Django template for GeoNode and Celery services below
x-common-django:
  &default-common-django
  image: geonode/geonode:4.0
  restart: on-failure
  env_file:
    - .env
  volumes:
    # - '.:/usr/src/geonode'
    - /opt/geonode/statics:/mnt/volumes/statics
    - /opt/geonode/geoserver-data-dir:/geoserver_data/data
    - /opt/geonode/backup-restore:/backup_restore
    - /opt/geonode/data:/data
    - /opt/geonode/tmp:/tmp
  depends_on:
    db:
      condition: service_healthy
    geoserver:
      condition: service_healthy

services:

  # Our custom django application. It includes Geonode.
  django:
    << : *default-common-django
    build:
      context: ./
      dockerfile: Dockerfile
    container_name: django4${COMPOSE_PROJECT_NAME}
    healthcheck:
      test: "curl --fail --silent --write-out 'HTTP CODE : %{http_code}\n' --output /dev/null http://127.0.0.1:8000/"
      start_period: 60s
      interval: 60s
      timeout: 10s
      retries: 10
    environment:
      - IS_CELERY=False
    entrypoint: ["/usr/src/geonode/entrypoint.sh"]
    command: "uwsgi --ini /usr/src/geonode/uwsgi.ini"

  # Celery worker that executes celery tasks created by Django.
  celery:
    << : *default-common-django
    image: geonode/geonode:4.0
    container_name: celery4${COMPOSE_PROJECT_NAME}
    depends_on:
      - django
    environment:
      - IS_CELERY=True
    entrypoint: ["/usr/src/geonode/entrypoint.sh"]
    command: "celery-cmd"

  # Geoserver backend
  geoserver:
    image: geonode/geoserver:2.20.5
    container_name: geoserver4${COMPOSE_PROJECT_NAME}
    healthcheck:
      test: "curl --fail --silent --write-out 'HTTP CODE : %{http_code}\n' --output /dev/null http://127.0.0.1:8080/geoserver/rest/workspaces/geonode.html"
      start_period: 60s
      interval: 60s
      timeout: 10s
      retries: 10
    env_file:
      - .env
    volumes:
      - statics:/mnt/volumes/statics
      - geoserver-data-dir:/geoserver_data/data
      - backup-restore:/backup_restore
      - data:/data
      - tmp:/tmp
    restart: on-failure
    depends_on:
      db:
        condition: service_healthy
      data-dir-conf:
        condition: service_healthy

  data-dir-conf:
    image: geonode/geoserver_data:2.20.5
    container_name: gsconf4${COMPOSE_PROJECT_NAME}
    entrypoint: sleep infinity
    volumes:
      - geoserver-data-dir:/geoserver_data/data
    restart: on-failure
    healthcheck:
      test: "ls -A '/geoserver_data/data' | wc -l"

  # PostGIS database.
  db:
    # use geonode official postgis 13 image
    image: geonode/postgis:13
    command: postgres -c "max_connections=${POSTGRESQL_MAX_CONNECTIONS}"
    container_name: db4${COMPOSE_PROJECT_NAME}
    env_file:
      - .env
    volumes:
      - dbdata:/var/lib/postgresql/data
      - dbbackups:/pg_backups
    restart: on-failure
    healthcheck:
      test: "pg_isready -d gis"
    # uncomment to enable remote connections to postgres
    #ports:
    #  - "5432:5432"

  # Vanilla RabbitMQ service. This is needed by celery
  rabbitmq:
    image: rabbitmq:3.7-alpine
    container_name: rabbitmq4${COMPOSE_PROJECT_NAME}
    volumes:
      - rabbitmq:/var/lib/rabbitmq
    restart: on-failure

volumes:
  statics:
    name: ${COMPOSE_PROJECT_NAME}-statics
  geoserver-data-dir:
    name: ${COMPOSE_PROJECT_NAME}-gsdatadir
  dbdata:
    name: ${COMPOSE_PROJECT_NAME}-dbdata
  dbbackups:
    name: ${COMPOSE_PROJECT_NAME}-dbbackups
  backup-restore:
    name: ${COMPOSE_PROJECT_NAME}-backup-restore
  data:
    name: ${COMPOSE_PROJECT_NAME}-data
  tmp:
    name: ${COMPOSE_PROJECT_NAME}-tmp
  rabbitmq:
    name: ${COMPOSE_PROJECT_NAME}-rabbitmq

My nginx file like this.

fishfree avatar Aug 21 '22 08:08 fishfree

The nginx conf is using the internal dns names like django:8000. To proxy from your host nginx you need to make sure to expose the port to your host:

https://github.com/GeoNode/geonode/blob/a313150954b15a4a3c42e3800b8f19d0fc883d7b/docker-compose.yml#L26-L41

    ports:
      - "localhost:8000:8000"

and then instead of django set localhost

https://github.com/GeoNode/geonode/blob/a313150954b15a4a3c42e3800b8f19d0fc883d7b/scripts/docker/nginx/geonode.conf.envsubst#L116

set $upstream localhost:8000;

you need to do the same for other proxies like geoserver.

t-book avatar Aug 22 '22 07:08 t-book

If you do not want to play with port exposure and reverse proxy parameters, you can use this solution. It requires that you can connect your primary NGINX reverse proxy (the one you cannot uninstall) to a docker network.

  1. Disable port exposure for geonode's nginx4geonode service by commenting these lines. https://github.com/GeoNode/geonode/blob/a313150954b15a4a3c42e3800b8f19d0fc883d7b/docker-compose.yml#L67-L69
  2. Create an external network docker network create GEONODE_NETWORK https://docs.docker.com/engine/reference/commandline/network_create/
  3. Connect nginx4geonode to this network: docker network connect GEONODE_NETWORK nginx4geonode
  4. Change the *.conf setting file of the primary NGINX reverse proxy to redirect to nginx4geonode service (use nginx4geonode as domain name)
  5. Connect nginx4geonode to this network docker network connect GEONODE_NETWORK PRIMARY_NGINX_CONTAINER_NAME
  6. Restart your main primary proxy to reload config docker container restart PRIMARY_NGINX_CONTAINER_NAME

Inogeo avatar Aug 22 '22 07:08 Inogeo

@Inogeo @t-book Thank you very much! I tried a lot, however, still no luck. Would you pls share your working docker-compose.yml, .env and Nginx site conf?

fishfree avatar Aug 31 '22 00:08 fishfree

@fishfree

I managed to get it working with my traefik setup maybe it helps

networks:
  yourTraefikNetwork:
    external: true
    name: yourTraefikNetwork
    
geoserver:
    image: geonode/geoserver:2.20.5
    # ...
    labels:
      traefik.enable: true
      traefik.app.frontend.rule: Host:${HTTP_HOST};Path:/geoserver
      traefik.app.port: 8080 #internal port to be exposed on https://HTTP_HOST
      traefik.docker.network: yourTraefikNetwork
    networks:
      - yourTraefikNetwork
      - default # this is important, as all other containers that do not explicitly set networks will be part of the 'default' network

geonode:
    image: geonode/nginx:4.0
    # ...
    labels:
      traefik.enable: true
      traefik.app.frontend.rule: Host:${HTTP_HOST}
      traefik.app.port: 80 #internal port to be exposed on https://HTTP_HOST
      traefik.docker.network: yourTraefikNetwork
    networks:
      - yourTraefikNetwork
      - default # this is important, as all other containers that do not explicitly set networks will be part of the 'default' network

.env changes:

GEOSERVER_WEB_UI_LOCATION=https://your.domain.com/geoserver/
GEOSERVER_PUBLIC_LOCATION=https://your.domain.com/geoserver/
GEOSERVER_LOCATION=https://your.domain.com/geoserver/
GEONODE_LB_HOST_IP=your.domain.com
GEONODE_LB_PORT=80
PUBLIC_PORT=443 # this is important to enable login to the geoserver
HTTP_HOST=your.domain.com
HTTPS_HOST= # this is important (but a bit counter intuitive) as traefik is taking care of https so the internal nginx only serves on 80

gotjoshua avatar Oct 06 '22 09:10 gotjoshua