Spin Up Your Own Terracotta Instance
Build, configure, and deploy Terracotta
Terracotta is free and open source, so if you’d like to create your own instance, you’re welcome to do so by following the instructions below.
Building Terracotta
The Terracotta code is available in this repository: Terracotta GitHub , and the current stable version is the latest tag in GitHub. Use the README file there to build Terracotta.
Terracotta is a java Spring Boot v3 application that uses Maven to build. The user interface (UI) is built with Vue.js v2 and needs to run yarn to build all the static files. The maven command includes everything necessary.
To generate a jar file (that will be created in the “target” directory) this command needs to be executed:
mvn clean install
*Please note, if test errors occur, try this command:
mvn clean install -DskipTests=true
*Please also note, to skip the yarn build, you can use -Dskip.yarn
Configuring Terracotta
Application properties file
To configure Terracotta, we will use an application properties file. The file can be named anything because we will define the name in the java command that launches the jar. A common name, however, would be “application.properties.”
This is a Spring Boot application, so any Spring configuration could be applied in this file.
Here is a line-by-line explanation of the configuration:
(Optional) Server port - in case it needs to run in a port different from the default 8080:
server.port=8090
Thymeleaf necessary configuration:
spring.thymeleaf.mode=HTML5
Logging path - If we use nohup these will be ignored, but in case we run the jar without nohup in the server this configuration will indicate where to write the logs:
logging.file=/path/terracotta.log
Logging level - Levels can change to DEBUG for more detailed information (we do not recommend this in prod, or if so, only for short tests, as the log can become very long).
logging.level.org.springframework.web=INFO
logging.level.org.springframework.security=INFO
logging.level.org.hibernate=ERROR
logging.level.edu.iu.terracotta=INFO
Database connection
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://
<mysql_server_url>:
<port>/
<database>
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=
<username>
spring.datasource.password=
<password>
spring.liquibase.change-log=classpath:/db/changelog/changelog-master.xml
SSL management with the AWS load balancer in front.
security.require-ssl=true
server.tomcat.remoteip.remote-ip-header=x-forwarded-for
server.tomcat.remoteip.protocol-header=x-forwarded-proto
security.headers.frame=false
Public and private keys - It is necessary to generate a NEW and UNIQUE pair of public and private keys and add them to the configuration file.
oicd.privatekey=
<-----BEGIN PRIVATE KEY-----MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC2QJCkV2gFoQD2z7dQRq7g5qIxPaZJJZAJ07wPxdAJiyuWbo0bMOvH//5IqmOnUdal7iNYtDKwr9Cx6UMq...72wuT8RzsVTPwN9uKZOlm/sHd7KtETaMXRM94mT/uisQ9QahX48tw/c4miu+Sv2xWwQ1sNJ4OXzO/tir0uLgMp6XcA==-----END PRIVATE KEY----->
oicd.publickey=
<-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtkCQpFdoBaEA9s+3UE...Q4k+79zbOxbvDSeuLLV0mAvM85k1m4lJMdOkmyTisx9BwvTamZnjsHA8krV2LeplSYPmzraXLbopAmSJGHibhMFpEfS6rwHaArNZFZ6vJBdWpTXd+QIDAQAB-----END PUBLIC KEY----->
Application-specific properties - The application url is very important, as we use it to build some links.
application.url=https://
<tool_url>
application.name= Terracotta DEV 1
application.description=The Terracotta tool
In case we want to load data in the first start of the application from a place that is not the sample data provided in the jar file:
initial.lti.data.location=classpath:data/
To edit the configuration using the /config/ API, we need to define a user and password. If we don’t define it, the user will be admin, and the password will be randomly generated and displayed in the log when the tool starts:
terracotta.admin.user = <
admin_user>
terracotta.admin.password = <
password>
Where the files will be uploaded - This can be linked to any external storage and can be accessed via a normal path. NOTE: this requires an existing folder that will need to be manually created:
upload.path=/the_path/terracotta_files
To overwrite the cron schedule (if not configured, it will run every 24 hours):
scheduled.deleteoldtokens.cron=*/50 * * * * *
To configure Caliper: The first command enables sending the events; the second enables saving the events in the database. The others are the necessary configurations to create the sensor and connect with the learning record store (LRS).
caliper.send will enable sending (or not) caliper events to the default server for the entities that have not defined individual caliper LRSs (default = false)
caliper.store-db will enable storage in the db for the caliper events generated (all of them, not only the ones with the default configuration) (default = false)
The rest are the parameters needed to configure the caliper sensor. The ones in bold are good as default values:
caliper.send=true
caliper.store-db=true
caliper.sensor-id = 123
caliper.client-id=1231
caliper.api-key = Bearer fdf7fc7f-8a71
caliper.connection-timeout = 10000
caliper.content-type = application/json
caliper.host = https://caliper.imsglobal.org/caliper/fdf7fc7f-8a71-6e0b/message
caliper.socket-timeout = 10000
Other configurations
Remember to create the file folder in the path you defined in the application folder; do the same if you define a folder to send the logs or to load the initial data.
Deploying Terracotta
Spring Boot tool deployments: Deploying Spring Boot Applications :: Spring Boot
The basic deployment consists of these steps:
Stop running the current version of Terracotta.
Replace the old jar with the newly generated jar file.
Restart Terracotta, launching the jar.
This is one example of the commands used in the dev and test servers to launch the jar file (there might by another valid way to do so):
nohup java -jar terracotta.jar --spring.config.location=application-local.properties &
This supposes that the jar file and properties file are in the same folder; this can be modified to indicate the correct path to the files.
Configuring LTI and Caliper
To configure the tool to work in Canvas (and Canvas to work with the tool), follow the steps detailed below.
Configure the tool in Canvas
Configure a new Development Key for LTI in Canvas (Admin -> Development Keys)
Below, you will find an example JSON configuration where the <tool_url> should be updated in the last lines.
This configuration ("windowTarget": "_blank"
) opens Terracotta in a new window, which is necessary to make it work in Safari and Firefox (it works without this configuration in Chrome). Please note that Terracotta is not currently compatible with Edge.
NOTE: In the left-had configuration page menu, the redirect url must be: https://<tool_url>/lti3
{
"title": "Terracotta",
"scopes": [
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/lineitem",
"https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly",
"https://purl.imsglobal.org/spec/lti-ags/scope/score",
"https://purl.imsglobal.org/spec/lti-nrps/scope/contextmembership.readonly",
"https://canvas.instructure.com/lti/account_lookup/scope/show"
],
"extensions": [
{
"platform": "canvas.instructure.com",
"settings": {
"platform": "canvas.instructure.com",
"placements": [
{
"enabled": true,
"placement": "course_navigation",
"message_type": "LtiResourceLinkRequest",
"windowTarget": "_blank"
}
]
},
"privacy_level": "public"
}
],
"public_jwk": {},
"description": "The terracotta tool for educational experiments",
"custom_fields": {
"due_at": "$Canvas.assignment.dueAt.iso8601",
"lock_at": "$Canvas.assignment.lockAt.iso8601",
"unlock_at": "$Canvas.assignment.unlockAt.iso8601",
"canvas_user_id": "$Canvas.user.id",
"canvas_login_id": "$Canvas.user.loginId",
"canvas_course_id": "$Canvas.course.id",
"canvas_user_name": "$User.username",
"canvas_assignment_id": "$Canvas.assignment.id",
"canvas_user_global_id": "$Canvas.user.globalId",
"allowed_attempts": "$Canvas.assignment.allowedAttempts",
"student_attempts": "$Canvas.assignment.submission.studentAttempts"
},
"public_jwk_url": "https://<tool_url>/jwks/jwk",
"target_link_uri": "https://<tool_url>/lti3",
"oidc_initiation_url": "https://<tool_url>/oidc/login_initiations"
}
Once this is created, it must be enabled, with the state switch set to “ON”. Take note of the key id because it will become the “client_id.”
Finally, “deploy” the tool in Canvas (Admin -> Settings -> Apps -> View -> Apps Configuration -> + App). Change the configuration type to “By Client ID” and introduce the ID from the previous step.
After clicking through to submit and accept, you will see Terracotta in the list of tools. You can then look in the tool’s menu for its deployment id (keep that number, too).
Configure the API token in Canvas
To create assignments, send grades, and read grades and outcomes, you will need an API token from Canvas.
You will need an admin user with permissions to create assignments and read/send grades.
Create the user (Account -> Settings -> Approved Integrations -> +New Access Token) and copy the value. You will need it for the configuration.
Configure the LMS in Terracotta
With the client_id and the deployment_id, you can configure Terracotta.
To do that, we need to add a row in the iss_configuration table on the Terracotta side.
You can do that directly with SQL or with any database tool that provides a UI to write in a database, like MySQLAdmin or DBeaver. You can also use the config API.
To use the config API, we need to use basic authentication to access to “our_tool_url
/config/” with these values: terracotta.admin.user = <
admin_user>
terracotta.admin.password = <
password>
Here is an example of a configuration to POST:
{
"iss": "https://canvas.instructure.com",
"clientId": "97140000000000216",
"oidcEndpoint": "https://terracotta.instructure.com/api/lti/authorize",
"jwksEndpoint": "https://terracotta.instructure.com/api/lti/security/jwks",
"oAuth2TokenUrl": "https://terracotta.instructure.com/login/oauth2/token",
"oAuth2TokenAud":
null,
"deploymentId": "448:5440a08422ab1ee7794a0588b5e4cb4a094c4256",
"apiToken": "9714~yidT975c2v3MT...WrM\n",
"baseUrl": "https://terracotta.instructure.com",
"caliperConfiguration":
null,
"caliperSensorId":
null,
"caliperClientId":
null,
"caliperApiKey":
null,
"caliperConnectionTimeout":
null,
"caliperContentType":
null,
"caliperHost":
null,
"caliperSocketTimeOut":
null
}
These values - iss, oidcEndpoint, jwksEndpoint and oAuth2TokenUrl - should be configured as explained at this link:
# Manually Configuring LTI Advantage Tools - Canvas LMS REST API DocumentationoAuth2TokenAud can be null (it would be needed for D2L, but not Canvas)
clientId and deploymentId: must be the same as what you configured in Canvas
apiToken: use the one created in Canvas
baseUrl: the url of the Canvas instance, needed to create the API calls
caliperConfiguration: a Boolean that indicates if you need to use a specific caliper configuration or not.
If set to true, we will always send events to that configuration.
If false, we won’t send events.
If null, we will use the default value in the applications properties file.
caliper *: same values explained in the configuration file.
Once this row is configured in the iss_configuration table, Terracotta should be able to receive LTI requests from Canvas.
AWS Infrastructure deployment
Test environment AWS resources deployment
Note: The instructions below are “high level”; they are the steps to deploy the AWS resources to support the application, but each of the steps listed below may require a few steps as well.
Create a VPC with:
at least 3 zones: (public, private, protected)
at least 2 subnets per zone
Create the security groups for:
the application server
the bastion server
the rds instance
the load balancer
Create the key pair to use with the bastion and application servers
Create a KMS key for the environment/deployment
Create the bastion server in the public zone
Configure the bastion server to allow ssh connections from specific ips (those allow to have shell access to the bastion/app servers)
Configure the application server security groups to allow ssh connections from the bastion server
Create the application server in the private zone
Create the rds instance in the protected zones, enabled encryption using the KMS key that was created before
Configure the rds security group to allow MySQL connections from the application server
Create a target group with the proper port where the application will run on the application server (this most likely will be 8080)
Add the application server to the target group
Create an internet facing Application Load Balancer (alb) in the public zone:
configure a redirection from 80 to 443
configure port 443 to forward to the target group of the application server
configure the alb security group to accept connections from anywhere to ports 80 and 443
Please keep in mind that “local” accounts must be created in both the bastion and application servers for people that need ssh/shell access to them.
Test environment diagram
Prod environment AWS resources deployment
The deployment for the PROD environment would be the same as the ones for the TEST environment, except that for PROD the recommendation is to have at least 3 subnets per zone.
Prod environment diagram