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:
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 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 :

Then, you must assign AmazonECSTaskExecutionRolePolicy, CloudWatchLogsFullAccess and custom ReadSecret permissions policies :

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 :

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 :
- Create 2 buckets, one for storing your templates, and one for storing renderings
- Create a user with a pair of API keys (KEY_ID and KEY_SECRET) with read and write rights to these buckets.
- In the task definition, you need to add the following environment variables:
AWS_ENDPOINT_URL=s3.amazonaws.com AWS_REGION=<S3 REGION> AWS_ACCESS_KEY_ID=<YOUR KEY_ID> AWS_SECRET_ACCESS_KEY=<YOUR KEY_SECRET> BUCKET_TEMPLATES=<YOUR TEMPLATES BUCKET NAME> BUCKET_RENDERS=<YOUR RENDERS BUCKET NAME>
Storing persistent data on shared Elastic File System (EFS)
To use storage via the shared volume, you need to:
Create an EFS space from the Elastic File System Console
Check that the network configuration allows this storage to be accessed from Carbone containers
Mount a shared volume by adding the
volumedirective to the task definition:"volume": [ { "name": "template-storage", "efs_volume_configuration": { "file_system_id": <EFS ID>, "root_directory": "/app/template" } }, { "name": "render-storage", "efs_volume_configuration": { "file_system_id": <EFS ID>, "root_directory": "/app/render" } } ]
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:
Add the environment variable
CARBONE_AUTHENTICATION=trueto the task definition.Generate a key pair with the same helper used on Docker and Kubernetes:
docker run -it --platform "linux/amd64" carbone/carbone-ee:slim-5.0.0-beta.0 generate-keysStore the public key content as a secret in AWS Secrets Manager (same as the license above), and reference it from the task definition as
CARBONE_AUTHENTICATION_PUBLIC_KEY, in thesecretsarray.Keep the private key secret — it never needs to leave your machine, it is only used to generate JWT tokens:
docker run -it --platform "linux/amd64" carbone/carbone-ee:slim-5.0.0-beta.0 generate-token ## Paste in terminal content of key.pem
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:
- Put an Application Load Balancer in front of the service, with a target group health check on
/status(port4000). - Configure ECS Service Auto Scaling with a target-tracking policy (for example, target CPU utilization, or ALB request count per target) to adjust the desired task count automatically.
- Because every task shares the same S3 bucket or EFS volume, there is no clustering/peer configuration to set up — any task can serve any request.
Infrastructure as Code
Carbone autoscaling deployment
A complete Terraform deployment example is available.
Upgrade
To upgrade Carbone on ECS:
- Create a new revision of the task definition with the updated
imagetag (for examplecarbone/carbone-ee:full-5.8.0). - 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:
- Insufficient capacity for the requested
cpu/memoryin Fargate, or a subnet/security group that doesn't allow the task to reach the internet (to pull the image) or your VPC endpoints.
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.