├── .env.example ├── .github └── workflows │ └── build.yml ├── .gitignore ├── README.md ├── bin ├── ckan ├── compose ├── generate_extension ├── install_src ├── reload ├── restart └── shell ├── ckan ├── Dockerfile ├── Dockerfile.dev ├── docker-entrypoint.d │ ├── 01_setup_datapusher.sh │ └── README.md ├── patches │ └── 00_test_test.patch └── setup │ ├── prerun.py.override │ ├── start_ckan.sh.override │ └── start_ckan_development.sh.override ├── docker-compose.dev.yml ├── docker-compose.yml ├── nginx ├── Dockerfile └── setup │ ├── ckan-local.crt │ ├── ckan-local.key │ ├── default.conf │ ├── error.html │ ├── index.html │ └── nginx.conf ├── postgresql ├── Dockerfile └── docker-entrypoint-initdb.d │ ├── .gitattributes │ ├── 10_create_ckandb.sh │ ├── 20_create_datastore.sh │ └── 30_setup_test_databases.sh └── src └── .placeholder /.env.example: -------------------------------------------------------------------------------- 1 | # Host Ports 2 | CKAN_PORT_HOST=5000 3 | NGINX_PORT_HOST=81 4 | NGINX_SSLPORT_HOST=8443 5 | 6 | # CKAN databases 7 | POSTGRES_USER=postgres 8 | POSTGRES_PASSWORD=postgres 9 | POSTGRES_DB=postgres 10 | POSTGRES_HOST=db 11 | CKAN_DB_USER=ckandbuser 12 | CKAN_DB_PASSWORD=ckandbpassword 13 | CKAN_DB=ckandb 14 | DATASTORE_READONLY_USER=datastore_ro 15 | DATASTORE_READONLY_PASSWORD=datastore 16 | DATASTORE_DB=datastore 17 | CKAN_SQLALCHEMY_URL=postgresql://ckandbuser:ckandbpassword@db/ckandb 18 | CKAN_DATASTORE_WRITE_URL=postgresql://ckandbuser:ckandbpassword@db/datastore 19 | CKAN_DATASTORE_READ_URL=postgresql://datastore_ro:datastore@db/datastore 20 | 21 | # Test database connections 22 | TEST_CKAN_SQLALCHEMY_URL=postgres://ckan:ckan@db/ckan_test 23 | TEST_CKAN_DATASTORE_WRITE_URL=postgresql://ckan:ckan@db/datastore_test 24 | TEST_CKAN_DATASTORE_READ_URL=postgresql://datastore_ro:datastore@db/datastore_test 25 | 26 | # Dev settings 27 | USE_HTTPS_FOR_DEV=false 28 | 29 | # CKAN core 30 | CKAN_VERSION=2.10.0 31 | CKAN_SITE_ID=default 32 | CKAN_SITE_URL=https://localhost:8443 33 | CKAN___BEAKER__SESSION__SECRET=CHANGE_ME 34 | # See https://docs.ckan.org/en/latest/maintaining/configuration.html#api-token-settings 35 | CKAN___API_TOKEN__JWT__ENCODE__SECRET=string:CHANGE_ME 36 | CKAN___API_TOKEN__JWT__DECODE__SECRET=string:CHANGE_ME 37 | CKAN_SYSADMIN_NAME=ckan_admin 38 | CKAN_SYSADMIN_PASSWORD=test1234 39 | CKAN_SYSADMIN_EMAIL=your_email@example.com 40 | CKAN_STORAGE_PATH=/var/lib/ckan 41 | CKAN_SMTP_SERVER=smtp.corporateict.domain:25 42 | CKAN_SMTP_STARTTLS=True 43 | CKAN_SMTP_USER=user 44 | CKAN_SMTP_PASSWORD=pass 45 | CKAN_SMTP_MAIL_FROM=ckan@localhost 46 | CKAN_MAX_UPLOAD_SIZE_MB=100 47 | TZ=UTC 48 | 49 | # Solr 50 | SOLR_IMAGE_VERSION=2.10-solr9 51 | CKAN_SOLR_URL=http://solr:8983/solr/ckan 52 | TEST_CKAN_SOLR_URL=http://solr:8983/solr/ckan 53 | 54 | # Redis 55 | REDIS_VERSION=6 56 | CKAN_REDIS_URL=redis://redis:6379/1 57 | TEST_CKAN_REDIS_URL=redis://redis:6379/1 58 | 59 | # Datapusher 60 | DATAPUSHER_VERSION=0.0.21 61 | CKAN_DATAPUSHER_URL=http://datapusher:8800 62 | CKAN__DATAPUSHER__CALLBACK_URL_BASE=http://ckan:5000 63 | 64 | # NGINX 65 | NGINX_PORT=80 66 | NGINX_SSLPORT=443 67 | 68 | # Extensions 69 | CKAN__PLUGINS="image_view text_view datatables_view datastore datapusher envvars" 70 | CKAN__HARVEST__MQ__TYPE=redis 71 | CKAN__HARVEST__MQ__HOSTNAME=redis 72 | CKAN__HARVEST__MQ__PORT=6379 73 | CKAN__HARVEST__MQ__REDIS_DB=1 74 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build CKAN Docker 2 | 3 | on: 4 | # Trigger the workflow on push or pull request, 5 | # but only for the master branch 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Set up Docker Buildx 20 | uses: docker/setup-buildx-action@v1 21 | 22 | - name: Set up QEMU 23 | uses: docker/setup-qemu-action@v1 24 | 25 | - name: NGINX build 26 | uses: docker/build-push-action@v2 27 | with: 28 | context: ./nginx 29 | file: ./nginx/Dockerfile 30 | push: false 31 | tags: kowhai/ckan-docker-nginx:test-build-only 32 | 33 | - name: PostgreSQL build 34 | uses: docker/build-push-action@v2 35 | with: 36 | context: ./postgresql 37 | file: ./postgresql/Dockerfile 38 | push: false 39 | tags: kowhai/ckan-docker-postgresql:test-build-only 40 | 41 | - name: CKAN build 42 | uses: docker/build-push-action@v2 43 | with: 44 | context: ./ckan 45 | file: ./ckan/Dockerfile 46 | push: false 47 | tags: kowhai/ckan-docker-ckan:test-build-only 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # generic 2 | .DS_Store 3 | .vagrant 4 | 5 | # code & config 6 | _service-provider/* 7 | _solr/schema.xml 8 | _src/* 9 | local/* 10 | .env 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker Compose setup for CKAN 2 | 3 | 4 | - [Docker Compose setup for CKAN](#docker-compose-setup-for-ckan) 5 | - [1. Overview](#1--overview) 6 | - [2. Installing Docker](#2--installing-docker) 7 | - [3. docker compose *vs* docker-compose](#3--docker-compose-vs-docker-compose) 8 | - [4. Install (build and run) CKAN plus dependencies](#4--install-build-and-run-ckan-plus-dependencies) 9 | - [Base mode](#base-mode) 10 | - [Development mode](#development-mode) 11 | - [Create an extension](#create-an-extension) 12 | - [Running HTTPS on development mode](#running-https-on-development-mode) 13 | - [Remote Debugging with VS Code](#remote-debugging-with-vs-code) 14 | - [Updating the environment file for development mode](#updating-the-environment-file-for-development-mode) 15 | - [5. CKAN images](#5-ckan-images) 16 | - [Extending the base images](#extending-the-base-images) 17 | - [Applying patches](#applying-patches) 18 | - [_uWSGI_ command line arguments](#uwsgi-command-line-arguments) 19 | - [6. Debugging with pdb](#6-debugging-with-pdb) 20 | - [7. Datastore and datapusher](#7-datastore-and-datapusher) 21 | - [8. NGINX](#8-nginx) 22 | - [9. ckanext-envvars](#9-ckanext-envvars) 23 | - [10. CKAN\_SITE\_URL](#10-ckan_site_url) 24 | - [11. Manage new users](#11-manage-new-users) 25 | - [12. Changing the base image](#12-changing-the-base-image) 26 | - [13. Replacing DataPusher with XLoader](#13-replacing-datapusher-with-xloader) 27 | - [Copying and License](#copying-and-license) 28 | 29 | 30 | ## 1. Overview 31 | 32 | This is a set of configuration and setup files to run a CKAN site. 33 | 34 | The CKAN images used are from the official CKAN [ckan-docker](https://github.com/ckan/ckan-docker-base) repo 35 | 36 | The non-CKAN images are as follows: 37 | 38 | * DataPusher: CKAN's [pre-configured DataPusher image](https://github.com/ckan/ckan-docker-base/tree/main/datapusher). 39 | * PostgreSQL: Official PostgreSQL image. Database files are stored in a named volume. 40 | * Solr: CKAN's [pre-configured Solr image](https://github.com/ckan/ckan-solr). Index data is stored in a named volume. 41 | * Redis: standard Redis image 42 | * NGINX: latest stable nginx image that includes SSL and Non-SSL endpoints 43 | 44 | The site is configured using environment variables that you can set in the `.env` file. 45 | 46 | ## 2. Installing Docker 47 | 48 | Install Docker by following the following instructions: [Install Docker Engine on Ubuntu](https://docs.docker.com/engine/install/ubuntu/) 49 | 50 | To verify a successful Docker installation, run `docker run hello-world` and `docker version`. These commands should output 51 | versions for client and server. 52 | 53 | ## 3. docker compose *vs* docker-compose 54 | 55 | All Docker Compose commands in this README will use the V2 version of Compose ie: `docker compose`. The older version (V1) 56 | used the `docker-compose` command. Please see [Docker Compose](https://docs.docker.com/compose/compose-v2/) for 57 | more information. 58 | 59 | ## 4. Install (build and run) CKAN plus dependencies 60 | 61 | ### Base mode 62 | 63 | Use this if you are a maintainer and will not be making code changes to CKAN or to CKAN extensions 64 | 65 | Copy the included `.env.example` and rename it to `.env`. Modify it depending on your own needs. 66 | 67 | > [!WARNING] 68 | > There is a sysadmin user created by default with the values defined in `CKAN_SYSADMIN_NAME` and `CKAN_SYSADMIN_PASSWORD` (`ckan_admin` and `test1234` by default). These must be changed before running this setup as a public CKAN instance. 69 | 70 | To build the images: 71 | 72 | docker compose build 73 | 74 | To start the containers: 75 | 76 | docker compose up 77 | 78 | This will start up the containers in the current window. By default the containers will log direct to this window with each container 79 | using a different colour. You could also use the -d "detach mode" option ie: `docker compose up -d` if you wished to use the current 80 | window for something else. 81 | 82 | At the end of the container start sequence there should be 6 containers running: 83 | 84 | ```bash 85 | $ docker compose ps 86 | NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS 87 | ckan-docker-ckan-1 ckan-docker-ckan "/srv/app/start_ckan…" ckan 4 minutes ago Up 3 minutes (healthy) 5000/tcp 88 | ckan-docker-datapusher-1 ckan/ckan-base-datapusher:0.0.20 "sh -c 'uwsgi --plug…" datapusher 4 minutes ago Up 4 minutes (healthy) 8800/tcp 89 | ckan-docker-db-1 ckan-docker-db "docker-entrypoint.s…" db 4 minutes ago Up 4 minutes (healthy) 90 | ckan-docker-nginx-1 ckan-docker-nginx "/bin/sh -c 'openssl…" nginx 4 minutes ago Up 2 minutes 80/tcp, 0.0.0.0:8443->443/tcp 91 | ckan-docker-redis-1 redis:6 "docker-entrypoint.s…" redis 4 minutes ago Up 4 minutes (healthy) 92 | ckan-docker-solr-1 ckan/ckan-solr:2.10-solr9 "docker-entrypoint.s…" solr 4 minutes ago Up 4 minutes (healthy) 93 | ``` 94 | 95 | After this step, CKAN should be running at `CKAN_SITE_URL` (by default https://localhost:8443) 96 | 97 | 98 | ### Development mode 99 | 100 | Use this mode if you are making code changes to CKAN and either creating new extensions or making code changes to existing extensions. This mode also uses the `.env` file for config options. 101 | 102 | To develop local extensions use the `docker-compose.dev.yml` file with help from the scripts under `bin`: 103 | 104 | dev script | description 105 | --- | --- 106 | `bin/ckan …` | exec `ckan` cli within the ckan-dev container 107 | `bin/compose …` | dev docker compose commands 108 | `bin/generate_extension` | generate extension in `src` directory 109 | `bin/install_src` | install all extensions from `src` directory (ckan-dev does not need to be running) 110 | `bin/reload` | reload ckan within the ckan-dev container without restarting 111 | `bin/restart` | shut down and restart the whole ckan-dev container (use `bin/compose up -d` instead to reload new values from .env) 112 | `bin/shell` | exec bash prompt within the ckan-dev container 113 | 114 | To build the images: 115 | 116 | bin/compose build 117 | 118 | To install extensions from the `src` directory: 119 | 120 | bin/install_src 121 | 122 | To start the containers: 123 | 124 | bin/compose up 125 | 126 | See [CKAN images](#5-ckan-images) for more details of what happens when using development mode. 127 | 128 | 129 | #### Create an extension 130 | 131 | You can use the ckan [extension](https://docs.ckan.org/en/latest/extensions/tutorial.html#creating-a-new-extension) instructions to create a CKAN extension, only executing the command inside the CKAN container and setting the mounted `src/` folder as output: 132 | 133 | bin/generate_extension 134 | 135 | ``` 136 | Extension's name [must begin 'ckanext-']: ckanext-mytheme 137 | Author's name []: Joe Bloggs 138 | Author's email []: joeb@example.com 139 | Your Github user or organization name []: example 140 | Brief description of the project []: My CKAN theme 141 | List of keywords (separated by spaces) [CKAN]: 142 | Do you want to include code examples? [y/N]: y 143 | 144 | Written: /srv/app/src_extensions/ckanext-mytheme 145 | ``` 146 | 147 | The new extension files and directories are created in the `/srv/app/src_extensions/` folder in the running container. They will also exist in the local src/ directory as local `/src` directory is mounted as `/srv/app/src_extensions/` on the ckan container. 148 | 149 | 150 | #### Running HTTPS on development mode 151 | 152 | Sometimes is useful to run your local development instance under HTTPS, for instance if you are using authentication extensions like [ckanext-saml2auth](https://github.com/keitaroinc/ckanext-saml2auth). To enable it, set the following in your `.env` file: 153 | 154 | ``` 155 | USE_HTTPS_FOR_DEV=true 156 | ``` 157 | 158 | and update the site URL setting: 159 | 160 | ``` 161 | CKAN_SITE_URL=https://localhost:5000 162 | ``` 163 | 164 | After recreating the `ckan-dev` container, you should be able to access CKAN at https://localhost:5000 165 | 166 | 167 | #### Remote Debugging with VS Code 168 | 169 | [Visual Studio Code](https://code.visualstudio.com/) is a free IDE that includes remote 170 | debugging for Python applications. To debug CKAN you must enable `debugpy` for your 171 | development instance in your `.env` file: 172 | 173 | ``` 174 | USE_DEBUGPY_FOR_DEV=true 175 | ``` 176 | 177 | Next run the install script to install debugpy: 178 | 179 | bin/install_src 180 | 181 | Then start the containers in [development mode](#development-mode) and launch VS Code. 182 | 183 | In VS Code: 184 | 185 | 1. Install the "Dev Container" extension: press CTRL+SHIFT+X, type "dev container", click "install" 186 | 2. Click the "Open a Remote Window" button in the bottom-left of the VS Code window 187 | 3. Click "Attach to Running Container..." and select your ckan-dev container, e.g. "ckan-docker-ckan-dev-1" 188 | 4. Click the "Run and Debug" icon on the left panel and choose to install the "Python Debugger" 189 | 5. Click "create a launch.json", select "Python Debugger", "Remote Attach", host "localhost" and port "5678" 190 | 6. Press F5 or click the "Run" menu and "Start Debugging" 191 | 192 | You can now set breakpoints and remote debug your CKAN development instance. 193 | 194 | 195 | #### Updating the environment file for development mode 196 | 197 | The Docker Compose environment `.env` file by default is set up for production mode. There are a few changes needed if you would like to run in Development mode: 198 | 199 | 1. Change the `CKAN_SITE_URL` variable to be: http://localhost:5000 200 | 2. Update the `CKAN__DATAPUSHER__CALLBACK_URL_BASE` variable to use the `ckan-dev` container name: http://ckan-dev:5000 201 | 202 | 203 | ## 5. CKAN images 204 | ![ckan images](https://user-images.githubusercontent.com/54408245/207079416-a01235af-2dea-4425-b6fd-f8c3687dd993.png) 205 | 206 | 207 | 208 | The Docker image config files used to build your CKAN project are located in the `ckan/` folder. There are two Docker files: 209 | 210 | * `Dockerfile`: this is based on `ckan/ckan-base:`, a base image located in the DockerHub repository, that has CKAN installed along with all its dependencies, properly configured and running on [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) (production setup) 211 | * `Dockerfile.dev`: this is based on `ckan/ckan-base:-dev` also located located in the DockerHub repository, and extends `ckan/ckan-base:` to include: 212 | 213 | * Any extension cloned on the `src` folder will be installed in the CKAN container when booting up Docker Compose (`docker compose up`). This includes installing any requirements listed in a `requirements.txt` (or `pip-requirements.txt`) file and running `python setup.py develop`. 214 | * CKAN is started running this: `/usr/bin/ckan -c /srv/app/ckan.ini run -H 0.0.0.0`. 215 | * Make sure to add the local plugins to the `CKAN__PLUGINS` env var in the `.env` file. 216 | 217 | * Any custom changes to the scripts run during container start up can be made to scripts in the `setup/` directory. For instance if you wanted to change the port on which CKAN runs you would need to make changes to the Docker Compose yaml file, and the `start_ckan.sh.override` file. Then you would need to add the following line to the Dockerfile ie: `COPY setup/start_ckan.sh.override ${APP_DIR}/start_ckan.sh`. The `start_ckan.sh` file in the locally built image would override the `start_ckan.sh` file included in the base image 218 | 219 | ### Extending the base images 220 | 221 | The CKAN base images are built from https://github.com/ckan/ckan-docker-base/ 222 | 223 | You can modify the docker files to build your own customized image tailored to your project, installing any extensions and extra requirements needed. For example here is where you would update to use a different CKAN base image ie: `ckan/ckan-base:` 224 | 225 | To perform extra initialization steps you can add scripts to your custom images and copy them to the `/docker-entrypoint.d` folder (The folder should be created for you when you build the image). Any `*.sh` and `*.py` file in that folder will be executed just after the main initialization script ([`prerun.py`](https://github.com/ckan/ckan-docker-base/blob/main/ckan-2.9/base/setup/prerun.py)) is executed and just before the web server and supervisor processes are started. 226 | 227 | For instance, consider the following custom image: 228 | 229 | ``` 230 | ckan 231 | ├── docker-entrypoint.d 232 | │ └── setup_validation.sh 233 | ├── Dockerfile 234 | └── Dockerfile.dev 235 | 236 | ``` 237 | 238 | We want to install an extension like [ckanext-validation](https://github.com/frictionlessdata/ckanext-validation) that needs to create database tables on startup time. We create a `setup_validation.sh` script in a `docker-entrypoint.d` folder with the necessary commands: 239 | 240 | ```bash 241 | #!/bin/bash 242 | 243 | # Create DB tables if not there 244 | ckan -c /srv/app/ckan.ini validation init-db 245 | ``` 246 | 247 | And then in our `Dockerfile.dev` file we install the extension and copy the initialization scripts: 248 | 249 | ```Dockerfile 250 | FROM ckan/ckan-base:2.9.7-dev 251 | 252 | RUN pip install -e git+https://github.com/frictionlessdata/ckanext-validation.git#egg=ckanext-validation && \ 253 | pip install -r https://raw.githubusercontent.com/frictionlessdata/ckanext-validation/master/requirements.txt 254 | 255 | COPY docker-entrypoint.d/* /docker-entrypoint.d/ 256 | ``` 257 | 258 | NB: There are a number of extension examples commented out in the Dockerfile.dev file 259 | 260 | ### Applying patches 261 | 262 | When building your project specific CKAN images (the ones defined in the `ckan/` folder), you can apply patches 263 | to CKAN core or any of the built extensions. To do so create a folder inside `ckan/patches` with the name of the 264 | package to patch (ie `ckan` or `ckanext-??`). Inside you can place patch files that will be applied when building 265 | the images. The patches will be applied in alphabetical order, so you can prefix them sequentially if necessary. 266 | 267 | For instance, check the following example image folder: 268 | 269 | ``` 270 | ckan 271 | ├── patches 272 | │ ├── ckan 273 | │ │ ├── 01_datasets_per_page.patch 274 | │ │ ├── 02_groups_per_page.patch 275 | │ │ ├── 03_or_filters.patch 276 | │ └── ckanext-harvest 277 | │ └── 01_resubmit_objects.patch 278 | ├── setup 279 | ├── Dockerfile 280 | └── Dockerfile.dev 281 | ``` 282 | 283 | ### _uWSGI_ command line arguments 284 | 285 | The images use the application server [_uWSGI_](https://uwsgi-docs.readthedocs.io/en/latest/) to run _CKAN_. There are two environment variables, that allow to configure _uWSGI_ using [command line arguments](https://uwsgi-docs.readthedocs.io/en/latest/Configuration.html#command-line-arguments). The available options are described [here](https://uwsgi-docs.readthedocs.io/en/latest/Options.html). 286 | 287 | For most use cases, the defaults specified in `ckan-X.XX/setup/start_ckan.sh` in `DEFAULT_UWSGI_OPTS` of the [ckan/ckan-docker-base](https://github.com/ckan/ckan-docker-base) image are fine. If required, you can either _overwrite_ the defaults or _append_ additional arguments. 288 | 289 | | Variable | Description | Defaults | 290 | |:--------------------|:------------------------------------------------------| :------------------| 291 | | `UWSGI_OPTS` | If set, overwrites `DEFAULT_UWSGI_OPTS`. If not set, `UWSGI_OPTS` will bet set to `DEFAULT_UWSGI_OPTS`. | unset | 292 | | `EXTRA_UWSGI_OPTS` | If set, appends its content to `UWSGI_OPTS`. | unset | 293 | 294 | > [!IMPORTANT] 295 | > These setting **do not** apply for the dev images. 296 | 297 | 298 | ## 6. Debugging with pdb 299 | 300 | Add these lines to the `ckan-dev` service in the docker-compose.dev.yml file 301 | 302 | ```yaml 303 | stdin_open: true 304 | tty: true 305 | ``` 306 | 307 | Debug with pdb (example) - Interact with `docker attach $(docker container ls -qf name=ckan)` 308 | 309 | command: `python -m pdb /usr/lib/ckan/venv/bin/ckan --config /srv/app/ckan.ini run --host 0.0.0.0 --passthrough-errors` 310 | 311 | ## 7. Datastore and datapusher 312 | 313 | The Datastore database and user is created as part of the entrypoint scripts for the db container. There is also a Datapusher container 314 | running the latest version of Datapusher. 315 | 316 | ## 8. NGINX 317 | 318 | The base Docker Compose configuration uses an NGINX image as the front-end (ie: reverse proxy). It includes HTTPS running on port number 8443. A "self-signed" SSL certificate is generated as part of the ENTRYPOINT. 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. 319 | 320 | Creating the SSL cert and key files as follows: 321 | `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` 322 | The `ckan-local.*` files will then need to be moved into the nginx/setup/ directory 323 | 324 | ## 9. ckanext-envvars 325 | 326 | The ckanext-envvars extension is used in the CKAN Docker base repo to build the base images. 327 | This extension checks for environmental variables conforming to an expected format and updates the corresponding CKAN config settings with its value. 328 | 329 | For the extension to correctly identify which env var keys map to the format used for the config object, env var keys should be formatted in the following way: 330 | 331 | All uppercase 332 | Replace periods ('.') with two underscores ('__') 333 | Keys must begin with 'CKAN' or 'CKANEXT', if they do not you can prepend them with '`CKAN___`' 334 | 335 | For example: 336 | 337 | * `CKAN__PLUGINS="envvars image_view text_view recline_view datastore datapusher"` 338 | * `CKAN__DATAPUSHER__CALLBACK_URL_BASE=http://ckan:5000` 339 | * `CKAN___BEAKER__SESSION__SECRET=CHANGE_ME` 340 | 341 | These parameters can be added to the `.env` file 342 | 343 | For more information please see [ckanext-envvars](https://github.com/okfn/ckanext-envvars) 344 | 345 | ## 10. CKAN_SITE_URL 346 | 347 | For convenience the CKAN_SITE_URL parameter should be set in the .env file. For development it can be set to http://localhost:5000 and non-development set to https://localhost:8443 348 | 349 | ## 11. Manage new users 350 | 351 | 1. Create a new user from the Docker host, for example to create a new user called 'admin' 352 | 353 | `docker compose exec ckan ckan user add admin email=admin@localhost` 354 | 355 | To set this user as a sysadmin run 356 | 357 | `docker compose exec ckan ckan sysadmin add admin` 358 | 359 | To delete the 'admin' user 360 | 361 | `docker compose exec ckan ckan user remove admin` 362 | 363 | In development mode use `bin/ckan` instead of `docker compose exec ckan ckan` for the above commands. 364 | 365 | 366 | ## 12. Changing the base image 367 | 368 | The base image used in the CKAN Dockerfile and Dockerfile.dev can be changed so a different DockerHub image is used eg: ckan/ckan-base:2.10.5 can be used instead of ckan/ckan-base:2.11.0 369 | 370 | ## 13. Replacing DataPusher with XLoader 371 | 372 | Check out the wiki page for this: https://github.com/ckan/ckan-docker/wiki/Replacing-DataPusher-with-XLoader 373 | 374 | Copying and License 375 | ------------------- 376 | 377 | This material is copyright (c) 2006-2023 Open Knowledge Foundation and contributors. 378 | 379 | It is open and licensed under the GNU Affero General Public License (AGPL) v3.0 380 | whose full text may be found at: 381 | 382 | http://www.fsf.org/licensing/licenses/agpl-3.0.html 383 | -------------------------------------------------------------------------------- /bin/ckan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ROOT="$(dirname ${BASH_SOURCE[0]})/.." 5 | 6 | docker compose -f "${ROOT}/docker-compose.dev.yml" exec ckan-dev ckan "$@" 7 | -------------------------------------------------------------------------------- /bin/compose: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ROOT="$(dirname ${BASH_SOURCE[0]})/.." 5 | 6 | docker compose -f "${ROOT}/docker-compose.dev.yml" "$@" 7 | -------------------------------------------------------------------------------- /bin/generate_extension: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ROOT="$(dirname ${BASH_SOURCE[0]})/.." 5 | if [[ "$(uname)" == "Darwin" ]]; then 6 | # macOS 7 | USERGROUP="$(stat -f '%u:%g' "${ROOT}/src")" 8 | else 9 | USERGROUP="$(stat -c '%u:%g' "${ROOT}/src")" 10 | fi 11 | 12 | docker compose -f "${ROOT}/docker-compose.dev.yml" exec -u "$USERGROUP" \ 13 | -e HOME=/srv/app/src_extensions ckan-dev ckan generate extension \ 14 | --output-dir /srv/app/src_extensions 15 | -------------------------------------------------------------------------------- /bin/install_src: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ROOT="$(dirname ${BASH_SOURCE[0]})/.." 5 | 6 | docker compose -f "${ROOT}/docker-compose.dev.yml" run -u root ckan-dev ./install_src.sh 7 | -------------------------------------------------------------------------------- /bin/reload: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ROOT="$(dirname ${BASH_SOURCE[0]})/.." 5 | 6 | docker compose -f "${ROOT}/docker-compose.dev.yml" exec ckan-dev \ 7 | bash -c 'kill $(ls -l /proc/*/exe | grep bin/python | grep -Po '"'"'/proc/\K[^/]*'"'"')' 8 | -------------------------------------------------------------------------------- /bin/restart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ROOT="$(dirname ${BASH_SOURCE[0]})/.." 5 | 6 | docker compose -f "${ROOT}/docker-compose.dev.yml" restart ckan-dev 7 | -------------------------------------------------------------------------------- /bin/shell: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | ROOT="$(dirname ${BASH_SOURCE[0]})/.." 5 | 6 | docker compose -f "${ROOT}/docker-compose.dev.yml" exec ckan-dev bash "$@" 7 | -------------------------------------------------------------------------------- /ckan/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ckan/ckan-base:2.11 2 | 3 | # Install any extensions needed by your CKAN instance 4 | # See Dockerfile.dev for more details and examples 5 | 6 | # Copy custom initialization scripts 7 | COPY --chown=ckan-sys:ckan-sys docker-entrypoint.d/* /docker-entrypoint.d/ 8 | 9 | # Apply any patches needed to CKAN core or any of the built extensions (not the 10 | # runtime mounted ones) 11 | COPY --chown=ckan-sys:ckan-sys patches ${APP_DIR}/patches 12 | 13 | USER ckan 14 | 15 | RUN for d in $APP_DIR/patches/*; do \ 16 | if [ -d $d ]; then \ 17 | for f in `ls $d/*.patch | sort -g`; do \ 18 | cd $SRC_DIR/`basename "$d"` && echo "$0: Applying patch $f to $SRC_DIR/`basename $d`"; patch -p1 < "$f" ; \ 19 | done ; \ 20 | fi ; \ 21 | done 22 | -------------------------------------------------------------------------------- /ckan/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM ckan/ckan-dev:2.11 2 | 3 | # Install any extensions needed by your CKAN instance 4 | # - Make sure to add the plugins to CKAN__PLUGINS in the .env file 5 | # - Also make sure all provide all extra configuration options, either by: 6 | # * Adding them to the .env file (check the ckanext-envvars syntax for env vars), or 7 | # * Adding extra configuration scripts to /docker-entrypoint.d folder) to update 8 | # the CKAN config file (ckan.ini) with the `ckan config-tool` command 9 | # 10 | # See README > Extending the base images for more details 11 | # 12 | # For instance: 13 | # 14 | ### XLoader ### 15 | #RUN pip3 install -e 'git+https://github.com/ckan/ckanext-xloader.git@master#egg=ckanext-xloader' && \ 16 | # pip3 install -r ${APP_DIR}/src/ckanext-xloader/requirements.txt && \ 17 | # pip3 install -U requests[security] 18 | 19 | ### Harvester ### 20 | #RUN pip3 install -e 'git+https://github.com/ckan/ckanext-harvest.git@master#egg=ckanext-harvest' && \ 21 | # pip3 install -r ${APP_DIR}/src/ckanext-harvest/pip-requirements.txt 22 | # will also require gather_consumer and fetch_consumer processes running (please see https://github.com/ckan/ckanext-harvest) 23 | 24 | ### Scheming ### 25 | #RUN pip3 install -e 'git+https://github.com/ckan/ckanext-scheming.git@master#egg=ckanext-scheming' 26 | 27 | ### Pages ### 28 | #RUN pip3 install -e git+https://github.com/ckan/ckanext-pages.git#egg=ckanext-pages 29 | 30 | ### DCAT ### 31 | #RUN pip3 install -e git+https://github.com/ckan/ckanext-dcat.git@v0.0.6#egg=ckanext-dcat && \ 32 | # pip3 install -r https://raw.githubusercontent.com/ckan/ckanext-dcat/v0.0.6/requirements.txt 33 | 34 | # Clone the extension(s) your are writing for your own project in the `src` folder 35 | # to get them mounted in this image at runtime 36 | 37 | # Copy custom initialization scripts 38 | COPY --chown=ckan-sys:ckan-sys docker-entrypoint.d/* /docker-entrypoint.d/ 39 | 40 | # Apply any patches needed to CKAN core or any of the built extensions (not the 41 | # runtime mounted ones) 42 | COPY --chown=ckan-sys:ckan-sys patches ${APP_DIR}/patches 43 | 44 | USER ckan 45 | 46 | RUN for d in $APP_DIR/patches/*; do \ 47 | if [ -d $d ]; then \ 48 | for f in `ls $d/*.patch | sort -g`; do \ 49 | cd $SRC_DIR/`basename "$d"` && echo "$0: Applying patch $f to $SRC_DIR/`basename $d`"; patch -p1 < "$f" ; \ 50 | done ; \ 51 | fi ; \ 52 | done 53 | -------------------------------------------------------------------------------- /ckan/docker-entrypoint.d/01_setup_datapusher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $CKAN__PLUGINS == *"datapusher"* ]]; then 4 | # Datapusher settings have been configured in the .env file 5 | # Set API token if necessary 6 | if [ -z "$CKAN__DATAPUSHER__API_TOKEN" ] ; then 7 | echo "Set up ckan.datapusher.api_token in the CKAN config file" 8 | ckan config-tool $CKAN_INI "ckan.datapusher.api_token=$(ckan -c $CKAN_INI user token add ckan_admin datapusher | tail -n 1 | tr -d '\t')" 9 | fi 10 | else 11 | echo "Not configuring DataPusher" 12 | fi 13 | -------------------------------------------------------------------------------- /ckan/docker-entrypoint.d/README.md: -------------------------------------------------------------------------------- 1 | Use scripts in this folder to run extra initialization steps in your custom CKAN images. 2 | Any file with `.sh` or `.py` extension will be executed just after the main initialization 3 | script (`prerun.py`) is executed and just before the web server and supervisor processes are 4 | started. 5 | -------------------------------------------------------------------------------- /ckan/patches/00_test_test.patch: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /ckan/setup/prerun.py.override: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import subprocess 4 | import psycopg2 5 | try: 6 | from urllib.request import urlopen 7 | from urllib.error import URLError 8 | except ImportError: 9 | from urllib2 import urlopen 10 | from urllib2 import URLError 11 | 12 | import time 13 | import re 14 | import json 15 | 16 | ckan_ini = os.environ.get("CKAN_INI", "/srv/app/ckan.ini") 17 | 18 | RETRY = 5 19 | 20 | 21 | def update_plugins(): 22 | 23 | plugins = os.environ.get("CKAN__PLUGINS", "") 24 | print(("[prerun] Setting the following plugins in {}:".format(ckan_ini))) 25 | print(plugins) 26 | cmd = ["ckan", "config-tool", ckan_ini, "ckan.plugins = {}".format(plugins)] 27 | subprocess.check_output(cmd, stderr=subprocess.STDOUT) 28 | print("[prerun] Plugins set.") 29 | 30 | 31 | def check_main_db_connection(retry=None): 32 | 33 | conn_str = os.environ.get("CKAN_SQLALCHEMY_URL") 34 | if not conn_str: 35 | print("[prerun] CKAN_SQLALCHEMY_URL not defined, not checking db") 36 | return check_db_connection(conn_str, retry) 37 | 38 | 39 | def check_datastore_db_connection(retry=None): 40 | 41 | conn_str = os.environ.get("CKAN_DATASTORE_WRITE_URL") 42 | if not conn_str: 43 | print("[prerun] CKAN_DATASTORE_WRITE_URL not defined, not checking db") 44 | return check_db_connection(conn_str, retry) 45 | 46 | 47 | def check_db_connection(conn_str, retry=None): 48 | 49 | if retry is None: 50 | retry = RETRY 51 | elif retry == 0: 52 | print("[prerun] Giving up after 5 tries...") 53 | sys.exit(1) 54 | 55 | try: 56 | connection = psycopg2.connect(conn_str) 57 | 58 | except psycopg2.Error as e: 59 | print(str(e)) 60 | print("[prerun] Unable to connect to the database, waiting...") 61 | time.sleep(10) 62 | check_db_connection(conn_str, retry=retry - 1) 63 | else: 64 | connection.close() 65 | 66 | 67 | def check_solr_connection(retry=None): 68 | 69 | if retry is None: 70 | retry = RETRY 71 | elif retry == 0: 72 | print("[prerun] Giving up after 5 tries...") 73 | sys.exit(1) 74 | 75 | url = os.environ.get("CKAN_SOLR_URL", "") 76 | search_url = '{url}/schema/name?wt=json'.format(url=url) 77 | 78 | try: 79 | connection = urlopen(search_url) 80 | except URLError as e: 81 | print(str(e)) 82 | print("[prerun] Unable to connect to solr, waiting...") 83 | time.sleep(10) 84 | check_solr_connection(retry=retry - 1) 85 | else: 86 | import re 87 | conn_info = connection.read() 88 | schema_name = json.loads(conn_info) 89 | if 'ckan' in schema_name['name']: 90 | print('[prerun] Succesfully connected to solr and CKAN schema loaded') 91 | else: 92 | print('[prerun] Succesfully connected to solr, but CKAN schema not found') 93 | 94 | 95 | def init_db(): 96 | 97 | db_command = ["ckan", "-c", ckan_ini, "db", "init"] 98 | print("[prerun] Initializing or upgrading db - start") 99 | try: 100 | subprocess.check_output(db_command, stderr=subprocess.STDOUT) 101 | print("[prerun] Initializing or upgrading db - end") 102 | except subprocess.CalledProcessError as e: 103 | if "OperationalError" in e.output: 104 | print(e.output) 105 | print("[prerun] Database not ready, waiting a bit before exit...") 106 | time.sleep(5) 107 | sys.exit(1) 108 | else: 109 | print(e.output) 110 | raise e 111 | 112 | 113 | def init_datastore_db(): 114 | 115 | conn_str = os.environ.get("CKAN_DATASTORE_WRITE_URL") 116 | if not conn_str: 117 | print("[prerun] Skipping datastore initialization") 118 | return 119 | 120 | datastore_perms_command = ["ckan", "-c", ckan_ini, "datastore", "set-permissions"] 121 | 122 | connection = psycopg2.connect(conn_str) 123 | cursor = connection.cursor() 124 | 125 | print("[prerun] Initializing datastore db - start") 126 | try: 127 | datastore_perms = subprocess.Popen( 128 | datastore_perms_command, stdout=subprocess.PIPE 129 | ) 130 | 131 | perms_sql = datastore_perms.stdout.read() 132 | # Remove internal pg command as psycopg2 does not like it 133 | perms_sql = re.sub(b'\\\\connect "(.*)"', b"", perms_sql) 134 | cursor.execute(perms_sql) 135 | for notice in connection.notices: 136 | print(notice) 137 | 138 | connection.commit() 139 | 140 | print("[prerun] Initializing datastore db - end") 141 | print(datastore_perms.stdout.read()) 142 | except psycopg2.Error as e: 143 | print("[prerun] Could not initialize datastore") 144 | print(str(e)) 145 | 146 | except subprocess.CalledProcessError as e: 147 | if "OperationalError" in e.output: 148 | print(e.output) 149 | print("[prerun] Database not ready, waiting a bit before exit...") 150 | time.sleep(5) 151 | sys.exit(1) 152 | else: 153 | print(e.output) 154 | raise e 155 | finally: 156 | cursor.close() 157 | connection.close() 158 | 159 | 160 | def create_sysadmin(): 161 | 162 | name = os.environ.get("CKAN_SYSADMIN_NAME") 163 | password = os.environ.get("CKAN_SYSADMIN_PASSWORD") 164 | email = os.environ.get("CKAN_SYSADMIN_EMAIL") 165 | 166 | if name and password and email: 167 | 168 | # Check if user exists 169 | command = ["ckan", "-c", ckan_ini, "user", "show", name] 170 | 171 | out = subprocess.check_output(command) 172 | if b"User:None" not in re.sub(b"\s", b"", out): 173 | print("[prerun] Sysadmin user exists, skipping creation") 174 | return 175 | 176 | # Create user 177 | command = [ 178 | "ckan", 179 | "-c", 180 | ckan_ini, 181 | "user", 182 | "add", 183 | name, 184 | "password=" + password, 185 | "email=" + email, 186 | ] 187 | 188 | subprocess.call(command) 189 | print("[prerun] Created user {0}".format(name)) 190 | 191 | # Make it sysadmin 192 | command = ["ckan", "-c", ckan_ini, "sysadmin", "add", name] 193 | 194 | subprocess.call(command) 195 | print("[prerun] Made user {0} a sysadmin".format(name)) 196 | 197 | 198 | if __name__ == "__main__": 199 | 200 | maintenance = os.environ.get("MAINTENANCE_MODE", "").lower() == "true" 201 | 202 | if maintenance: 203 | print("[prerun] Maintenance mode, skipping setup...") 204 | else: 205 | check_main_db_connection() 206 | init_db() 207 | update_plugins() 208 | check_datastore_db_connection() 209 | init_datastore_db() 210 | check_solr_connection() 211 | create_sysadmin() 212 | -------------------------------------------------------------------------------- /ckan/setup/start_ckan.sh.override: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Add ckan.datapusher.api_token to the CKAN config file (updated with corrected value later) 4 | ckan config-tool $CKAN_INI ckan.datapusher.api_token=xxx 5 | 6 | # Set up the Secret key used by Beaker and Flask 7 | # This can be overriden using a CKAN___BEAKER__SESSION__SECRET env var 8 | if grep -E "beaker.session.secret ?= ?$" ckan.ini 9 | then 10 | echo "Setting beaker.session.secret in ini file" 11 | ckan config-tool $CKAN_INI "beaker.session.secret=$(python3 -c 'import secrets; print(secrets.token_urlsafe())')" 12 | ckan config-tool $CKAN_INI "WTF_CSRF_SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_urlsafe())')" 13 | JWT_SECRET=$(python3 -c 'import secrets; print("string:" + secrets.token_urlsafe())') 14 | ckan config-tool $CKAN_INI "api_token.jwt.encode.secret=${JWT_SECRET}" 15 | ckan config-tool $CKAN_INI "api_token.jwt.decode.secret=${JWT_SECRET}" 16 | fi 17 | 18 | # Run the prerun script to init CKAN and create the default admin user 19 | sudo -u ckan -EH python3 prerun.py 20 | 21 | echo "Set up ckan.datapusher.api_token in the CKAN config file" 22 | ckan config-tool $CKAN_INI "ckan.datapusher.api_token=$(ckan -c $CKAN_INI user token add ckan_admin datapusher | tail -n 1 | tr -d '\t')" 23 | 24 | # Run any startup scripts provided by images extending this one 25 | if [[ -d "/docker-entrypoint.d" ]] 26 | then 27 | for f in /docker-entrypoint.d/*; do 28 | case "$f" in 29 | *.sh) echo "$0: Running init file $f"; . "$f" ;; 30 | *.py) echo "$0: Running init file $f"; python3 "$f"; echo ;; 31 | *) echo "$0: Ignoring $f (not an sh or py file)" ;; 32 | esac 33 | echo 34 | done 35 | fi 36 | 37 | # Set the common uwsgi options 38 | UWSGI_OPTS="--plugins http,python \ 39 | --socket /tmp/uwsgi.sock \ 40 | --wsgi-file /srv/app/wsgi.py \ 41 | --module wsgi:application \ 42 | --uid 92 --gid 92 \ 43 | --http 0.0.0.0:5000 \ 44 | --master --enable-threads \ 45 | --lazy-apps \ 46 | -p 2 -L -b 32768 --vacuum \ 47 | --harakiri $UWSGI_HARAKIRI" 48 | 49 | if [ $? -eq 0 ] 50 | then 51 | # Start supervisord 52 | supervisord --configuration /etc/supervisord.conf & 53 | # Start uwsgi 54 | sudo -u ckan -EH uwsgi $UWSGI_OPTS 55 | else 56 | echo "[prerun] failed...not starting CKAN." 57 | fi 58 | -------------------------------------------------------------------------------- /ckan/setup/start_ckan_development.sh.override: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Install any local extensions in the src_extensions volume 4 | echo "Looking for local extensions to install..." 5 | echo "Extension dir contents:" 6 | ls -la $SRC_EXTENSIONS_DIR 7 | for i in $SRC_EXTENSIONS_DIR/* 8 | do 9 | if [ -d $i ]; 10 | then 11 | 12 | if [ -f $i/pip-requirements.txt ]; 13 | then 14 | pip install -r $i/pip-requirements.txt 15 | echo "Found requirements file in $i" 16 | fi 17 | if [ -f $i/requirements.txt ]; 18 | then 19 | pip install -r $i/requirements.txt 20 | echo "Found requirements file in $i" 21 | fi 22 | if [ -f $i/dev-requirements.txt ]; 23 | then 24 | pip install -r $i/dev-requirements.txt 25 | echo "Found dev-requirements file in $i" 26 | fi 27 | if [ -f $i/setup.py ]; 28 | then 29 | cd $i 30 | python3 $i/setup.py develop 31 | echo "Found setup.py file in $i" 32 | cd $APP_DIR 33 | fi 34 | 35 | # Point `use` in test.ini to location of `test-core.ini` 36 | if [ -f $i/test.ini ]; 37 | then 38 | echo "Updating \`test.ini\` reference to \`test-core.ini\` for plugin $i" 39 | ckan config-tool $i/test.ini "use = config:../../src/ckan/test-core.ini" 40 | fi 41 | fi 42 | done 43 | 44 | # Set debug to true 45 | echo "Enabling debug mode" 46 | ckan config-tool $CKAN_INI -s DEFAULT "debug = true" 47 | 48 | # Add ckan.datapusher.api_token to the CKAN config file (updated with corrected value later) 49 | ckan config-tool $CKAN_INI ckan.datapusher.api_token=xxx 50 | 51 | # Set up the Secret key used by Beaker and Flask 52 | # This can be overriden using a CKAN___BEAKER__SESSION__SECRET env var 53 | if grep -E "beaker.session.secret ?= ?$" ckan.ini 54 | then 55 | echo "Setting beaker.session.secret in ini file" 56 | ckan config-tool $CKAN_INI "beaker.session.secret=$(python3 -c 'import secrets; print(secrets.token_urlsafe())')" 57 | ckan config-tool $CKAN_INI "WTF_CSRF_SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_urlsafe())')" 58 | JWT_SECRET=$(python3 -c 'import secrets; print("string:" + secrets.token_urlsafe())') 59 | ckan config-tool $CKAN_INI "api_token.jwt.encode.secret=${JWT_SECRET}" 60 | ckan config-tool $CKAN_INI "api_token.jwt.decode.secret=${JWT_SECRET}" 61 | fi 62 | 63 | # Update the plugins setting in the ini file with the values defined in the env var 64 | echo "Loading the following plugins: $CKAN__PLUGINS" 65 | ckan config-tool $CKAN_INI "ckan.plugins = $CKAN__PLUGINS" 66 | 67 | # Update test-core.ini DB, SOLR & Redis settings 68 | echo "Loading test settings into test-core.ini" 69 | ckan config-tool $SRC_DIR/ckan/test-core.ini \ 70 | "sqlalchemy.url = $TEST_CKAN_SQLALCHEMY_URL" \ 71 | "ckan.datastore.write_url = $TEST_CKAN_DATASTORE_WRITE_URL" \ 72 | "ckan.datastore.read_url = $TEST_CKAN_DATASTORE_READ_URL" \ 73 | "solr_url = $TEST_CKAN_SOLR_URL" \ 74 | "ckan.redis.url = $TEST_CKAN_REDIS_URL" 75 | 76 | # Run the prerun script to init CKAN and create the default admin user 77 | sudo -u ckan -EH python3 prerun.py 78 | 79 | echo "Set up ckan.datapusher.api_token in the CKAN config file" 80 | ckan config-tool $CKAN_INI "ckan.datapusher.api_token=$(ckan -c $CKAN_INI user token add ckan_admin datapusher | tail -n 1 | tr -d '\t')" 81 | 82 | # Run any startup scripts provided by images extending this one 83 | if [[ -d "/docker-entrypoint.d" ]] 84 | then 85 | for f in /docker-entrypoint.d/*; do 86 | case "$f" in 87 | *.sh) echo "$0: Running init file $f"; . "$f" ;; 88 | *.py) echo "$0: Running init file $f"; python3 "$f"; echo ;; 89 | *) echo "$0: Ignoring $f (not an sh or py file)" ;; 90 | esac 91 | echo 92 | done 93 | fi 94 | 95 | # Start supervisord 96 | supervisord --configuration /etc/supervisord.conf & 97 | 98 | # Start the development server with automatic reload 99 | sudo -u ckan -EH ckan -c $CKAN_INI run -H 0.0.0.0 -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | volumes: 2 | ckan_storage: 3 | pg_data: 4 | solr_data: 5 | pip_cache: 6 | site_packages: 7 | local_bin: 8 | home_dir: 9 | 10 | services: 11 | 12 | ckan-dev: 13 | build: 14 | context: ckan/ 15 | dockerfile: Dockerfile.dev 16 | args: 17 | - TZ=${TZ} 18 | env_file: 19 | - .env 20 | links: 21 | - db 22 | - solr 23 | - redis 24 | ports: 25 | - "0.0.0.0:${CKAN_PORT_HOST}:5000" 26 | volumes: 27 | - ckan_storage:/var/lib/ckan 28 | - ./src:/srv/app/src_extensions 29 | - pip_cache:/root/.cache/pip 30 | - site_packages:/usr/local/lib/python3.10/site-packages 31 | - local_bin:/usr/local/bin 32 | - home_dir:/srv/app/ 33 | restart: unless-stopped 34 | healthcheck: 35 | test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5000"] 36 | interval: 60s 37 | timeout: 10s 38 | retries: 3 39 | 40 | datapusher: 41 | image: ckan/ckan-base-datapusher:${DATAPUSHER_VERSION} 42 | restart: unless-stopped 43 | healthcheck: 44 | test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:8800"] 45 | interval: 60s 46 | timeout: 10s 47 | retries: 3 48 | 49 | db: 50 | build: 51 | context: postgresql/ 52 | environment: 53 | - POSTGRES_USER 54 | - POSTGRES_PASSWORD 55 | - POSTGRES_DB 56 | - CKAN_DB_USER 57 | - CKAN_DB_PASSWORD 58 | - CKAN_DB 59 | - DATASTORE_READONLY_USER 60 | - DATASTORE_READONLY_PASSWORD 61 | - DATASTORE_DB 62 | volumes: 63 | - pg_data:/var/lib/postgresql/data 64 | restart: unless-stopped 65 | healthcheck: 66 | test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}", "-d", "${POSTGRES_DB}"] 67 | 68 | solr: 69 | image: ckan/ckan-solr:${SOLR_IMAGE_VERSION} 70 | volumes: 71 | - solr_data:/var/solr 72 | restart: unless-stopped 73 | healthcheck: 74 | test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:8983/solr/"] 75 | 76 | redis: 77 | image: redis:${REDIS_VERSION} 78 | restart: unless-stopped 79 | healthcheck: 80 | test: ["CMD", "redis-cli", "-e", "QUIT"] 81 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | volumes: 2 | ckan_storage: 3 | pg_data: 4 | solr_data: 5 | pip_cache: 6 | site_packages: 7 | 8 | services: 9 | 10 | nginx: 11 | build: 12 | context: nginx/ 13 | dockerfile: Dockerfile 14 | networks: 15 | - webnet 16 | - ckannet 17 | depends_on: 18 | ckan: 19 | condition: service_healthy 20 | ports: 21 | - "0.0.0.0:${NGINX_SSLPORT_HOST}:${NGINX_SSLPORT}" 22 | 23 | ckan: 24 | build: 25 | context: ckan/ 26 | dockerfile: Dockerfile 27 | args: 28 | - TZ=${TZ} 29 | networks: 30 | - ckannet 31 | - dbnet 32 | - solrnet 33 | - redisnet 34 | env_file: 35 | - .env 36 | depends_on: 37 | db: 38 | condition: service_healthy 39 | solr: 40 | condition: service_healthy 41 | redis: 42 | condition: service_healthy 43 | volumes: 44 | - ckan_storage:/var/lib/ckan 45 | - pip_cache:/root/.cache/pip 46 | - site_packages:/usr/lib/python3.10/site-packages 47 | restart: unless-stopped 48 | healthcheck: 49 | test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5000/api/action/status_show"] 50 | interval: 60s 51 | timeout: 10s 52 | retries: 3 53 | 54 | datapusher: 55 | networks: 56 | - ckannet 57 | - dbnet 58 | image: ckan/ckan-base-datapusher:${DATAPUSHER_VERSION} 59 | restart: unless-stopped 60 | healthcheck: 61 | test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:8800"] 62 | interval: 60s 63 | timeout: 10s 64 | retries: 3 65 | 66 | db: 67 | build: 68 | context: postgresql/ 69 | networks: 70 | - dbnet 71 | environment: 72 | - POSTGRES_USER 73 | - POSTGRES_PASSWORD 74 | - POSTGRES_DB 75 | - CKAN_DB_USER 76 | - CKAN_DB_PASSWORD 77 | - CKAN_DB 78 | - DATASTORE_READONLY_USER 79 | - DATASTORE_READONLY_PASSWORD 80 | - DATASTORE_DB 81 | volumes: 82 | - pg_data:/var/lib/postgresql/data 83 | restart: unless-stopped 84 | healthcheck: 85 | test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER}", "-d", "${POSTGRES_DB}"] 86 | 87 | solr: 88 | networks: 89 | - solrnet 90 | image: ckan/ckan-solr:${SOLR_IMAGE_VERSION} 91 | volumes: 92 | - solr_data:/var/solr 93 | restart: unless-stopped 94 | healthcheck: 95 | test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:8983/solr/"] 96 | 97 | redis: 98 | image: redis:${REDIS_VERSION} 99 | networks: 100 | - redisnet 101 | restart: unless-stopped 102 | healthcheck: 103 | test: ["CMD", "redis-cli", "-e", "QUIT"] 104 | 105 | networks: 106 | webnet: 107 | ckannet: 108 | solrnet: 109 | internal: true 110 | dbnet: 111 | internal: true 112 | redisnet: 113 | internal: true 114 | -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:stable-alpine 2 | 3 | ENV NGINX_DIR=/etc/nginx 4 | 5 | RUN apk update --no-cache && \ 6 | apk upgrade --no-cache && \ 7 | apk add --no-cache openssl 8 | 9 | COPY setup/nginx.conf ${NGINX_DIR}/nginx.conf 10 | COPY setup/index.html /usr/share/nginx/html/index.html 11 | COPY setup/error.html /usr/share/nginx/html/error.html 12 | COPY setup/default.conf ${NGINX_DIR}/conf.d/ 13 | 14 | RUN mkdir -p ${NGINX_DIR}/certs 15 | 16 | ENTRYPOINT \ 17 | openssl req \ 18 | -subj '/C=DE/ST=Berlin/L=Berlin/O=None/CN=localhost' \ 19 | -x509 -newkey rsa:4096 \ 20 | -nodes -keyout /etc/nginx/ssl/default_key.pem \ 21 | -keyout ${NGINX_DIR}/certs/ckan-local.key \ 22 | -out ${NGINX_DIR}/certs/ckan-local.crt \ 23 | -days 365 && \ 24 | nginx -g 'daemon off;' 25 | -------------------------------------------------------------------------------- /nginx/setup/ckan-local.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFIDCCAwgCCQDr3dGZoSvqMDANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJE 3 | RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xDTALBgNVBAoMBE5v 4 | bmUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzAzMzEwMjM1MjZaFw0yNDAzMzAw 5 | MjM1MjZaMFIxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcM 6 | BkJlcmxpbjENMAsGA1UECgwETm9uZTESMBAGA1UEAwwJbG9jYWxob3N0MIICIjAN 7 | BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApej5FEF4lCOAmmUaAr67w6Go2XZO 8 | crV2UoWbJQq+aC688XpSX5MaxBVK7r4MQGvwC0u/5aN50fyGQBWGeiY6/27MbGHA 9 | fimLtGAmHf5ys4FYtD71YYV0ekUMvlTV1flV3gdM3JItlkXR8ukqIb6WlAGv4vS3 10 | 31QdoUyd7bGbCMmtDJ2ecnSlO5U0l9Udoqz4+cDPUMWMc1rXw9DfK/mzm+KR3iW+ 11 | QdWwbWj+Crd/aBKiofKIscq2svRfcVisxSbPr4ib1iMEAxes3nt2cBYNQe8H2OVh 12 | SHbskKtaVgG5d+X+f/Mo+P6/1wrqY1JBgkegWkpcaz5mlT4tjsiudfmKsRRnKqHP 13 | m5qohWBZxH2MDWX1ggJsziI546a5Y0lkvazql8QUd44X/vrWnx37sCn50Dj8DRAf 14 | xtzNAC4doO+nIS+NC964yr6Ps4NrZE++WP5Ry6VUKhl46JSRkg6vtc27ZRrGn6LS 15 | AmWU/Ob6/9UaPQkWZ3A/iDnkrkBflM6wdaD/EQmb5LLou84dhZCivqEJ6/5TdB3c 16 | 8w5muTQY2SLY9JmvECNQpfviD1IdXq7zqeH23L/hgE9i3GrYGWqGc9E3cjNht8Qt 17 | hF7WbRaomzbjH6ChZTtiSEw3wtf6bTLKuJjWCBDbp+GypyfDWrvJI2UFVwtH5QMv 18 | HYvxG4t+u+E6F2MCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAQcFH6iKXcErUuPJv 19 | N+EdDfJh8CTvbqnp7SXOBQ2Q66NhsTZXPrpyOzT3APoeineWhwt7YZF59m02O1Ek 20 | yS2qVEdAI9vDgmRvR6ryRsaEkLvnbhfTsBkN56c2oLTxqHBHooAyBKVIl0rSplW9 21 | EYhZ9t+08QNd/2unEipgTMFUM+JIMMzseKDwrug97tGsCftIPeWddkPchT309Lwr 22 | ECl2JsXX4t67oNR54hqRRvxyriSx/E8BF7rupsnaGNdNPPASoBbGVGEWumUutWMh 23 | PzlkyOgpl5fZ44WqYOBvBeLGGPTkM3uoaySv6GNOAxFsXJfHXCq59TL93LRn4RKs 24 | rik07ZabYa95JFAPUUSzMpplU4RCpE6r+MFceb1WMrDpK/4zoLLeIwmlwiHsrg/6 25 | L0tN1/RLVQwvpxiVqlmETlyDmqFC+McURNU1ZJU2V8efQTWhDVnB7rNVefQsbTLN 26 | 5jaWiKMKQxva2Skf1jgVT9JOfYYCRlHpryOp9yIrqQqVxlaaDJz/Jm91Pt4QhCDj 27 | VhSMDYVMFtE/ylMbB1qR3MJBw0xCCG4zdZpUzvFfR6/wQ5FZ4DvXsbYnsxX/JhgV 28 | sTqxkdnhhR0UsxuHyxGWVPPxS+5IZdxVETcjrMVeaK9PAHyBBSI4DQHYIJWoyZ3m 29 | y9oQx2IvfVXpGptadU5EKWM6210= 30 | -----END CERTIFICATE----- 31 | -------------------------------------------------------------------------------- /nginx/setup/ckan-local.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCl6PkUQXiUI4Ca 3 | ZRoCvrvDoajZdk5ytXZShZslCr5oLrzxelJfkxrEFUruvgxAa/ALS7/lo3nR/IZA 4 | FYZ6Jjr/bsxsYcB+KYu0YCYd/nKzgVi0PvVhhXR6RQy+VNXV+VXeB0zcki2WRdHy 5 | 6SohvpaUAa/i9LffVB2hTJ3tsZsIya0MnZ5ydKU7lTSX1R2irPj5wM9QxYxzWtfD 6 | 0N8r+bOb4pHeJb5B1bBtaP4Kt39oEqKh8oixyray9F9xWKzFJs+viJvWIwQDF6ze 7 | e3ZwFg1B7wfY5WFIduyQq1pWAbl35f5/8yj4/r/XCupjUkGCR6BaSlxrPmaVPi2O 8 | yK51+YqxFGcqoc+bmqiFYFnEfYwNZfWCAmzOIjnjprljSWS9rOqXxBR3jhf++taf 9 | HfuwKfnQOPwNEB/G3M0ALh2g76chL40L3rjKvo+zg2tkT75Y/lHLpVQqGXjolJGS 10 | Dq+1zbtlGsafotICZZT85vr/1Ro9CRZncD+IOeSuQF+UzrB1oP8RCZvksui7zh2F 11 | kKK+oQnr/lN0HdzzDma5NBjZItj0ma8QI1Cl++IPUh1ervOp4fbcv+GAT2LcatgZ 12 | aoZz0TdyM2G3xC2EXtZtFqibNuMfoKFlO2JITDfC1/ptMsq4mNYIENun4bKnJ8Na 13 | u8kjZQVXC0flAy8di/Ebi3674ToXYwIDAQABAoICAFZTZma3ujm6T0wGlwYeoCwm 14 | jWi5OhBNgwdlJVicwn4K85zh/MJmFGM6gQbANDfA8eGuxGaELPqp3mCx0or0IXaO 15 | /CbYpgP/MgXkkXDB2IS2JKWErMDVY8nK69qM4ca4OYmRWtjZ5oZuRdOSpq1wMYFJ 16 | b28zzgiSB+jJqNLourZT2Yra6Hq9Xswl0nu+E/F09wdc34Izh+Ttu57Tq4uCHYZa 17 | 2XMxSFGREn+bRbPlzpEkQSLqw11fELkEljSv4xWiICZBenRtO8UwKG6K5xFjJ/rK 18 | mNauY3QFDQopXpOpygsszMNejk8gnkkSEOsk/ZkAE9tnHbdffJjjBWlp2fzgnty1 19 | 72MwzlrinfOsYn6Ioe/mobGmedxQl4hiu6lI/Rl94C8HmycYRddQAg/55mTgZHBK 20 | kUQCnqbLl9JLFiSwbL6YupkKGJeSPoXdzJcp4v+PT8a1QRDzdge8bwXQZJ59UhEu 21 | EYJnYy79jBT8+UdTZxCYdmc3wuvUvOpxLihOEdr5+/6ZqQ0znoeTXNHxvzb43vRy 22 | W7XgaP4pQH6/sD8mSRGHWNdG0hX9Fjc/C9rQzwMJwCAcGRTN7CjyOCMMbkmoCy5v 23 | UDV22WzZqlUUZijuinLVV2Gn1WSXLWPSOJUFpiVgvrnycItroRoOfOAQOt20HnQu 24 | b/R2P0xCKJCmHqBICpRhAoIBAQDZYD1ZMpvIX2ZyGkjUpy2Zm4ofly0mf/uzMnhv 25 | y76aedZ+uSxlDLnlHTbL2sVOQhq6aRDYAWKYxekDf5FxZ8SXx11Dn/QHvGcZ/Hcl 26 | LrhsGvVKPNPOMsXT8o0g7/BaS3hrzzOgHPRPl6dUZ78C4jX/KLjmNoqeO+FYqqB9 27 | 15yiGIDwJAanhoBOD7gonM9D9f3O6H5KzaDiggem+xSF3RVJyxPTWUEEa9hGZVcx 28 | /QZuEe8W79x3Tk0L5I9/Lw6qfN/JFuN9BY4zTLGar6TtDN2LRIfHm+8eHVyFASxO 29 | RqvTe9MfJwDRuwrULhaCtLjlLpU2HMjhZDlfG3z6EebulZJ1AoIBAQDDY7WEiksY 30 | /5eCyWp1oWTxqnmNKhxD6vd1nRviDEpVTZ0lsHdtiKzpkiEXbvkKjbFbm7wEcsNx 31 | HLKL4Q7Az89iR++dN4QkaqzsdnyRVc9W6UlUk5T2FqKoqsYcm0tG7fgIlXZ0PHgs 32 | jG9cHXIne/QvFQ15xfAv/6bAi0rjfntGf47TaZT6Y56sQQ14OvYemjYviWiBaylQ 33 | kbj3k+mAEGI8n71A2fWndk133HiLJ1EyWLUc8DEcB4kqwJHIYJGEYkwRWwoJmrS2 34 | hRZVHsn9ar4qi/0UOodUtLpZXerfNPW/KmFCOcI1I7244UgWpOcRke19F2OOI+Eh 35 | mOi4aJwVEJd3AoIBACKf4MW/eO7uuzu7khRFWM8Z5mNnyipSwn3lsSdllcO3WoIu 36 | 7rJd15J2F89a1ojDoMxGhgdSGSlqhNYo0Lr2o2rlt6ZY6R7+VJHgE/5ZNckKdj3P 37 | +JDkp3w+K1quvWM0mEbb50Y+tm+jIWUhbVyBOcad7u3EjEnuEdP0wcGpwWpUat1V 38 | b7Xph7BncpcNezpBCZ+Wit9RZ6oMujlPzxIPiB+L+Gl20xNoNjfoVn5A5nBL7QCD 39 | TmO2ljEpw+2nSje/0kmOmsfERcVIFxYjmiqkHPnc/Z++59StKpqI+EyzlxUFqThS 40 | FyBRIcVwXeeN79GZnOzUou677yOGFl8i0Nz5+C0CggEBAKTodd5snh92MVk4R/sK 41 | AdmaCUckoICOQtdoh40M1HwUqqqRuuqerVnhdL6Dcfv/RQ7NbS3P8rZ4AxXeGIaR 42 | njYUAt+NaKEXy+Uzx8UeSIXRFYwll1bwGc8De3vPcgRmeq47/6LxGnh2+tIjJCLB 43 | EoHeYeZCMotAWWwu5EEHkmIY7OHwPcXq6JP3v7eXA/0mKM+MSMDaQh93Lkb+9teY 44 | fGEwbRncG+KADbg5QyAnSfeVOR84dipzDckgiKo3Hvo9wHfxf5JFmXpm70deWhrh 45 | yai9SBeXonrSomkkxEQpPbRfv4CWoRwak1kEAsTh3whMQsYORH9GNxAVL23dFMcO 46 | ntcCggEBANhRGQvq1vxhnLkilwJ0EBocQ+KF8nZfzzOtQ194gPolRWpjVzDOeGc0 47 | Us4omOreNpIXNYg9ELWMgm53viEoY3GMVt1kPPGwWW/JGeGv0kqr8aM3kWm5gc2H 48 | eu/nM5JbOvUKxnruia9I8BvJeeTTVytRQbv4kojEkZagHKYoZJ+ox0Cx1UmXeVI/ 49 | vCufq4wqetJFNv05SNw7r+UObbc57BIPSvR3SGYmaZYkb8Wo/dZXF+vOAySnR8Go 50 | 3bihBMtzmspt9JQtPBDy84okQrojsfm8fyyMRZ/UtMrhvGYFd9bcMDsCY+jybRXa 51 | E0CmRHNQumr+KBM8UT4YtWA+recgbtA= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /nginx/setup/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | #listen 80; 3 | #listen [::]:80; 4 | listen 443 ssl; 5 | listen [::]:443 ssl; 6 | server_name localhost; 7 | ssl_certificate /etc/nginx/certs/ckan-local.crt; 8 | ssl_certificate_key /etc/nginx/certs/ckan-local.key; 9 | 10 | # TLS 1.2 & 1.3 only 11 | ssl_protocols TLSv1.2 TLSv1.3; 12 | 13 | # Disable weak ciphers 14 | ssl_prefer_server_ciphers on; 15 | ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; 16 | 17 | # SSL sessions 18 | ssl_session_timeout 1d; 19 | # ssl_session_cache dfine in stream and http 20 | ssl_session_tickets off; 21 | 22 | #access_log /var/log/nginx/host.access.log main; 23 | 24 | location / { 25 | proxy_pass http://ckan:5000/; 26 | proxy_set_header X-Forwarded-For $remote_addr; 27 | proxy_set_header Host $host; 28 | #proxy_cache cache; 29 | proxy_cache_bypass $cookie_auth_tkt; 30 | proxy_no_cache $cookie_auth_tkt; 31 | proxy_cache_valid 30m; 32 | proxy_cache_key $host$scheme$proxy_host$request_uri; 33 | } 34 | 35 | error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 /error.html; 36 | 37 | # redirect server error pages to the static page /error.html 38 | # 39 | location = /error.html { 40 | ssi on; 41 | internal; 42 | auth_basic off; 43 | root /usr/share/nginx/html; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /nginx/setup/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Error 7 | 8 | 9 |

