> For the complete documentation index, see [llms.txt](https://docs.coherent.global/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coherent.global/hybrid-runner/how-to-set-up-the-hybrid-runner/hybrid-method-3-custom-docker-image.md).

# Hybrid method 3: Custom Docker image

This is a variation of [Hybrid method 2: Manual Wasm mount](/hybrid-runner/how-to-set-up-the-hybrid-runner/hybrid-method-2-manual-wasm-mount.md). The result is a [Docker image](https://docs.docker.com/) that includes the runner and Wasm files to be deployed.

## Bundle `nodegen-server` and Wasm modules into a new Docker image

1. Complete the instructions in [Hybrid method 2: Manual Wasm mount](/hybrid-runner/how-to-set-up-the-hybrid-runner/hybrid-method-2-manual-wasm-mount.md#export-the-wasm-modules-from-spark).
2. Navigate to your desired working directory and move the exported `ZIP` to this location. In this example the name of the file is `runner_example.zip`.
3. Create a [Dockerfile](https://docs.docker.com/engine/reference/builder/) with the following content:

   ```docker
   FROM alpine:latest AS unzipper

   # Set extract model name
   ARG MODEL_PATH=./runner_example.zip

   # Add unzip package
   RUN apk add unzip
   RUN mkdir /models && mkdir /model_zip

   # Copy extracted model model zip to temp folder
   COPY $MODEL_PATH ./model_zip

   # Unzip the extracted zip file
   RUN find ./model_zip -depth -name "*.zip" -exec sh -c 'f="{}"; unzip -- "$f" -d ./models' \; && rm -rf ./model_zip;

   # Set nodegen-server image
   FROM ghcr.io/coherent-partners/nodegen-server:latest

   # Create models folder
   RUN mkdir /models

   # Copy unzipped models to previously created folder
   COPY --from=unzipper /models/ /models

   # Set MODEL_LOCATION variable to models folder
   ENV MODEL_LOCATION=/models

   # Set the hybrid runner mode
   ENV USE_SAAS=false

   # Default application will listen on port 3000; you can set different to port by set PORT variable
   ENV PORT=8080

   # Start the application by script npm start
   CMD ["npm", "start"]
   ```
4. [`docker image build`](https://docs.docker.com/engine/reference/commandline/build/) the Docker image.

   ```sh
   docker build -t nodegen_server_custom .
   ```
5. [`docker container run`](https://docs.docker.com/engine/reference/commandline/run/) the service and create a container called `wasm-server`. This example binds `8080` of the container to the port `8080` of the host.

   ```bash
   docker run --name wasm-server -p 8080:8080 nodegen_server_custom
   ```
6. Make API calls to `localhost:8080` for the `healthcheck` and `execute` endpoints.

   ```shellscript
   # healthcheck
   curl 'http://localhost:8080/healthcheck'

   # execute
   curl --location --request POST 'http://localhost:8080/mytenant/api/v3/execute' \
   --header 'Content-Type: application/json' \
   --data '{
       "request_data": {
           "inputs": { "A": 1 , "B": 2 }
       },
       "request_meta": {
           "version_id": "c16d9b89-92c4-430f-a30e-9b04805fcb78",
           "call_purpose": "Offline",
           "source_system": "Hybrid Runner"
       }
   }'
   ```

## Configure `HTTPS` with nginx

By default, `nodegen-server` only supports `HTTP`. `HTTPS` support can be configured by including [nginx](https://nginx.org/en/) server in the Docker image. Read more on how to configure `HTTPS` servers in the nginx [documentation](https://nginx.org/en/docs/http/configuring_https_servers.html).

1. Navigate to your desired working directory and move the exported ZIP to this location. In this example the name of the file is `runner_example.zip`.
2. Prepare your SSL certificate in the working directory saved as `ssl`.
3. Create your [`nginx.conf`](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/) in the working directory. Here is an example that of the file contents.

   ```nginx
   events {
     worker_connections 1024;
   }
   http {
     upstream backend {
         server localhost:8080;
     }

     server {
       listen 443 ssl http2 default_server;
       listen [::]:443 ssl http2 default_server;

       server_name localhost;

       ssl_certificate /etc/ssl/nginx-selfsigned.crt;
       ssl_certificate_key /etc/ssl/nginx-selfsigned.key;

       location / {
         proxy_http_version 1.1;
         proxy_cache_bypass $http_upgrade;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection 'upgrade';
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_pass http://backend;
       }
     }
   }
   ```
4. Create a [`Dockerfile`](https://docs.docker.com/engine/reference/builder/) with the following content:

   ```docker
   FROM alpine:latest AS unzipper

   # Set extract model name
   ARG MODEL_PATH=./runner_example.zip

   # Add unzip package
   RUN apk add unzip
   RUN mkdir /models && mkdir /model_zip

   # Copy extracted model model zip to temp folder
   COPY $MODEL_PATH ./model_zip

   # Unzip the extracted zip file
   RUN find ./model_zip -depth -name "*.zip" -exec sh -c 'f="{}"; unzip -- "$f" -d ./models' \; && rm -rf ./model_zip;

   # Set nodegen-server image
   FROM ghcr.io/coherent-partners/nodegen-server:latest

   # Create models folder
   RUN mkdir /models

   # Copy unzipped models to previously created folder
   COPY --from=unzipper /models/ /models

   # Set MODEL_LOCATION variable to models folder
   ENV MODEL_LOCATION=/models

   # Set the hybrid runner mode
   ENV USE_SAAS=false

   # Default application will listen on port 3000; you can set different to port by set PORT variable
   ENV PORT=8080

   # ADDED: Proxy app through nginx
   RUN apk update && apk add nginx
   COPY nginx.conf /etc/nginx/nginx.conf

   # ADDED: Copy ssl certificate
   COPY ssl /etc/ssl
   EXPOSE 443

   # MODIFIED: Start the application by script npm start
   CMD nginx; npm start;
   ```
5. Make API calls to the `healthcheck` and `execute` endpoints similar [Hybrid method 2: Manual Wasm mount](/hybrid-runner/how-to-set-up-the-hybrid-runner/hybrid-method-2-manual-wasm-mount.md).
