Self-hosted deployment

Carbone on Amazon Elastic Container Service

Generate and manage your reports inside your own Amazon ECS Cluster

Introduction

Setting up Carbone in an ECS environment is very simple and effective.

Here's the recommended configuration:

Carbone on ECS architecture

To use Carbone Enterprise Edition on Amazon Elastic Container Service, you need a Carbone license. Talk to us to find out more.

Quickstart

Create ECS Cluster

To set up Carbone in your environment, the first step is to create your cluster. To do this, connect to the Amazon Elastic Container Service console and create your cluster:

Create Carbone Cluster

Create IAM role

You then need to prepare a role that will be used by your Carbone container.

For this example, we suggest you give access rights to CloudWatch and to read secrets for license storage.

You must first create the carbone_service_role with Elastic Container Service Task trusted entity : Create Role

Then, you must assign AmazonECSTaskExecutionRolePolicy, CloudWatchLogsFullAccess and custom ReadSecret permissions policies : Assign permission to role

Storing Carbone License

To store secrets properly, we recommend using AWS Secrets Manager. You'll need to create a new secret from the AWS Secrets Manager Console.

Insert your license as Other type of secret : Storing Carbone licence

Create Task definition

You now need to create a task definition for the Carbone service. Go to the Task definitions console, and create a task. Here is an example of a json task definition:

{
    "family": "carboneService",
    "containerDefinitions": [
        {
            "name": "Carbone",
            "image": "carbone/carbone-ee:full",
            "cpu": 0,
            "portMappings": [
                {
                    "containerPort": 4000,
                    "hostPort": 4000,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "environment": [
                {
                    "name": "CARBONE_STUDIO",
                    "value": "true"
                }
            ],
            "mountPoints": [],
            "volumesFrom": [],
            "secrets": [
                {
                    "name": "CARBONE_LICENSE",
                    "valueFrom": <REPLACE WITH YOUR LICENCE SECRET ARN>
                }
            ],
            "stopTimeout": 20,
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "awslog-carbone",
                    "awslogs-create-group": "true",
                    "awslogs-region": "eu-west-3",
                    "awslogs-stream-prefix": "Carbone"
                }
            },
            "systemControls": []
        }
    ],
    "executionRoleArn": <REPLACE WITH YOUR ROLE ARN>,
    "networkMode": "awsvpc",
    "placementConstraints": [],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "1024",
    "memory": "2048",
    "runtimePlatform": {
        "cpuArchitecture": "ARM64",
        "operatingSystemFamily": "LINUX"
    }
}

Create Service

Finally, all that's left to do is create the service in your cluster using the task definition you've just created.

You can then configure the number of tasks you need, autoscaling, an Application Load Balancer, ...

Et voilà 🎉

Configuration

Storage backends

To use Carbone in production, you need to configure data persistence for template and rendering storage.

There are two possible solutions in the ECS environment: using S3 buckets or configuring an Elastic File System shared volume.

We recommend using S3 rather than EFS. If you run multiple instances with template management enabled, EFS is not supported as a storage backend — use S3 instead.

Storing persistent data on S3 bucket

To store your data on S3 buckets, you need to :

Storing persistent data on shared Elastic File System (EFS)

To use storage via the shared volume, you need to:

Enable Carbone options

All Carbone configuration options are available on this page.

You can also create your own plugins, configure your version of LibreOffice or add your own fonts by creating your own Carbone image.

Authentication

To enable API authentication:

A JWT token is then displayed in the console. You can then use it in your API calls.

Scaling and availability

Since template and render storage is external (S3 or EFS, see Storage backends above), Carbone tasks are stateless and can be scaled horizontally:

Infrastructure as Code

Carbone Terraform deployment

A complete Terraform deployment example is available. It deploys Carbone EE on ECS Fargate behind an Application Load Balancer, with autoscaling and optional EFS or S3 storage, in one terraform apply.

Prerequisites:

Usage:

# 1. Store the license in Secrets Manager
aws secretsmanager create-secret \n  --name carbone-ee/license \n  --secret-string "<your-license-key>" \n  --profile ecs

# 2. Edit terraform.tfvars to match your environment, then deploy
terraform init
terraform apply

The service URL is printed at the end of the apply.

Configuration options

Variable Type Default Description
region string "us-east-1" AWS region to deploy into
studio bool false Enable the Carbone Studio web interface
template_management bool false Enable the Template Management API
debug bool false Enable ECS Exec to open a shell into running containers
job_balancer bool false Enable Carbone's job balancer (CARBONE_JOB_BALANCER) — spreads document conversion load across the peers of a cluster

Runtime limits (max_data_size, max_generation_time, max_download_file_size_total, max_download_file_count, max_download_file_timeout, max_download_file_concurrency) map directly to Carbone's own CARBONE_* configuration options and default to the same values.

Storage modes

efs_storage and s3_storage are mutually exclusive. template_storage and render_storage control which directories are persisted, independently of the backend used.

efs_storage s3_storage template_storage render_storage Result
true false true false Templates persisted on EFS
true false true true Templates + renders persisted on EFS
false true true false Templates persisted on S3
false true true true Templates + renders persisted on S3
false false No persistent storage

EFS is not supported with template_management enabled on more than one task: the Template Management API relies on a SQLite database, and SQLite's POSIX file locks are not reliably enforced across NFS/EFS clients — this risks SQLITE_IOERR errors and database corruption. Use s3_storage = true in that case.

Autoscaling

The service scales between min_capacity (default 2) and max_capacity (default 6) tasks using a target-tracking policy on the queued metric that Carbone exposes on its /metrics endpoint.

An AWS Distro for OpenTelemetry (ADOT) sidecar runs alongside Carbone in each task, scrapes localhost:4000/metrics every 15 seconds, and publishes the queued metric to CloudWatch under the Carbone/ECS namespace. Application Auto Scaling then keeps the average queued value across tasks at or below target_value (default 5), adding or removing tasks as needed. ADOT logs are written to the same CloudWatch log group as Carbone, under the adot stream prefix.

Production best practices

FAQ

Open a shell into a running task — set debug = true and apply, then:

aws ecs list-tasks --cluster CarboneCluster --profile ecs
aws ecs execute-command --cluster CarboneCluster --task <task-id> --container Carbone --interactive --command "/bin/bash" --profile ecs

Disable debug and redeploy once done.

Check service logs:

aws logs tail awslog-carbone --follow --profile ecs

Retrieve the service URL after deployment:

terraform output service_url

Scale manually (note: autoscaling overrides this once active — update desired_count in ecs.tf to change the baseline permanently):

aws ecs update-service --cluster CarboneCluster --service carbone --desired-count 3 --profile ecs

Update the license:

aws secretsmanager put-secret-value --secret-id carbone-ee/license --secret-string "<new-license>" --profile ecs
aws ecs update-service --cluster CarboneCluster --service carbone --force-new-deployment --profile ecs

Upgrade

To upgrade Carbone on ECS:

  1. Create a new revision of the task definition with the updated image tag (for example carbone/carbone-ee:full-5.8.0).
  2. Update the service to use the new task definition revision. ECS performs a rolling deployment, starting new tasks and draining old ones behind the load balancer.

This is safe without downtime as long as template/render storage is external (S3 or EFS) rather than task-local.

Troubleshooting

Container logs. Every task ships its logs to the CloudWatch log group configured in the task definition (awslog-carbone in the example above) — check there first for application-level errors.

Task stuck in PENDING or fails to start. Common causes:

Task starts then stops immediately. Usually a permissions issue: the execution role needs secretsmanager:GetSecretValue on the license (and public key, if authentication is enabled) secret ARNs referenced in the task definition's secrets array.

Health check failures on the load balancer. Confirm the target group points at container port 4000 and path /status, and that the security group attached to the tasks allows inbound traffic from the load balancer.