Share:

This article is largely to document how to configure a Grails application to deploy to Elastic Beanstalk successfully with some specific requirements. Note this article reflects deployments based on Amazon Linux 2, as of August 2023.

There are many ways to deploy to AWS, In this particular scenario my requirements are as such.

  1. I have a setup AWS Code Pipeline setup to execute whenever I push to my GitHub repository.
  2. I am building an executable Jar file. As such my Beanstalk configuration is pure Java, not Tomcat.
  3. I am using Nginx as the web proxy in front of the application.
  4. I want non-https traffic to redirect automatically to https.
  5. I also need Nginx to allow uploads from users of payloads larger than the 1MB default.
  6. My build instructions should use Java 17

It is assumed all AWS resources are setup, Beanstalk, CodePipeline, CodeBuild, etc. This is not a full tutorial.

Nginx Custom Configuration

In the root of the Grails application, we need to create configuration fails at very specific paths. All additional configurations can go into a single file, but I like to separate configs per their primary function, so in my case, you’ll see I have two files.

Create a folder within the root of your project, (NOT within grails-app) named
.platform/nginx/conf.d/elasticbeanstalk

My first file here is to provide the redirect behaviour. This is named 00_application.conf and contains the following:

location / {
     set $redirect 0;
     if ($http_x_forwarded_proto != "https") {
       set $redirect 1;
     }
     if ($http_user_agent ~* "ELB-HealthChecker") {
       set $redirect 0;
     }
     if ($redirect = 1) {
       return 301 https://$host$request_uri;
     }   
 
     proxy_pass          http://127.0.0.1:5000;
     proxy_http_version  1.1;
 
     proxy_set_header    Connection          $connection_upgrade;
     proxy_set_header    Upgrade             $http_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;
}

The second file is named 01_client_size.conf and simply contains the following:

client_max_body_size 50M;

This as it suggests, configures Nginx to accept uploads of a maximum of 50M, this can be changed as required.

AWS CodeBuild Configuration

The next task is to configure AWS CodeBuild to correctly package our Jar file and include the configuration in the root of the produced artifact.

Create a buildspec.yml file, again in the root folder of your project. The contents of my file are as such:

version: 0.2
phases:
  install:
    runtime-versions:
      java: corretto17
  pre_build:
    commands:
      - echo Running tests
      - sudo chmod +x ./gradlew
      - ./gradlew clean --stacktrace
      - ./gradlew assemble --stacktrace
      - ./gradlew test --stacktrace
  build:
    commands:
      - echo Building jar
      - ./gradlew bootJar
  post_build:
    commands:
      - echo Build completed
      - mkdir deploy
      - cp build/libs/*.jar deploy/
      - cp -r .platform deploy/
      - cd deploy
cache:
  paths:
    - '/root/.gradle/wrapper/**/*'
    - '/root/.gradle/caches/**/*'
    - '.gradle/**/*'
artifacts:
  files:
    - '*.jar'
    - '.platform/**/*'
  base-directory: 'deploy'
  discard-paths: no

The majority of examples and tutorials you will probably find on this subject will instruct you to use discard-paths: yes however the key difference here is that it’s absolutely mandatory to maintain the .platform directory structure in order to configure Nginx. So therefore in the post_build section, we are creating a deploy folder to contain our compiled Jar in the root, and also the Nginx configuration in it’s expected structure.

As ever, we hope this helps someone facing this sometimes challenging task of what should be a simple deployment configuration.

Share: