Skip to content

Commit

Permalink
Merge pull request #59 from mjanez/fix/nginx-multilocations
Browse files Browse the repository at this point in the history
Fix/nginx multilocations
  • Loading branch information
mjanez authored Jul 26, 2023
2 parents 93831d9 + a2fa917 commit ab4b991
Show file tree
Hide file tree
Showing 17 changed files with 372 additions and 180 deletions.
13 changes: 8 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,18 @@ TEST_CKAN_REDIS_URL=redis://redis:6379/1
# NGINX
NGINX_PORT=80
NGINX_SSLPORT=443
NGINX_LOG_DIR=/var/log/nginx

# Apache HTTP Server
APACHE_VERSION=2.4-alpine
APACHE_PORT=80
APACHE_LOG_DIR=/var/log/apache
APACHE_SERVER_NAME=localhost
# Check CKAN__ROOT_PATH and CKANEXT__DCAT__BASE_URI. If you don't need to use domain locations, it is better to use the nginx configuration. Leave blank or use the root `/`.
APACHE_CKAN_LOCATION=/catalog
APACHE_PYCSW_LOCATION=/csw

#NIGNX/APACHE
## Check CKAN__ROOT_PATH and CKANEXT__DCAT__BASE_URI. If you don't need to use domain locations, it is better to use the nginx configuration. Leave blank or use the root `/`.
PROXY_SERVER_NAME=localhost
PROXY_CKAN_LOCATION=/catalog
PROXY_PYCSW_LOCATION=/csw