Oops! Something went wrong.

10 |

We're sorry, but the page you requested could not be found.

11 | 12 | 13 | -------------------------------------------------------------------------------- /nginx/setup/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | CKAN Docker NGINX landing page 8 | 14 | 15 | 16 | 17 |

18 | CKAN Docker NGINX landing page 19 |

20 | 21 | 22 | -------------------------------------------------------------------------------- /nginx/setup/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | user nginx; 3 | worker_processes auto; 4 | 5 | error_log /var/log/nginx/error.log notice; 6 | pid /var/run/nginx.pid; 7 | 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | 14 | http { 15 | include /etc/nginx/mime.types; 16 | default_type application/octet-stream; 17 | 18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 19 | '$status $body_bytes_sent "$http_referer" ' 20 | '"$http_user_agent" "$http_x_forwarded_for"'; 21 | 22 | access_log /var/log/nginx/access.log main; 23 | 24 | sendfile on; 25 | tcp_nopush on; 26 | tcp_nodelay on; 27 | types_hash_max_size 2048; 28 | keepalive_timeout 65; 29 | 30 | # Don't expose Nginx version 31 | server_tokens off; 32 | 33 | # Prevent clickjacking attacks 34 | add_header X-Frame-Options "SAMEORIGIN"; 35 | 36 | # Mitigate Cross-Site scripting attack 37 | add_header X-XSS-Protection "1; mode=block"; 38 | 39 | # Enable gzip encryption 40 | gzip on; 41 | 42 | proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache:30m max_size=250m; 43 | proxy_temp_path /tmp/nginx_proxy 1 2; 44 | 45 | client_max_body_size 140M; 46 | 47 | include /etc/nginx/conf.d/*.conf; 48 | 49 | # Error status text 50 | map $status $status_text { 51 | 400 'Bad Request'; 52 | 401 'Unauthorized'; 53 | 402 'Payment Required'; 54 | 403 'Forbidden'; 55 | 404 'Not Found'; 56 | 405 'Method Not Allowed'; 57 | 406 'Not Acceptable'; 58 | 407 'Proxy Authentication Required'; 59 | 408 'Request Timeout'; 60 | 409 'Conflict'; 61 | 410 'Gone'; 62 | 411 'Length Required'; 63 | 412 'Precondition Failed'; 64 | 413 'Payload Too Large'; 65 | 414 'URI Too Long'; 66 | 415 'Unsupported Media Type'; 67 | 416 'Range Not Satisfiable'; 68 | 417 'Expectation Failed'; 69 | 418 'I\'m a teapot'; 70 | 421 'Misdirected Request'; 71 | 422 'Unprocessable Entity'; 72 | 423 'Locked'; 73 | 424 'Failed Dependency'; 74 | 425 'Too Early'; 75 | 426 'Upgrade Required'; 76 | 428 'Precondition Required'; 77 | 429 'Too Many Requests'; 78 | 431 'Request Header Fields Too Large'; 79 | 451 'Unavailable For Legal Reasons'; 80 | 500 'Internal Server Error'; 81 | 501 'Not Implemented'; 82 | 502 'Bad Gateway'; 83 | 503 'Service Unavailable'; 84 | 504 'Gateway Timeout'; 85 | 505 'HTTP Version Not Supported'; 86 | 506 'Variant Also Negotiates'; 87 | 507 'Insufficient Storage'; 88 | 508 'Loop Detected'; 89 | 510 'Not Extended'; 90 | 511 'Network Authentication Required'; 91 | default 'Something is wrong'; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /postgresql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:16-alpine 2 | 3 | # Include extra setup scripts (eg datastore) 4 | COPY --chown=postgres:postgres docker-entrypoint-initdb.d /docker-entrypoint-initdb.d 5 | -------------------------------------------------------------------------------- /postgresql/docker-entrypoint-initdb.d/.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf 2 | -------------------------------------------------------------------------------- /postgresql/docker-entrypoint-initdb.d/10_create_ckandb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 5 | CREATE ROLE "$CKAN_DB_USER" NOSUPERUSER CREATEDB CREATEROLE LOGIN PASSWORD '$CKAN_DB_PASSWORD'; 6 | CREATE DATABASE "$CKAN_DB" OWNER "$CKAN_DB_USER" ENCODING 'utf-8'; 7 | EOSQL 8 | -------------------------------------------------------------------------------- /postgresql/docker-entrypoint-initdb.d/20_create_datastore.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 5 | CREATE ROLE "$DATASTORE_READONLY_USER" NOSUPERUSER NOCREATEDB NOCREATEROLE LOGIN PASSWORD '$DATASTORE_READONLY_PASSWORD'; 6 | CREATE DATABASE "$DATASTORE_DB" OWNER "$CKAN_DB_USER" ENCODING 'utf-8'; 7 | EOSQL -------------------------------------------------------------------------------- /postgresql/docker-entrypoint-initdb.d/30_setup_test_databases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 5 | CREATE DATABASE ckan_test OWNER "$CKAN_DB_USER" ENCODING 'utf-8'; 6 | CREATE DATABASE datastore_test OWNER "$CKAN_DB_USER" ENCODING 'utf-8'; 7 | EOSQL 8 | -------------------------------------------------------------------------------- /src/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ckan/ckan-docker/fc90a89227f432f58e7dcc80311dbeb1151ff90f/src/.placeholder --------------------------------------------------------------------------------