diff --git a/docker/geoserver/Dockerfile b/docker/geoserver/Dockerfile index 9545a00..c2bed83 100644 --- a/docker/geoserver/Dockerfile +++ b/docker/geoserver/Dockerfile @@ -1,33 +1,55 @@ ARG IMAGE_VERSION=9.0.90-jdk11-temurin-focal -ARG JAVA_HOME=/usr/local/openjdk-11 + FROM tomcat:$IMAGE_VERSION -LABEL GeoNode Development Team ARG GEOSERVER_VERSION=2.24.x -ARG GEOSERVER_CORS_ENABLED=False -ARG GEOSERVER_CORS_ALLOWED_ORIGINS=* -ARG GEOSERVER_CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,HEAD,OPTIONS -ARG GEOSERVER_CORS_ALLOWED_HEADERS=* +ARG GEONODE_LOG_DIR=/var/log/geonode + +# Some label best practices +# https://www.docker.com/blog/docker-best-practices-using-tags-and-labels-to-manage-docker-image-sprawl/ +LABEL org.opencontainers.image.title="GeoNode's Geoserver image" \ + org.opencontainers.image.version=${GEOSERVER_VERSION} \ + org.opencontainers.image.vendor="GeoNode Development Team" + # # Set GeoServer version and data directory # -ENV GEOSERVER_VERSION=${GEOSERVER_VERSION} -ENV GEOSERVER_DATA_DIR="/geoserver_data/data" -ENV GEOSERVER_CORS_ENABLED=$GEOSERVER_CORS_ENABLED -ENV GEOSERVER_CORS_ALLOWED_ORIGINS=$GEOSERVER_CORS_ALLOWED_ORIGINS -ENV GEOSERVER_CORS_ALLOWED_METHODS=$GEOSERVER_CORS_ALLOWED_METHODS -ENV GEOSERVER_CORS_ALLOWED_HEADERS=$GEOSERVER_CORS_ALLOWED_HEADERS +ENV GEOSERVER_VERSION=${GEOSERVER_VERSION} \ + GEOSERVER_DATA_DIR="/geoserver_data/data" \ + GEONODE_LOG_DIR=${GEONODE_LOG_DIR} \ + GEOSERVER_CORS_ENABLED=false \ + GEOSERVER_CORS_ALLOWED_ORIGINS="*" \ + GEOSERVER_CORS_ALLOWED_METHODS="GET,POST,PUT,DELETE,HEAD,OPTIONS" \ + GEOSERVER_CORS_ALLOWED_HEADERS="*" \ + FORCE_REINIT=false \ + INVOKE_LOG_STDOUT=true \ + CATALINA_OPTS="-Djava.awt.headless=true -Dgwc.context.suffix=gwc -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=${GEONODE_LOG_DIR}/jvm.log -XX:MaxPermSize=512m -XX:PermSize=256m -Xms512m -Xmx2048m -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGS-SHAPEFILE-CHARSET=UTF-8 -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://geoserver:8080/geoserver/pdf -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine" + +# +# Install required packages (no need to use curl and wget) +# +RUN apt-get update -y && \ + apt-get install -y --no-install-recommends --no-install-suggests \ + curl \ + # wget \ + unzip \ + procps \ + less \ + python3-minimal \ + python3-pip && \ + apt-get autoremove && \ + rm -rf /var/lib/apt/lists/* && \ + pip install --no-cache-dir j2cli invoke==2.2.0 requests==2.31.0 + # # Download and install GeoServer # -RUN apt-get update -y && apt-get install curl wget unzip -y -RUN cd /usr/local/tomcat/webapps \ - && wget --no-check-certificate --progress=bar:force:noscroll https://artifacts.geonode.org/geoserver/${GEOSERVER_VERSION}/geoserver.war -O geoserver.war \ - && unzip -q geoserver.war -d geoserver \ - && rm geoserver.war \ - && mkdir -p $GEOSERVER_DATA_DIR +WORKDIR /usr/local/tomcat/webapps -VOLUME $GEOSERVER_DATA_DIR +RUN curl --fail --silent --show-error --location --output geoserver.war \ + https://artifacts.geonode.org/geoserver/${GEOSERVER_VERSION}/geoserver.war && \ + unzip -q geoserver.war -d geoserver && \ + rm geoserver.war # no longer used since 2.24.2 #ENV GEOSERVER_LIB_DIR="/usr/local/tomcat/webapps/geoserver/WEB-INF/lib" @@ -37,28 +59,28 @@ VOLUME $GEOSERVER_DATA_DIR # mv hibernate-spatial-postgis-1.1.3.2.jar $GEOSERVER_LIB_DIR && \ # mv postgis-jdbc-1.3.3.jar $GEOSERVER_LIB_DIR - # copy the script and perform the run of scripts from entrypoint.sh -RUN mkdir -p /usr/local/tomcat/tmp WORKDIR /usr/local/tomcat/tmp -COPY set_geoserver_auth.sh \ - entrypoint.sh \ - tasks.py \ - multidump.sh \ - multidump-alt.sh \ + +COPY set_geoserver_auth.sh entrypoint.sh tasks.py multidump.sh multidump-alt.sh \ /usr/local/tomcat/tmp/ COPY ./templates /templates -RUN chmod +x \ - /usr/local/tomcat/tmp/set_geoserver_auth.sh \ - /usr/local/tomcat/tmp/entrypoint.sh - -RUN apt-get install -y procps less && \ - apt-get install -y python3 python3-pip python3-dev +# create the data and logs directory and set permissions +RUN mkdir -p ${GEOSERVER_DATA_DIR} ${GEONODE_LOG_DIR} ${CATALINA_HOME}/conf/Catalina/localhost && \ + chmod +x set_geoserver_auth.sh entrypoint.sh && \ + cp ${CATALINA_HOME}/conf/catalina.properties ${CATALINA_HOME}/conf/catalina.properties.orig && \ + cp ${CATALINA_HOME}/webapps/geoserver/WEB-INF/web.xml ${CATALINA_HOME}/webapps/geoserver/WEB-INF/web.xml.orig && \ + chmod -R g=u \ + ${GEOSERVER_DATA_DIR} \ + ${GEONODE_LOG_DIR} \ + ${CATALINA_HOME}/conf/Catalina/localhost \ + ${CATALINA_HOME}/conf/catalina.properties \ + ${CATALINA_HOME}/webapps/geoserver/WEB-INF/web.xml -RUN pip install j2cli invoke==2.2.0 requests==2.31.0 +VOLUME ${GEOSERVER_DATA_DIR} -ENV JAVA_OPTS="-Djava.awt.headless=true -Dgwc.context.suffix=gwc -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=/var/log/jvm.log -XX:MaxPermSize=512m -XX:PermSize=256m -Xms512m -Xmx2048m -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=4 -Dfile.encoding=UTF8 -Djavax.servlet.request.encoding=UTF-8 -Djavax.servlet.response.encoding=UTF-8 -Duser.timezone=GMT -Dorg.geotools.shapefile.datetime=false -DGS-SHAPEFILE-CHARSET=UTF-8 -DGEOSERVER_CSRF_DISABLED=true -DPRINT_BASE_URL=http://geoserver:8080/geoserver/pdf -Xbootclasspath/a:/usr/local/tomcat/webapps/geoserver/WEB-INF/lib/marlin-0.9.3.jar -Dsun.java2d.renderer=org.marlin.pisces.MarlinRenderingEngine" +ENTRYPOINT [ "/usr/local/tomcat/tmp/entrypoint.sh" ] -CMD ["/usr/local/tomcat/tmp/entrypoint.sh"] +CMD [ "catalina.sh", "run"] diff --git a/docker/geoserver/docker-compose-dev.yml b/docker/geoserver/docker-compose-dev.yml new file mode 100644 index 0000000..83b1b06 --- /dev/null +++ b/docker/geoserver/docker-compose-dev.yml @@ -0,0 +1,10 @@ +version: '3.9' + +services: + geoserver: + image: geonode/geoserver:dev + data-dir-conf: + image: geonode/geoserver_data:dev + postgis: + ports: + - "5432:5432" \ No newline at end of file diff --git a/docker/geoserver/docker-compose.yml b/docker/geoserver/docker-compose.yml index f981603..5f0bead 100644 --- a/docker/geoserver/docker-compose.yml +++ b/docker/geoserver/docker-compose.yml @@ -1,15 +1,12 @@ version: '3.9' services: - postgis: - image: geonode/postgis:13 - ports: - - "25432:5432" + image: geonode/postgis:15.3-latest + environment: + POSTGRES_PASSWORD: postgres volumes: - - /srv/docker/geoserver/postgis:/var/lib/postgresql - #volumes_from: - #- pgstore + - pgdata:/var/lib/postgresql/data healthcheck: test: "pg_isready -d postgres -U postgres" restart: on-failure @@ -18,36 +15,50 @@ services: image: geonode/geoserver:2.24.x build: context: . + args: + GEOSERVER_VERSION: 2.24.x links: - postgis ports: - "8080:8080" volumes: - - /geoserver_data/data + - data:/geoserver_data/data environment: - - NGINX_BASE_URL=http://localhost + NGINX_BASE_URL: http://localhost + # GEOSERVER_CORS_ENABLED: true + # GEOSERVER_CORS_ALLOWED_ORIGINS: localhost + # GEOSERVER_CORS_ALLOWED_METHODS: GET,POST,PUT,DELETE,HEAD,OPTIONS + # GEOSERVER_CORS_ALLOWED_HEADERS: "*" + # INVOKE_LOG_STDOUT: false + # FORCE_REINIT: true depends_on: postgis: - condition: service_completed_successfully + condition: service_healthy data-dir-conf: condition: service_healthy + user: '1000' healthcheck: - test: curl --fail -s http://localhost:8080/geoserver/rest/workspaces/geonode.html || exit 1 - interval: 1m30s + # geoserver can't test with rest, because it needs authorization. + test: curl --fail -s http://localhost:8080/geoserver/index.html || exit 1 + interval: 30s timeout: 10s retries: 3 restart: on-failure data-dir-conf: image: geonode/geoserver_data:2.24.x - container_name: geoserver_data_dir # named data container - entrypoint: sleep infinity + build: + context: ../geoserver_data + args: + GEOSERVER_VERSION: 2.24.x + command: ["sleep", "infinity"] volumes: - - /geoserver_data/data + - data:/geoserver_data/data healthcheck: test: "ls -A '/geoserver_data/data' | wc -l" restart: on-failure volumes: # reference to the named data container that holds the preloaded geoserver data directory - geoserver_data_dir: + data: + pgdata: diff --git a/docker/geoserver/entrypoint.sh b/docker/geoserver/entrypoint.sh index e7d395f..305ff3a 100644 --- a/docker/geoserver/entrypoint.sh +++ b/docker/geoserver/entrypoint.sh @@ -1,58 +1,88 @@ #!/bin/bash set -e -source /root/.bashrc +# check if user exists in passwd file +# if not, change HOME to /tmp +HAS_USER=$(getent passwd $(id -u) | wc -l) +if [ $HAS_USER -eq 1 ]; then + echo "User $_USER exists in passwd file" + + if [ $HOME = "/" ]; then + echo "HOME is /, changing to /tmp" + export HOME=/tmp + fi +else + echo "User does not exist in passwd file, changing HOME to /tmp" + export HOME=/tmp +fi +unset HAS_USER + +# Preserving the original behavior. +if [ ! -e $HOME/.bashrc ]; then + echo "No $HOME/.bashrc found, getting default from skeleton" + cp /etc/skel/.bashrc $HOME/.bashrc +fi + +source $HOME/.bashrc +# Parse bools +parse_bool () { + case $1 in + [Tt][Rr][Uu][Ee]|[Yy][Ee][Ss]|[Oo][Nn]|1) echo 'true';; + *) echo 'false';; + esac +} -INVOKE_LOG_STDOUT=${INVOKE_LOG_STDOUT:-TRUE} invoke () { - if [ $INVOKE_LOG_STDOUT = 'true' ] || [ $INVOKE_LOG_STDOUT = 'True' ] + if [ $(parse_bool $INVOKE_LOG_STDOUT) = 'true' ] then /usr/local/bin/invoke $@ else - /usr/local/bin/invoke $@ > /usr/src/geonode/invoke.log 2>&1 + /usr/local/bin/invoke $@ > ${GEONODE_LOG_DIR}/invoke.log 2>&1 fi echo "$@ tasks done" } # control the values of LB settings if present +OVERRIDE_ENV=$HOME/.override_env + if [ -n "$GEONODE_LB_HOST_IP" ]; then echo "GEONODE_LB_HOST_IP is defined and not empty with the value '$GEONODE_LB_HOST_IP' " - echo export GEONODE_LB_HOST_IP=${GEONODE_LB_HOST_IP} >> /root/.override_env + echo export GEONODE_LB_HOST_IP=${GEONODE_LB_HOST_IP} >> $OVERRIDE_ENV else echo "GEONODE_LB_HOST_IP is either not defined or empty setting the value to 'django' " - echo export GEONODE_LB_HOST_IP=django >> /root/.override_env + echo export GEONODE_LB_HOST_IP=django >> $OVERRIDE_ENV export GEONODE_LB_HOST_IP=django fi if [ -n "$GEONODE_LB_PORT" ]; then echo "GEONODE_LB_HOST_IP is defined and not empty with the value '$GEONODE_LB_PORT' " - echo export GEONODE_LB_PORT=${GEONODE_LB_PORT} >> /root/.override_env + echo export GEONODE_LB_PORT=${GEONODE_LB_PORT} >> $OVERRIDE_ENV else echo "GEONODE_LB_PORT is either not defined or empty setting the value to '8000' " - echo export GEONODE_LB_PORT=8000 >> /root/.override_env + echo export GEONODE_LB_PORT=8000 >> $OVERRIDE_ENV export GEONODE_LB_PORT=8000 fi if [ -n "$GEOSERVER_LB_HOST_IP" ]; then echo "GEOSERVER_LB_HOST_IP is defined and not empty with the value '$GEOSERVER_LB_HOST_IP' " - echo export GEOSERVER_LB_HOST_IP=${GEOSERVER_LB_HOST_IP} >> /root/.override_env + echo export GEOSERVER_LB_HOST_IP=${GEOSERVER_LB_HOST_IP} >> $OVERRIDE_ENV else echo "GEOSERVER_LB_HOST_IP is either not defined or empty setting the value to 'geoserver' " - echo export GEOSERVER_LB_HOST_IP=geoserver >> /root/.override_env + echo export GEOSERVER_LB_HOST_IP=geoserver >> $OVERRIDE_ENV export GEOSERVER_LB_HOST_IP=geoserver fi if [ -n "$GEOSERVER_LB_PORT" ]; then echo "GEOSERVER_LB_PORT is defined and not empty with the value '$GEOSERVER_LB_PORT' " - echo export GEOSERVER_LB_PORT=${GEOSERVER_LB_PORT} >> /root/.override_env + echo export GEOSERVER_LB_PORT=${GEOSERVER_LB_PORT} >> $OVERRIDE_ENV else echo "GEOSERVER_LB_PORT is either not defined or empty setting the value to '8000' " - echo export GEOSERVER_LB_PORT=8080 >> /root/.override_env + echo export GEOSERVER_LB_PORT=8080 >> $OVERRIDE_ENV export GEOSERVER_LB_PORT=8080 fi @@ -60,10 +90,10 @@ fi if [ -n "$DATABASE_HOST" ]; then echo "DATABASE_HOST is defined and not empty with the value '$DATABASE_HOST' " - echo export DATABASE_HOST=${DATABASE_HOST} >> /root/.override_env + echo export DATABASE_HOST=${DATABASE_HOST} >> $OVERRIDE_ENV else echo "DATABASE_HOST is either not defined or empty setting the value to 'db' " - echo export DATABASE_HOST=db >> /root/.override_env + echo export DATABASE_HOST=db >> $OVERRIDE_ENV export DATABASE_HOST=db fi @@ -71,10 +101,10 @@ fi if [ -n "$DATABASE_PORT" ]; then echo "DATABASE_PORT is defined and not empty with the value '$DATABASE_PORT' " - echo export DATABASE_HOST=${DATABASE_PORT} >> /root/.override_env + echo export DATABASE_HOST=${DATABASE_PORT} >> $OVERRIDE_ENV else echo "DATABASE_PORT is either not defined or empty setting the value to '5432' " - echo export DATABASE_PORT=5432 >> /root/.override_env + echo export DATABASE_PORT=5432 >> $OVERRIDE_ENV export DATABASE_PORT=5432 fi @@ -82,10 +112,10 @@ fi if [ -n "$GEONODE_GEODATABASE" ]; then echo "GEONODE_GEODATABASE is defined and not empty with the value '$GEONODE_GEODATABASE' " - echo export GEONODE_GEODATABASE=${GEONODE_GEODATABASE} >> /root/.override_env + echo export GEONODE_GEODATABASE=${GEONODE_GEODATABASE} >> $OVERRIDE_ENV else echo "GEONODE_GEODATABASE is either not defined or empty setting the value '${COMPOSE_PROJECT_NAME}_data' " - echo export GEONODE_GEODATABASE=${COMPOSE_PROJECT_NAME}_data >> /root/.override_env + echo export GEONODE_GEODATABASE=${COMPOSE_PROJECT_NAME}_data >> $OVERRIDE_ENV export GEONODE_GEODATABASE=${COMPOSE_PROJECT_NAME}_data fi @@ -93,10 +123,10 @@ fi if [ -n "$GEONODE_GEODATABASE_USER" ]; then echo "GEONODE_GEODATABASE_USER is defined and not empty with the value '$GEONODE_GEODATABASE_USER' " - echo export GEONODE_GEODATABASE_USER=${GEONODE_GEODATABASE_USER} >> /root/.override_env + echo export GEONODE_GEODATABASE_USER=${GEONODE_GEODATABASE_USER} >> $OVERRIDE_ENV else echo "GEONODE_GEODATABASE_USER is either not defined or empty setting the value '$GEONODE_GEODATABASE' " - echo export GEONODE_GEODATABASE_USER=${GEONODE_GEODATABASE} >> /root/.override_env + echo export GEONODE_GEODATABASE_USER=${GEONODE_GEODATABASE} >> $OVERRIDE_ENV export GEONODE_GEODATABASE_USER=${GEONODE_GEODATABASE} fi @@ -104,10 +134,10 @@ fi if [ -n "$GEONODE_GEODATABASE_PASSWORD" ]; then echo "GEONODE_GEODATABASE_PASSWORD is defined and not empty with the value '$GEONODE_GEODATABASE_PASSWORD' " - echo export GEONODE_GEODATABASE_PASSWORD=${GEONODE_GEODATABASE_PASSWORD} >> /root/.override_env + echo export GEONODE_GEODATABASE_PASSWORD=${GEONODE_GEODATABASE_PASSWORD} >> $OVERRIDE_ENV else echo "GEONODE_GEODATABASE_PASSWORD is either not defined or empty setting the value '${GEONODE_GEODATABASE}' " - echo export GEONODE_GEODATABASE_PASSWORD=${GEONODE_GEODATABASE} >> /root/.override_env + echo export GEONODE_GEODATABASE_PASSWORD=${GEONODE_GEODATABASE} >> $OVERRIDE_ENV export GEONODE_GEODATABASE_PASSWORD=${GEONODE_GEODATABASE} fi @@ -115,40 +145,41 @@ fi if [ -n "$GEONODE_GEODATABASE_SCHEMA" ]; then echo "GEONODE_GEODATABASE_SCHEMA is defined and not empty with the value '$GEONODE_GEODATABASE_SCHEMA' " - echo export GEONODE_GEODATABASE_SCHEMA=${GEONODE_GEODATABASE_SCHEMA} >> /root/.override_env + echo export GEONODE_GEODATABASE_SCHEMA=${GEONODE_GEODATABASE_SCHEMA} >> $OVERRIDE_ENV else echo "GEONODE_GEODATABASE_SCHEMA is either not defined or empty setting the value to 'public'" - echo export GEONODE_GEODATABASE_SCHEMA=public >> /root/.override_env + echo export GEONODE_GEODATABASE_SCHEMA=public >> $OVERRIDE_ENV export GEONODE_GEODATABASE_SCHEMA=public fi -if [ ! -z "${GEOSERVER_JAVA_OPTS}" ] -then - echo "GEOSERVER_JAVA_OPTS is filled so I replace the value of '$JAVA_OPTS' with '$GEOSERVER_JAVA_OPTS'" - export JAVA_OPTS=${GEOSERVER_JAVA_OPTS} -fi +# No need of this, because we only need to set CATALINA_OPTS to modify tomcat's behavior. +# if [ ! -z "${GEOSERVER_JAVA_OPTS}" ] +# then +# echo "GEOSERVER_JAVA_OPTS is filled so I replace the value of '$JAVA_OPTS' with '$GEOSERVER_JAVA_OPTS'" +# export JAVA_OPTS=${GEOSERVER_JAVA_OPTS} +# fi # control the value of NGINX_BASE_URL variable if [ -z `echo ${NGINX_BASE_URL} | sed 's/http:\/\/\([^:]*\).*/\1/'` ] then echo "NGINX_BASE_URL is empty so I'll use the default Geoserver base url" echo "Setting GEOSERVER_LOCATION='${SITEURL}'" - echo export GEOSERVER_LOCATION=${SITEURL} >> /root/.override_env + echo export GEOSERVER_LOCATION=${SITEURL} >> $OVERRIDE_ENV else echo "NGINX_BASE_URL is filled so GEOSERVER_LOCATION='${NGINX_BASE_URL}'" echo "Setting GEOSERVER_LOCATION='${NGINX_BASE_URL}'" - echo export GEOSERVER_LOCATION=${NGINX_BASE_URL} >> /root/.override_env + echo export GEOSERVER_LOCATION=${NGINX_BASE_URL} >> $OVERRIDE_ENV fi if [ -n "$SUBSTITUTION_URL" ]; then echo "SUBSTITUTION_URL is defined and not empty with the value '$SUBSTITUTION_URL'" echo "Setting GEONODE_LOCATION='${SUBSTITUTION_URL}' " - echo export GEONODE_LOCATION=${SUBSTITUTION_URL} >> /root/.override_env + echo export GEONODE_LOCATION=${SUBSTITUTION_URL} >> $OVERRIDE_ENV else echo "SUBSTITUTION_URL is either not defined or empty so I'll use the default GeoNode location " echo "Setting GEONODE_LOCATION='http://${GEONODE_LB_HOST_IP}:${GEONODE_LB_PORT}' " - echo export GEONODE_LOCATION=http://${GEONODE_LB_HOST_IP}:${GEONODE_LB_PORT} >> /root/.override_env + echo export GEONODE_LOCATION=http://${GEONODE_LB_HOST_IP}:${GEONODE_LB_PORT} >> $OVERRIDE_ENV fi # set basic tagname @@ -156,18 +187,18 @@ TAGNAME=( "baseUrl" "authApiKey" ) if ! [ -f ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ] then - echo "Configuration file '$GEOSERVER_DATA_DIR'/security/auth/geonodeAuthProvider/config.xml is not available so it is gone to skip " + echo "Configuration file '$GEOSERVER_DATA_DIR/security/auth/geonodeAuthProvider/config.xml' is not available so it is gone to skip" else # backup geonodeAuthProvider config.xml cp ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml.orig # run the setting script for geonodeAuthProvider - /usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/ ${TAGNAME[@]} > /dev/null 2>&1 + ./set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/config.xml ${GEOSERVER_DATA_DIR}/security/auth/geonodeAuthProvider/ ${TAGNAME[@]} > /dev/null 2>&1 fi # backup geonode REST role service config.xml cp "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml" "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml.orig" # run the setting script for geonode REST role service -/usr/local/tomcat/tmp/set_geoserver_auth.sh "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml" "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/" ${TAGNAME[@]} > /dev/null 2>&1 +./set_geoserver_auth.sh "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/config.xml" "${GEOSERVER_DATA_DIR}/security/role/geonode REST role service/" ${TAGNAME[@]} > /dev/null 2>&1 # set oauth2 filter tagname TAGNAME=( "cliendId" "clientSecret" "accessTokenUri" "userAuthorizationUri" "redirectUri" "checkTokenEndpointUrl" "logoutUri" ) @@ -175,7 +206,7 @@ TAGNAME=( "cliendId" "clientSecret" "accessTokenUri" "userAuthorizationUri" "red # backup geonode-oauth2 config.xml cp ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml.orig # run the setting script for geonode-oauth2 -/usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/ "${TAGNAME[@]}" > /dev/null 2>&1 +./set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/config.xml ${GEOSERVER_DATA_DIR}/security/filter/geonode-oauth2/ "${TAGNAME[@]}" > /dev/null 2>&1 # set global tagname TAGNAME=( "proxyBaseUrl" ) @@ -183,16 +214,23 @@ TAGNAME=( "proxyBaseUrl" ) # backup global.xml cp ${GEOSERVER_DATA_DIR}/global.xml ${GEOSERVER_DATA_DIR}/global.xml.orig # run the setting script for global configuration -/usr/local/tomcat/tmp/set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/global.xml ${GEOSERVER_DATA_DIR}/ ${TAGNAME[@]} > /dev/null 2>&1 +./set_geoserver_auth.sh ${GEOSERVER_DATA_DIR}/global.xml ${GEOSERVER_DATA_DIR}/ ${TAGNAME[@]} > /dev/null 2>&1 # set correct amqp broker url sed -i -e 's/localhost/rabbitmq/g' ${GEOSERVER_DATA_DIR}/notifier/notifier.xml # exclude wrong dependencies -sed -i -e 's/xom-\*\.jar/xom-\*\.jar,bcprov\*\.jar/g' /usr/local/tomcat/conf/catalina.properties +_PROPS="$CATALINA_HOME/conf/catalina.properties" -# J2 templating for this docker image we should also do it for other configuration files in /usr/local/tomcat/tmp +if [ -f $_PROPS ] && [ -w $_PROPS ]; then + sed -e 's/xom-\*\.jar/xom-\*\.jar,bcprov\*\.jar/g' $_PROPS > /tmp/catalina.properties + cat /tmp/catalina.properties > $_PROPS + rm /tmp/catalina.properties +fi +unset _PROPS + +# J2 templating for this docker image we should also do it for other configuration files in /usr/local/tomcat/tmp declare -a geoserver_datadir_template_dirs=("geofence") for template in in ${geoserver_datadir_template_dirs[*]}; do @@ -202,7 +240,7 @@ for template in in ${geoserver_datadir_template_dirs[*]}; do for f in $(find ${GEOSERVER_DATA_DIR}/geofence/ -type f -name "*.j2"); do echo -e "Evaluating template\n\tSource: $f\n\tDest: ${f%.j2}" - /usr/local/bin/j2 $f > ${f%.j2} + j2 $f > ${f%.j2} rm -f $f done @@ -213,10 +251,12 @@ done # if enabled, this will add the filter definitions # to the end of the web.xml # (this will only happen if our filter has not yet been added before) -if [ "${GEOSERVER_CORS_ENABLED}" = "true" ] || [ "${GEOSERVER_CORS_ENABLED}" = "True" ]; then - if ! grep -q DockerGeoServerCorsFilter "$CATALINA_HOME/webapps/geoserver/WEB-INF/web.xml"; then - echo "Enable CORS for $CATALINA_HOME/webapps/geoserver/WEB-INF/web.xml" - sed -i "\::i\\ +_WEBXML="$CATALINA_HOME/webapps/geoserver/WEB-INF/web.xml" + +if [ $(parse_bool $GEOSERVER_CORS_ENABLED) = "true" ] && [ -f $_WEBXML ] && [ -w $_WEBXML ]; then + if ! grep -q DockerGeoServerCorsFilter "$_WEBXML"; then + echo "Enable CORS for $_WEBXML" + sed "\::i\\ \n\ DockerGeoServerCorsFilter\n\ org.apache.catalina.filters.CorsFilter\n\ @@ -236,15 +276,20 @@ if [ "${GEOSERVER_CORS_ENABLED}" = "true" ] || [ "${GEOSERVER_CORS_ENABLED}" = " \n\ DockerGeoServerCorsFilter\n\ /*\n\ - " "$CATALINA_HOME/webapps/geoserver/WEB-INF/web.xml"; + " "$_WEBXML" > /tmp/web.xml; + cat /tmp/web.xml > "$_WEBXML" + rm /tmp/web.xml fi fi -if [ ${FORCE_REINIT} = "true" ] || [ ${FORCE_REINIT} = "True" ] || [ ! -e "${GEOSERVER_DATA_DIR}/geoserver_init.lock" ]; then - # Run async configuration, it needs Geoserver to be up and running - # executes step configure-geoserver from task.py file +unset _WEBXML + +# Force reinit +# Run async configuration, it needs Geoserver to be up and running +# executes step configure-geoserver from task.py file +if [ $(parse_bool $FORCE_REINIT) = "true" ] || [ ! -e "${GEOSERVER_DATA_DIR}/geoserver_init.lock" ]; then nohup sh -c "invoke configure-geoserver" & fi # start tomcat -exec env JAVA_OPTS="${JAVA_OPTS}" catalina.sh run +exec "$@" diff --git a/docker/geoserver/set_geoserver_auth.sh b/docker/geoserver/set_geoserver_auth.sh index 023636d..c8d7516 100644 --- a/docker/geoserver/set_geoserver_auth.sh +++ b/docker/geoserver/set_geoserver_auth.sh @@ -2,12 +2,39 @@ auth_conf_source="$1" auth_conf_target="$2" + # Creating a temporary file for sed to write the changes to temp_file="xml.tmp" touch $temp_file -source /root/.bashrc -source /root/.override_env +# check if user exists in passwd file +# if not, change HOME to /tmp +HAS_USER=$(getent passwd $(id -u) | wc -l) +if [ $HAS_USER -eq 1 ]; then + echo "User $_USER exists in passwd file" + + if [ $HOME = "/" ]; then + echo "HOME is /, changing to /tmp" + export HOME=/tmp + fi +else + echo "User does not exist in passwd file, changing HOME to /tmp" + export HOME=/tmp +fi +unset HAS_USER + +# Preserving the original behavior. +if [ ! -e $HOME/.bashrc ]; then + echo "No $HOME/.bashrc found, getting default from skeleton" + cp /etc/skel/.bashrc $HOME/.bashrc +fi + +source $HOME/.bashrc + +# Load the environment variables, if exists +if [ -e $HOME/.override_env ]; then + source $HOME/.override_env +fi test -z "$auth_conf_source" && echo "You must specify a source file" && exit 1 test -z "$auth_conf_target" && echo "You must specify a target conf directory" && exit 1 diff --git a/docker/geoserver_data/Dockerfile b/docker/geoserver_data/Dockerfile index 2c67bb6..9cf90dd 100644 --- a/docker/geoserver_data/Dockerfile +++ b/docker/geoserver_data/Dockerfile @@ -1,26 +1,30 @@ FROM alpine:latest ARG GEOSERVER_VERSION=2.24.x -LABEL GeoNode development team +ARG BASE_GEOSERVER_DATA_DIR=/geoserver_data -# Install curl in alpine 3.3+ -RUN apk --no-cache add curl +# Some label best practices +# https://www.docker.com/blog/docker-best-practices-using-tags-and-labels-to-manage-docker-image-sprawl/ +LABEL org.opencontainers.image.title="GeoNode's Geoserver Data image" \ + org.opencontainers.image.version=${GEOSERVER_VERSION} \ + org.opencontainers.image.vendor="GeoNode Development Team" -# Download required files -RUN mkdir -p /tmp/geonode/downloaded -ENV TEMP_DOWNLOADED /tmp/geonode/downloaded -WORKDIR ${TEMP_DOWNLOADED} +ENV TEMP_DOWNLOADED=/tmp/geonode/downloaded \ + GEOSERVER_VERSION=${GEOSERVER_VERSION} -ENV GEOSERVER_VERSION=${GEOSERVER_VERSION} +WORKDIR ${TEMP_DOWNLOADED} -ADD download.sh ${TEMP_DOWNLOADED} -RUN chmod +x ${TEMP_DOWNLOADED}/download.sh -RUN ${TEMP_DOWNLOADED}/download.sh $GEOSERVER_VERSION $TEMP_DOWNLOADED +COPY download.sh . -# for debugging -RUN ls -lart +# Download required files +RUN apk --no-cache add curl && \ + chmod +x download.sh && \ + sh download.sh $GEOSERVER_VERSION $TEMP_DOWNLOADED && \ + # for debugging + ls -lart # preparing the volume -ENV BASE_GEOSERVER_DATA_DIR /geoserver_data -RUN mkdir -p ${BASE_GEOSERVER_DATA_DIR} -RUN cp -r ${TEMP_DOWNLOADED}/data ${BASE_GEOSERVER_DATA_DIR} +RUN mkdir -p ${BASE_GEOSERVER_DATA_DIR} && \ + cp -r ${TEMP_DOWNLOADED}/data ${BASE_GEOSERVER_DATA_DIR} && \ + chmod -R g=u ${BASE_GEOSERVER_DATA_DIR}/data + VOLUME ${BASE_GEOSERVER_DATA_DIR}/data diff --git a/docker/letsencrypt/Dockerfile b/docker/letsencrypt/Dockerfile index 3d00328..5289d21 100644 --- a/docker/letsencrypt/Dockerfile +++ b/docker/letsencrypt/Dockerfile @@ -3,16 +3,15 @@ FROM alpine:latest RUN apk add --no-cache certbot # Installing scripts -ADD docker-entrypoint.sh /docker-entrypoint.sh -RUN chmod +x /docker-entrypoint.sh +COPY docker-entrypoint.sh /docker-entrypoint.sh +COPY crontab /crontab -# Installing cronjobs -ADD crontab /crontab -RUN /usr/bin/crontab /crontab && \ +RUN chmod +x /docker-entrypoint.sh && \ + crontab /crontab && \ rm /crontab # Setup the entrypoint ENTRYPOINT ["./docker-entrypoint.sh"] # We run cron in foreground to update the certificates -CMD /usr/sbin/crond -f +CMD ["/usr/sbin/crond", "-f"] diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile index 430d6a7..33aeb9a 100644 --- a/docker/nginx/Dockerfile +++ b/docker/nginx/Dockerfile @@ -1,19 +1,33 @@ -ARG NGINX_VERSION=1.25.3 -FROM nginx:${NGINX_VERSION}-alpine +ARG NGINX_VERSION=1.25.5 +FROM nginxinc/nginx-unprivileged:${NGINX_VERSION}-alpine + +USER root RUN apk add --no-cache openssl inotify-tools vim -WORKDIR /etc/nginx/ +WORKDIR /etc/nginx + +COPY nginx.conf.envsubst ./ +COPY nginx.https.available.conf.envsubst ./https/ +COPY geonode.conf.envsubst ./sites-enabled/ +COPY docker-autoreload.sh docker-entrypoint.sh / -RUN mkdir -p /etc/nginx/html &&\ - touch /etc/nginx/html/index.html +RUN mkdir -p \ + /geonode-certificates/disabled \ + /geonode-certificates/staging \ + /geonode-certificates/production \ + /geonode-certificates/autoissued && \ + mv nginx.conf nginx.conf.orig && \ + touch nginx.conf && \ + chmod -R g=u \ + /geonode-certificates/* \ + nginx.conf \ + ./https/ \ + ./sites-enabled/ && \ + chmod +x /docker-autoreload.sh /docker-entrypoint.sh -ADD nginx.conf.envsubst nginx.https.available.conf.envsubst ./ -ADD geonode.conf.envsubst ./sites-enabled/ +USER nginx -ADD docker-autoreload.sh docker-entrypoint.sh / ENTRYPOINT ["/docker-entrypoint.sh"] -RUN chmod +x /docker-autoreload.sh -RUN chmod +x /docker-entrypoint.sh CMD ["nginx", "-g", "daemon off;"] diff --git a/docker/nginx/docker-autoreload.sh b/docker/nginx/docker-autoreload.sh index 812cc76..8c5d193 100644 --- a/docker/nginx/docker-autoreload.sh +++ b/docker/nginx/docker-autoreload.sh @@ -15,13 +15,13 @@ do echo "Creating symbolic link for WAN host" # for some reason, the ln -f flag doesn't work below... - rm -f /certificate_symlink + rm -f /tmp/certificate_symlink if [ -f "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST/fullchain.pem" ] && [ -f "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST/privkey.pem" ]; then echo "Certbot certificate exists, we symlink to the live cert" - ln -sf "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST" /certificate_symlink + ln -sf "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST" /tmp/certificate_symlink else echo "Certbot certificate does not exist, we symlink to autoissued" - ln -sf "/geonode-certificates/autoissued" /certificate_symlink + ln -sf "/geonode-certificates/autoissued" /tmp/certificate_symlink fi # Test nginx configuration diff --git a/docker/nginx/docker-entrypoint.sh b/docker/nginx/docker-entrypoint.sh index 316cab0..1f1f262 100644 --- a/docker/nginx/docker-entrypoint.sh +++ b/docker/nginx/docker-entrypoint.sh @@ -3,34 +3,14 @@ # Exit script in case of error set -e -echo $"\n\n\n" +echo "\n\n\n" echo "-----------------------------------------------------" echo "STARTING NGINX ENTRYPOINT ---------------------------" +echo "-----------------------------------------------------" date # We make the config dir -mkdir -p "/geonode-certificates/$LETSENCRYPT_MODE" - -echo "Creating autoissued certificates for HTTP host" -if [ ! -f "/geonode-certificates/autoissued/privkey.pem" ] || [[ $(find /geonode-certificates/autoissued/privkey.pem -mtime +365 -print) ]]; then - echo "Autoissued certificate does not exist or is too old, we generate one" - mkdir -p "/geonode-certificates/autoissued/" - openssl req -x509 -nodes -days 1825 -newkey rsa:2048 -keyout "/geonode-certificates/autoissued/privkey.pem" -out "/geonode-certificates/autoissued/fullchain.pem" -subj "/CN=${HTTP_HOST:-HTTPS_HOST}" -else - echo "Autoissued certificate already exists" -fi - -echo "Creating symbolic link for HTTPS certificate" -# for some reason, the ln -f flag doesn't work below... -# TODO : not DRY (reuse same scripts as docker-autoreload.sh) -rm -f /certificate_symlink -if [ -f "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST/fullchain.pem" ] && [ -f "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST/privkey.pem" ]; then - echo "Certbot certificate exists, we symlink to the live cert" - ln -sf "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST" /certificate_symlink -else - echo "Certbot certificate does not exist, we symlink to autoissued" - ln -sf "/geonode-certificates/autoissued" /certificate_symlink -fi +# mkdir -p "/geonode-certificates/$LETSENCRYPT_MODE" if [ -z "${HTTPS_HOST}" ]; then HTTP_SCHEME="http" @@ -39,6 +19,7 @@ if [ -z "${HTTPS_HOST}" ]; then else PUBLIC_HOST="$HTTP_HOST:$HTTP_PORT" fi + else HTTP_SCHEME="https" if [ $HTTPS_PORT = "443" ]; then @@ -46,6 +27,27 @@ else else PUBLIC_HOST="$HTTPS_HOST:$HTTPS_PORT" fi + + echo "Creating autoissued certificates for HTTP host" + if [ ! -f "/geonode-certificates/autoissued/privkey.pem" ] || [[ $(find /geonode-certificates/autoissued/privkey.pem -mtime +365 -print) ]]; then + echo "Autoissued certificate does not exist or is too old, we generate one" + # mkdir -p "/geonode-certificates/autoissued/" + openssl req -x509 -nodes -days 1825 -newkey rsa:2048 -keyout "/geonode-certificates/autoissued/privkey.pem" -out "/geonode-certificates/autoissued/fullchain.pem" -subj "/CN=${HTTP_HOST:-HTTPS_HOST}" + else + echo "Autoissued certificate already exists" + fi + + echo "Creating symbolic link for HTTPS certificate" + # for some reason, the ln -f flag doesn't work below... + # TODO : not DRY (reuse same scripts as docker-autoreload.sh) + rm -f /tmp/certificate_symlink + if [ -f "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST/fullchain.pem" ] && [ -f "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST/privkey.pem" ]; then + echo "Certbot certificate exists, we symlink to the live cert" + ln -sf "/geonode-certificates/$LETSENCRYPT_MODE/live/$HTTPS_HOST" /tmp/certificate_symlink + else + echo "Certbot certificate does not exist, we symlink to autoissued" + ln -sf "/geonode-certificates/autoissued" /tmp/certificate_symlink + fi fi export HTTP_SCHEME=${HTTP_SCHEME:-http} @@ -58,15 +60,15 @@ export PUBLIC_HOST=${PUBLIC_HOST} defined_envs=$(printf '${%s} ' $(env | cut -d= -f1)) echo "Replacing environment variables" -envsubst "$defined_envs" < /etc/nginx/nginx.conf.envsubst > /etc/nginx/nginx.conf -envsubst "$defined_envs" < /etc/nginx/nginx.https.available.conf.envsubst > /etc/nginx/nginx.https.available.conf -envsubst "$defined_envs" < /etc/nginx/sites-enabled/geonode.conf.envsubst > /etc/nginx/sites-enabled/geonode.conf +envsubst "$defined_envs" < ./nginx.conf.envsubst > nginx.conf +envsubst "$defined_envs" < ./https/nginx.https.available.conf.envsubst > ./https/nginx.https.available.conf +envsubst "$defined_envs" < ./sites-enabled/geonode.conf.envsubst > ./sites-enabled/geonode.conf echo "Enabling or not https configuration" if [ -z "${HTTPS_HOST}" ]; then - echo "" > /etc/nginx/nginx.https.enabled.conf + echo "" > ./https/nginx.https.enabled.conf else - ln -sf /etc/nginx/nginx.https.available.conf /etc/nginx/nginx.https.enabled.conf + ln -sf /etc/nginx/https/nginx.https.available.conf /etc/nginx/https/nginx.https.enabled.conf fi echo "Loading nginx autoreloader" diff --git a/docker/nginx/geonode.conf.envsubst b/docker/nginx/geonode.conf.envsubst index 173adbf..36c60a8 100644 --- a/docker/nginx/geonode.conf.envsubst +++ b/docker/nginx/geonode.conf.envsubst @@ -1,5 +1,3 @@ -include /etc/nginx/mime.types; - # This is the main geonode conf charset utf-8; diff --git a/docker/nginx/nginx.conf.envsubst b/docker/nginx/nginx.conf.envsubst index b606520..df7ffca 100644 --- a/docker/nginx/nginx.conf.envsubst +++ b/docker/nginx/nginx.conf.envsubst @@ -3,12 +3,30 @@ worker_processes auto; +error_log /var/log/nginx/error.log notice; +pid /tmp/nginx.pid; + events { } http { - server_names_hash_bucket_size 64; + proxy_temp_path /tmp/proxy_temp; + client_body_temp_path /tmp/client_temp; + fastcgi_temp_path /tmp/fastcgi_temp; + uwsgi_temp_path /tmp/uwsgi_temp; + scgi_temp_path /tmp/scgi_temp; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + server_names_hash_bucket_size 128; # Allow Nginx to resolve Docker host names (see https://sandro-keil.de/blog/2017/07/24/let-nginx-start-if-upstream-host-is-unavailable-or-down/) resolver $RESOLVER; # it seems rancher uses 169.254.169.250 instead of 127.0.0.11 which works well in docker-compose (see /etc/resolv.conf) @@ -16,13 +34,13 @@ http { # https - listens on specific name - this uses letsencrypt cert # this includes a symlink that links either to nginx.https.available.conf if https in enabled # or to an empty file if https is disabled. - include nginx.https.enabled.conf; + include https/nginx.https.enabled.conf; # http - listens to specific HTTP_HOST only - this is not encrypted (not ideal but admissible on LAN for instance) # even if not used (HTTP_HOST empty), we must keep it as it's used for internal API calls between django and geoserver # TODO : do not use unencrypted connection even on LAN, but is it possible to have browser not complaining about unknown authority ? server { - listen 80; + listen 8080; server_name $HTTP_HOST 127.0.0.1; include sites-enabled/*.conf; @@ -30,8 +48,8 @@ http { # Default server closes the connection (we can connect only using HTTP_HOST and HTTPS_HOST) server { - listen 80 default_server; - listen 443; + listen 8080 default_server; + listen 8443; server_name _; return 444; } diff --git a/docker/nginx/nginx.https.available.conf.envsubst b/docker/nginx/nginx.https.available.conf.envsubst index fcd1cb3..18107b6 100644 --- a/docker/nginx/nginx.https.available.conf.envsubst +++ b/docker/nginx/nginx.https.available.conf.envsubst @@ -7,12 +7,12 @@ ssl_session_timeout 10m; # this is the actual HTTPS host server { - listen 443 ssl; + listen 8443 ssl; server_name $HTTPS_HOST; keepalive_timeout 70; - ssl_certificate /certificate_symlink/fullchain.pem; - ssl_certificate_key /certificate_symlink/privkey.pem; + ssl_certificate /tmp/certificate_symlink/fullchain.pem; + ssl_certificate_key /tmp/certificate_symlink/privkey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; @@ -21,7 +21,7 @@ server { # if we try to connect from http, we redirect to https server { - listen 80; + listen 8080; server_name $HTTPS_HOST $HTTP_HOST; # TODO : once geoserver supports relative urls, we should allow access though both HTTP and HTTPS at the same time and hence remove HTTP_HOST from this line # Except for let's encrypt challenge