Details#
Networking#
The template places the EC2 instance in the first subnet of the default VPC in the selected AWS region. The template assigns an Elastic IP (EIP) to the instance to keep its public IP address stable across stop/start cycles.
Amazon Route 53 manages DNS. The template references a Hosted Zone for your domain (which must already exist) and adds a DNS record pointing your subdomain to the instance’s Elastic IP.
The instance’s security group only allows ingress on port 443 (HTTPS). There is no SSH access — all administrator operations go through AWS Systems Manager (SSM).
Compute#
The template selects the latest Amazon Linux 2023 AMI compatible with the chosen instance type:
Standard AL2023 AMI for CPU instances (x86_64 or arm64)
Deep Learning AMI (DLAMI) for GPU or Neuron instances (x86_64 or arm64)
You can also provide a specific AMI ID to override automatic selection.
Storage#
The instance has two volumes. The root volume inherits its size and settings from the selected AMI, with a configurable minimum size. It persists across instance restarts and instance type changes, as long as the new instance type is compatible with the existing root volume. The template attaches a separate EBS data volume and mounts it into the JupyterLab container at /home/jovyan — this volume persists user data across container restarts and instance stop/start cycles.
You can optionally attach additional EBS volumes or EFS file systems and mount them into the Jupyter home directory.
TLS#
Let’s Encrypt provides TLS certificates using the ACME protocol. Traefik acts as the ACME client and proves domain ownership via a DNS-01 challenge: it creates a temporary TXT record in the Route 53 Hosted Zone, Let’s Encrypt verifies it, and issues the certificate. Traefik stores the certificate in acme.json and renews it automatically. The template also backs the certificate up to AWS Secrets Manager so it persists across instance replacements.
IAM and Secrets#
The template creates an IAM role for the EC2 instance with permissions for SSM, Route 53, S3, and (optionally) EFS access.
The template creates two AWS Secrets Manager secrets:
One to store the OAuth App client secret
One to store TLS certificates from Let’s Encrypt, ensuring they persist across instance replacements
Deployment Configuration#
An S3 bucket stores all deployment configuration files: bash scripts, Docker service definitions, and application configuration. The instance pulls these files during setup or updates via a cloud-init script.
The template creates an SSM startup document that orchestrates instance configuration using these files:
File |
Purpose |
|---|---|
|
EC2 instance configuration |
|
Docker service definitions |
|
Docker service startup |
|
Optional EBS/EFS volume mounts |
|
Traefik reverse proxy configuration |
|
Jupyter container image |
|
Jupyter container entrypoint |
|
Fallback if Jupyter fails to start |
|
Python dependencies for the Jupyter environment |
|
Jupyter server settings |
|
Log rotation sidecar container |
|
Logrotate configuration |
|
Fluent-bit log collection configuration |
|
Fluent-bit Docker log parsers |
If you selected pixi as the dependency manager, the template uses pixi.jupyter.toml instead of pyproject.jupyter.toml.
An SSM association triggers the startup script on the instance whenever the configuration changes.
Operations#
The template creates SSM documents that the jd CLI uses to manage the deployment remotely:
Document |
Purpose |
|---|---|
|
Verify services are running and TLS certificates are available |
|
Translate status checks to human-readable output |
|
Update authorized org, teams, and/or users |
|
Retrieve current authorization settings |
|
Update running services |
|
Rotate the OAuth cookie secret and invalidate all sessions |
Logging#
Fluent-bit collects Docker service logs and writes them to /var/log/services on the instance volume. A logrotate sidecar container handles automatic rotation of all log files based on configurable size and retention settings.
Presets#
The template provides two variable presets:
defaults-all.tfvars— comprehensive preset with all recommended valuesdefaults-base.tfvars— minimal preset that prompts for instance type and volume size
Requirements#
Name |
Version |
|---|---|
terraform |
>= 1.0 |
aws |
>= 4.66 |
Providers#
Name |
Version |
|---|---|
aws |
>= 4.66 |
Terraform Modules#
Name |
Location |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Inputs#
Name |
Type |
Default |
Description |
|---|---|---|---|
region |
|
|
The AWS region where to create the resources |
instance_type |
|
|
The type of instance to start |
key_pair_name |
|
|
The name of key pair |
ami_id |
|
|
The ID of the AMI to use for the instance |
min_root_volume_size_gb |
|
|
The minimum size in gigabytes of the root EBS volume for the EC2 instance (will use AMI snapshot size if larger) |
volume_size_gb |
|
|
The size in GB of the EBS volume the Jupyter Server has access to |
volume_type |
|
|
The type of EBS volume the Jupyter Server will has access to |
iam_role_prefix |
|
|
The prefix for the name of the IAM role for the instance |
oauth_app_secret_prefix |
|
|
The prefix for the name of the AWS secret to store your OAuth app client secret |
s3_bucket_prefix |
|
|
The prefix for the name of the S3 bucket where deployment scripts are stored (3-28 characters, lowercase alphanumeric with hyphens) |
certs_secret_prefix |
|
|
The prefix for the name of the AWS secret where ACME certificates are stored |
letsencrypt_email |
|
Required |
An email for letsencrypt to notify about certificate expirations |
domain |
|
Required |
A domain that you own |
subdomain |
|
Required |
A sub-domain of |
oauth_provider |
|
|
The OAuth provider to use |
oauth_allowed_org |
|
|
The GitHub organization to allowlist |
oauth_allowed_teams |
|
|
The list of GitHub teams to allowlist |
oauth_allowed_usernames |
|
|
The list of GitHub usernames to allowlist |
oauth_app_client_id |
|
Required |
The client ID of the OAuth app |
oauth_app_client_secret |
|
Required |
The client secret of the OAuth app |
log_files_rotation_size_mb |
|
|
The size in megabytes at which to rotate log files |
log_files_retention_count |
|
|
The maximum number of rotated log files to retain for a log group |
log_files_retention_days |
|
|
The maximum number of days to retain any log files |
custom_tags |
|
|
The custom tags to add to all the resources |
additional_ebs_mounts |
|
|
Elastic block stores to mount on the notebook home directory |
additional_efs_mounts |
|
|
Elastic file systems to mount on the notebook home directory |
Outputs#
Name |
Description |
|---|---|
|
The URL to access your notebook app |
|
The URL for the OAuth callback - do not use directly |
|
The ID of the EC2 instance |
|
The Amazon Machine Image ID used by the EC2 instance |
|
The public IP assigned to the EC2 instance |
|
The ARN of the AWS Secret storing the OAuth client secret |
|
The ARN of the AWS Secret where TLS certificates are stored |
|
Name of the S3 bucket where deployment scripts and service configuration files are stored |
|
ARN of the S3 bucket where deployment scripts and service configuration files are stored |
|
The AWS region where the resources were created |
|
Unique identifier for this deployment |
|
Hash of files affecting docker compose image builds (jupyter, log-rotator) |
|
Hash of all deployment script files which controls SSM association re-execution |
|
Name of the SSM document to verify if the server is ready to serve traffic |
|
Name of the SSM document to control server container operations |
|
Name of the SSM document to print server logs to terminal |
|
Name of the SSM document to execute commands inside server containers |
|
Name of the SSM document to start interactive shell sessions inside server containers (jupyter or traefik) |
|
Name of the SSM document to remove the allowlisted organization |
|
Name of the SSM document to view authorized users, teams and organization |
|
Name of the SSM document to change the authorized users |
|
Name of the SSM document to change the authorized teams |
|
Name of the SSM document to allowlist an organization |
|
Name of the SSM document to remove the allowlisted organization |
|
List of identifiers of resources that should not be destroyed |