# pycsw
PYCSW_PORT=8000
Expand Down Expand Up @@ -76,7 +79,7 @@ TEST_CKAN_DATASTORE_READ_URL=postgresql://datastore_ro:datastore@db/datastore_te
## If use docker-compose.ghcr.yml only "*.*.*" versions available in: https://github.com/mjanez/ckan-docker/pkgs/container/ckan-spatial
CKAN_VERSION=2.9.9
CKAN_SITE_ID=default
# CKAN_SITE_URL = http:/ or https:/ + APACHE_SERVER_NAME. Optionally the APACHE_HOST_PORT if different from 80
# CKAN_SITE_URL = http:/ or https:/ + PROXY_SERVER_NAME. Optionally the APACHE_HOST_PORT if different from 80
CKAN_SITE_URL=http://localhost
CKAN__ROOT_PATH=/catalog/{{LANG}}
CKAN_PORT=5000
Expand Down
84 changes: 49 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,25 @@ The non-CKAN images are as follows:
* PostgreSQL: [Custom image](/postgresql/Dockerfile) based on official PostgreSQL image. Database files are stored in a named volume.
* Solr: CKAN's [pre-configured Solr image](https://github.com/ckan/ckan-solr). The index data is stored in a named volume and has a spatial schema. [^2]
* Redis: standard Redis image
* Apache HTTP Server: [Custom image](/apache/Dockerfile) based on official latest stable httpd image. Configured to serve multiple routes for the [ckan-pycsw](#ckan-pycsw) CSW endpoint (`{CKAN_SITE_URL}/csw`) and CKAN (`{CKAN_SITE_URL}/catalog`).
* NGINX: latest stable nginx image that includes SSL and Non-SSL endpoints.
* ckan-pycsw: [Custom image](/ckan-pycsw/Dockerfile) based on [pycsw CKAN harvester ISO19139](https://github.com/mjanez/ckan-pycsw) for INSPIRE Metadata CSW Endpoint.

Optional HTTP Endpoint ([`docker-compose.nginx.yml`](/docker-compose.nginx.yml)):
* `docker-compose.nginx.yml`:
* NGINX: latest stable nginx image that includes SSL and Non-SSL endpoints instead of Apache HTTP Server. No locations, no ckan-pycsw, only CKAN.

Optional HTTP Endpoint ([`docker-compose.apache.yml`](/docker-compose.apache.yml)):
* `docker-compose.apache.yml`:
* Apache HTTP Server: [Custom image](/apache/Dockerfile) based on official latest stable httpd image. Configured to serve multiple routes for the [ckan-pycsw](#ckan-pycsw) CSW endpoint (`{CKAN_SITE_URL}/csw`) and CKAN (`{CKAN_SITE_URL}/catalog`). Only HTTP.

| Compose files | Repository | Type | Docker tag | Size | Notes |
| --- | --- | --- | --- | --- | --- |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.nginx.yml`](/docker-cospatianginx.yml) | CKAN 2.9.8 | custom image | [`mjanez/ckan-spatial:ckan-2.9.8`](https://github.com/mjanez/ckan-docker/pkgs/container/ckan-spatial) | 800 MB | Custom Dockerfile: [`ckan/Dockerfile`](/ckan/Dockerfile) |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.nginx.yml`](/docker-compose.nginx.yml) | PostgreSQL 15.2 | base image | [`postgres/postgres:15-alpine`](https://hub.docker.com/layers/library/postgres/15-alpine/images/sha256-53a02ecbe9d18ff6476e6651c34811da39f054424c725fc15d2b480fc3fab877?context=explore) | 89.74 MB | Custom Dockerfile: [`postgresql/Dockerfile`](/postgresql/Dockerfile) |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.nginx.yml`](/docker-compose.nginx.yml) | Solr 8.11.1 | custom image | [`ckan/ckan-solr:2.9-solr8-spatial`](https://registry.hub.docker.com/layers/ckan/ckan-solr/2.9-solr8-spatial/images/sha256-b5ee4979891c7dd1f10d2ac2cbdd4d80ff656879edb0f0493616be7b4cf8bc3a?context=explore) | 331.1 MB | CKAN's [pre-configured spatial Solr image](https://github.com/ckan/ckan-solr). |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.nginx.yml`](/docker-compose.nginx.yml) | Redis 7.0.10 | base image | [`redis/redis:7-alpine`](https://hub.docker.com/layers/library/redis/7-alpine/images/sha256-98f4ea44e912d0941d29015a4e2448151b94411109c896b5627d94d79306eea7?context=explore) | 11.82 MB | - |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.apache.yml`](/docker-compose.apache.yml) | CKAN 2.9.8 | custom image | [`mjanez/ckan-spatial:ckan-2.9.8`](https://github.com/mjanez/ckan-docker/pkgs/container/ckan-spatial) | 800 MB | Custom Dockerfile: [`ckan/Dockerfile`](/ckan/Dockerfile) |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.apache.yml`](/docker-compose.apache.yml) | PostgreSQL 15.2 | base image | [`postgres/postgres:15-alpine`](https://hub.docker.com/layers/library/postgres/15-alpine/images/sha256-53a02ecbe9d18ff6476e6651c34811da39f054424c725fc15d2b480fc3fab877?context=explore) | 89.74 MB | Custom Dockerfile: [`postgresql/Dockerfile`](/postgresql/Dockerfile) |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.apache.yml`](/docker-compose.apache.yml) | Solr 8.11.1 | custom image | [`ckan/ckan-solr:2.9-solr8-spatial`](https://registry.hub.docker.com/layers/ckan/ckan-solr/2.9-solr8-spatial/images/sha256-b5ee4979891c7dd1f10d2ac2cbdd4d80ff656879edb0f0493616be7b4cf8bc3a?context=explore) | 331.1 MB | CKAN's [pre-configured spatial Solr image](https://github.com/ckan/ckan-solr). |
| [`docker-compose.yml`](/docker-compose.yml) / [`docker-compose.apache.yml`](/docker-compose.apache.yml) | Redis 7.0.10 | base image | [`redis/redis:7-alpine`](https://hub.docker.com/layers/library/redis/7-alpine/images/sha256-98f4ea44e912d0941d29015a4e2448151b94411109c896b5627d94d79306eea7?context=explore) | 11.82 MB | - |
| [`docker-compose.yml`](/docker-compose.yml) | Apache HTTP Server 2.4 | custom image | [`httpd/httpd:2.4`](https://hub.docker.com/layers/library/httpd/2.4/images/sha256-f34e8e25ee18da020633ef0b2bf7516d8cfdad5c5c4b0595d36e5cd78a098101?context=explore) | 54.47 MB | Custom Dockerfile: [`apache/Dockerfile`](/apache/Dockerfile) |
| [`docker-compose.yml`](/docker-compose.yml)| pycsw CKAN harvester ISO19139 | custom image | [`mjanez/ckan-pycsw:latest`](https://github.com/mjanez/ckan-pycsw/pkgs/container/ckan-pycsw) | 175 MB | Custom Dockerfile: [`ckan-pycsw/Dockerfile`](/ckan-pycsw/Dockerfile) |
| [`docker-compose.nginx.yml`](/docker-compose.nginx.yml) | NGINX 1.22.1 | base image | [`nginx:stable-alpine`](https://hub.docker.com/layers/library/nginx/stable-alpine/images/sha256-ff2a5d557ca22fa93669f5e70cfbeefda32b98f8fd3d33b38028c582d700f93a?context=explore) | 9.74 MB | No routing, only CKAN. Custom Dockerfile: [`nginx/Dockerfile`](/nginx/Dockerfile) |
| [`docker-compose.apache.yml`](/docker-compose.apache.yml) | NGINX 1.22.1 | base image | [`nginx:stable-alpine`](https://hub.docker.com/layers/library/nginx/stable-alpine/images/sha256-ff2a5d557ca22fa93669f5e70cfbeefda32b98f8fd3d33b38028c582d700f93a?context=explore) | 9.74 MB | No routing, only CKAN. Custom Dockerfile: [`nginx/Dockerfile`](/nginx/Dockerfile) |


The site is configured using environment variables that you can set in the `.env` file for an Apache HTTP Server and ckan-pycsw deployment (default `.env.example`), or replace it with the [`.env.nginx.example`](/samples/.env.nginx.example) for a NGINX and CKAN-only deployment using the Docker Compose file: [`docker-compose.nginx.yml`](/docker-compose.nginx.yml).
The site is configured using environment variables that you can set in the `.env` file for an NGINX and ckan-pycsw deployment (default `.env.example`), or replace it with the [`.env.apache.example`](/samples/.env.apache.example) for a Apache HTTP Server deployment using the Docker Compose file: [`docker-compose.apache.yml`](/docker-compose.apache.yml).


### ckan-docker roadmap
Expand Down Expand Up @@ -118,9 +117,9 @@ Use this if you are a maintainer and will not be making code changes to CKAN or
cp .env.example .env
```

- **Apache HTTP Server & CKAN/ckan-pycsw endpoints**: Modifiy the variables about the site URL or locations (`CKAN_SITE_URL` `CKAN_URL`, `PYCSW_URL`, `CKANEXT__DCAT__BASE_URI`, `APACHE_SERVER_NAME`, `APACHE_CKAN_LOCATION`, `APACHE_PYCSW_LOCATION`, etc.).
- **NGINX & CKAN/ckan-pycsw endpoints**: Modifiy the variables about the site URL or locations (`CKAN_SITE_URL` `CKAN_URL`, `PYCSW_URL`, `CKANEXT__DCAT__BASE_URI`, `PROXY_SERVER_NAME`, `PROXY_CKAN_LOCATION`, `PROXY_PYCSW_LOCATION`, etc.).

- **NGINX only CKAN**: Replace the [`.env`](/.env) with the [`/samples/.env.nginx.example`](/samples/.env.nginx.example) and modify the variables as needed.
- **Apache HTTP Server**: Replace the [`.env`](/.env) with the [`/samples/.env.apache.example`](/samples/.env.apache.example) and modify the variables as needed.

>**Note**:<br>
> Please note that when accessing CKAN directly (via a browser) ie: not going through Apache/NGINX you will need to make sure you have "ckan" set up to be an alias to localhost in the local hosts file. Either that or you will need to change the `.env` entry for `CKAN_SITE_URL`
Expand Down Expand Up @@ -149,7 +148,7 @@ window for something else.

>**Note**<br>
> * Or `docker compose up --build` to build & up the containers.
> * Or `docker compose -f docker-compose.nginx.yml up -d --build` to use the NGINX version.
> * Or `docker compose -f docker-compose.apache.yml up -d --build` to use the Apache HTTP Server version.

>**Note**<br>
> Learn more about configuring this ckan docker:
Expand All @@ -158,11 +157,11 @@ window for something else.

At the end of the container start sequence there should be 6 containers running (or 5 if use NGINX Docker Compose file)

After this step, CKAN should be running at {`APACHE_SERVER_NAME`}{`APACHE_CKAN_LOCATION`} and ckan-pycsw at {`APACHE_SERVER_NAME`}{`APACHE_PYCSW_LOCATION`}, i.e: http://localhost/catalog or http://localhost/csw
After this step, CKAN should be running at {`PROXY_SERVER_NAME`}{`PROXY_CKAN_LOCATION`} and ckan-pycsw at {`PROXY_SERVER_NAME`}{`PROXY_PYCSW_LOCATION`}, i.e: http://localhost/catalog or http://localhost/csw

|CONTAINER ID |IMAGE |COMMAND|CREATED|STATUS|PORTS|NAMES|
|------------|----------------------------------|--------------------|-------|-------|------|-----|
|0217537f717e|ckan-docker-apache |/docker-entrypoint.…|6 minutes ago |Up 4 minutes|80/tcp,0.0.0.0:80->80/tcp | apache |
|0217537f717e|ckan-docker-nginx |/docker-entrypoint.…|6 minutes ago |Up 4 minutes|80/tcp,0.0.0.0:80->80/tcp,0.0.0.0:8443->443/tcp | nginx |
|7b06ab2e060a|ckan-docker-ckan|/srv/app/start_ckan…|6 minutes ago |Up 5 minutes (healthy)|0.0.0.0:5000->5000/tcp|ckan | |
|1b8d9789c29a|redis:7-alpine |docker-entrypoint.s…|6 minutes ago |Up 4 minutes (healthy)|6379/tcp |redis | |
|7f162741254d|ckan/ckan-solr:2.9-solr8-spatial |docker-entrypoint.s…|6 minutes ago |Up 4 minutes (healthy)|8983/tcp |solr | |
Expand Down Expand Up @@ -345,36 +344,51 @@ command: `python -m pdb /usr/lib/ckan/venv/bin/ckan --config /srv/app/ckan.ini r
The Datastore database and user is created as part of the entrypoint scripts for the db container.
### Apache HTTP Server
The default Docker Compose configuration ([`docker-compose.yml`](/docker-compose.yml)) uses an httpd image as the front-end. It has two routes for the ckan (default location: `/catalog`) and ckan-pycsw (default location: `/csw`) services.
### NGINX
The default Docker Compose configuration ([`docker-compose.yml`](/docker-compose.yml)) uses an NGINX image as the front-end (ie: reverse proxy). It includes HTTPS running on port number 8443 and an HTTP port (81). A "self-signed" SSL certificate is generated beforehand and the server certificate and key files are included. The NGINX `server_name` (ENV: `PROXY_SERVER_NAME`) directive and the `CN` field in the SSL certificate have been both set to 'localhost'. This should obviously not be used for production.
Both web locations can be modified in the `.env` file:
The proxy locations, ports and other NGINX options can be modified in the `.env` file:
```ini
...
# Host Ports
NGINX_PORT_HOST=81
NGINX_SSLPORT_HOST=8443
# Apache HTTP Server
APACHE_VERSION=2.4
APACHE_PORT=80
APACHE_LOG_DIR=/var/log/apache
APACHE_SERVER_NAME=mjanez-cautious-lamp-4pjq9vpg967hq447-80.preview.app.github.dev
# Check CKAN__ROOT_PATH and CKANEXT__DCAT__BASE_URI. If you don't need to use domain locations, it is better to use the nginx configuration. Leave blank or use the root `/`.
APACHE_CKAN_LOCATION=/catalog
APACHE_PYCSW_LOCATION=/csw
# NGINX
NGINX_PORT=80
NGINX_SSLPORT=443
NGINX_LOG_DIR=/var/log/nginx
...
# Check CKAN__ROOT_PATH and CKANEXT__DCAT__BASE_URI. If you don't need to use domain locations, it is better to use the nginx configuration. Leave blank or use the root `/`.
PROXY_SERVER_NAME=192.168.68.106
PROXY_CKAN_LOCATION=/catalog
PROXY_PYCSW_LOCATION=/csw
```

### NGINX
>**Warning**<br>
> The [nginx docker compose file](/docker-compose.nginx.yml) only deploys the CKAN service, not ckan-pycsw.

The nginx Docker Compose configuration ([`docker-compose.nginx.yml`](/docker-compose.nginx.yml)) uses an NGINX image as the front-end (ie: reverse proxy). It includes HTTPS running on port number 8443 and an HTTP port (81). A "self-signed" SSL certificate is generated beforehand and the server certificate and key files are included. The NGINX `server_name` directive and the `CN` field in the SSL certificate have been both set to 'localhost'. This should obviously not be used for production.

Creating the SSL cert and key files as follows:
`openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=DE/ST=Berlin/L=Berlin/O=None/CN=localhost" -keyout ckan-local.key -out ckan-local.crt`
The `ckan-local.*` files will then need to be moved into the nginx/setup/ directory


### Apache HTTP Server
The Docker Compose configuration ([`docker-compose.apache.yml`](/docker-compose.apache.yml)) uses an httpd image as the front-end. It has two routes for the ckan (default location: `/catalog`) and ckan-pycsw (default location: `/csw`) services.

The proxy locations, ports and other Apache Web Server options can be modified in the `.env` file:
```ini
# Host Ports
APACHE_PORT_HOST=81
# Apache HTTP Server
APACHE_VERSION=2.4-alpine
APACHE_PORT=80
APACHE_LOG_DIR=/var/log/apache
# Check CKAN__ROOT_PATH and CKANEXT__DCAT__BASE_URI. If you don't need to use domain locations, it is better to use the nginx configuration. Leave blank or use the root `/`.
PROXY_SERVER_NAME=192.168.68.106
PROXY_CKAN_LOCATION=/catalog
PROXY_PYCSW_LOCATION=/csw
```


### envvars
The ckanext-envvars extension is used in the CKAN Docker base repo to build the base images.
This extension checks for environmental variables conforming to an expected format and updates the corresponding CKAN config settings with its value.
Expand Down
10 changes: 5 additions & 5 deletions apache/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ ENV APACHE_PORT=80
ENV APACHE_LOG_DIR=/var/log/apache
ENV APACHE_ROOT=/usr/local/apache2
ENV APACHE_DOCUMENT_ROOT=${APACHE_ROOT}/htdocs
ENV APACHE_SERVER_NAME=localhost
ENV PROXY_SERVER_NAME=localhost

ENV APACHE_CKAN_LOCATION=/
ENV APACHE_PYCSW_LOCATION=/csw
ENV APACHE_PYCSW_PROXY_PASS=http://${PYCSW_CONTAINER_NAME}:${PYCSW_PORT_HOST}
ENV APACHE_CKAN_PROXY_PASS=http://${CKAN_CONTAINER_NAME}:${CKAN_PORT_HOST}
ENV PROXY_CKAN_LOCATION=/catalog
ENV PROXY_PYCSW_LOCATION=/csw
ENV PROXY_PYCSW_PROXY_PASS=http://${PYCSW_CONTAINER_NAME}:${PYCSW_PORT_HOST}
ENV PROXY_CKAN_PROXY_PASS=http://${CKAN_CONTAINER_NAME}:${CKAN_PORT_HOST}

RUN mkdir -p ${APACHE_LOG_DIR}

Expand Down
14 changes: 7 additions & 7 deletions apache/setup/httpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,18 @@ Group www-data
# virtual host being defined.
#
<VirtualHost *:${APACHE_PORT}>
<Location ${APACHE_CKAN_LOCATION}>
ProxyPass ${APACHE_CKAN_PROXY_PASS}
ProxyPassReverse ${APACHE_CKAN_PROXY_PASS}
<Location ${PROXY_CKAN_LOCATION}>
ProxyPass ${PROXY_CKAN_PROXY_PASS}
ProxyPassReverse ${PROXY_CKAN_PROXY_PASS}
</Location>

<Location ${APACHE_PYCSW_LOCATION}>
ProxyPass ${APACHE_PYCSW_PROXY_PASS}
ProxyPassReverse ${APACHE_PYCSW_PROXY_PASS}
<Location ${PROXY_PYCSW_LOCATION}>
ProxyPass ${PROXY_PYCSW_PROXY_PASS}
ProxyPassReverse ${PROXY_PYCSW_PROXY_PASS}
</Location>

Protocols h2 http/1.1
ServerName ${APACHE_SERVER_NAME}
ServerName ${PROXY_SERVER_NAME}
ServerAdmin webmaster@localhost
DocumentRoot ${APACHE_DOCUMENT_ROOT}
ErrorLog ${APACHE_LOG_DIR}/error.log
Expand Down
2 changes: 1 addition & 1 deletion ckan/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ RUN echo ${TZ} > /etc/timezone && \
# Used to configure the container environment by setting environment variables, creating users, running initialization scripts, .etc
COPY docker-entrypoint.d/* /docker-entrypoint.d/

# Update who.ini with APACHE_CKAN_LOCATION
# Update who.ini with PROXY_CKAN_LOCATION
COPY setup/who.ini ${APP_DIR}/

# Apply any patches needed to CKAN core
Expand Down
2 changes: 1 addition & 1 deletion ckan/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ RUN echo ${TZ} > /etc/timezone && \
# Used to configure the container environment by setting environment variables, creating users, running initialization scripts, .etc
COPY docker-entrypoint.d/* /docker-entrypoint.d/

# Update who.ini with APACHE_CKAN_LOCATION
# Update who.ini with PROXY_CKAN_LOCATION
COPY setup/who.ini ${APP_DIR}/

# Override start_ckan.sh with DEV sh
Expand Down
2 changes: 1 addition & 1 deletion ckan/Dockerfile.ghcr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN if ! [ /usr/share/zoneinfo/${TZ} -ef /etc/localtime ]; then \
# Used to configure the container environment by setting environment variables, creating users, running initialization scripts, .etc
COPY docker-entrypoint.d/* /docker-entrypoint.d/

# Update who.ini with APACHE_CKAN_LOCATION
# Update who.ini with PROXY_CKAN_LOCATION
COPY setup/who.ini ${APP_DIR}/

# Apply any patches needed to CKAN core
Expand Down
18 changes: 12 additions & 6 deletions ckan/docker-entrypoint.d/00_update_who.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
#!/bin/bash

# Update who.ini when exists APACHE_CKAN_LOCATION
# Update who.ini when exists PROXY_CKAN_LOCATION
echo "Update who.ini"
if [ -n "$APACHE_CKAN_LOCATION" ] && [ "$APACHE_CKAN_LOCATION" != "/" ]; then \
sed -i "s|\${WHO_LOCATION}|$APACHE_CKAN_LOCATION|g" ${APP_DIR}/who.ini; \
else \
sed -i "s|\${WHO_LOCATION}|/|g" ${APP_DIR}/who.ini; \
fi
if [ -n "$PROXY_CKAN_LOCATION" ] && [ "$PROXY_CKAN_LOCATION" != "/" ]; then
sed -i "s|\${WHO_LOCATION}|$PROXY_CKAN_LOCATION|g" "${APP_DIR}/who.ini";
else
# Check if the value is exactly "/"
if [ "$PROXY_CKAN_LOCATION" = "/" ]; then
sed -i "s|\${WHO_LOCATION}||g" "${APP_DIR}/who.ini";
else
# Handle the case when $PROXY_CKAN_LOCATION is empty or not set
sed -i "s|\${WHO_LOCATION}|/|g" "${APP_DIR}/who.ini";
fi
fi
Loading

0 comments on commit ab4b991

Please sign in to comment.