Deploying Containers To Amazon Lightsail
AWSOfficialPublished by AWS
- Skill
- Workflow
- Cloud and DevOps
- Apache-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured procedure for deploying container images to the Amazon Lightsail Container Service. It covers the entire lifecycle from service creation and image preparation to deployment and troubleshooting. The service offers a managed environment with a fixed monthly cost, including load balancing and TLS termination, without the complexity of managing clusters or VPCs. The workflow emphasizes manual capacity management, as the service does not support autoscaling or scale-to-zero, and requires careful adherence to regional and resource-specific configurations.
What it does
- Creates and manages long-lived container services with fixed monthly pricing.
- Deploys container images from local builds, public registries, or GitHub repositories.
- Configures public endpoints with managed HTTPS URLs and health checks.
- Provides diagnostic steps for failed deployments using container logs.
- Manages service capacity through manual power and scale adjustments.
- Facilitates service teardown to stop recurring charges.
When to use it
- When you need to host a containerized application with a predictable, flat monthly budget.
- When you want to avoid the operational overhead of managing Kubernetes or complex VPC networking.
- When your workload is always-on and does not require autoscaling or scale-to-zero capabilities.
- When you need a simple, managed public HTTPS endpoint for a containerized service.
Advantages
- Predictable monthly billing based on fixed capacity.
- Managed infrastructure including load balancing and TLS certificates.
- Simplified deployment process without cluster or VPC configuration.
- Direct integration with local development workflows and public registries.
Usage examples
- “How do I deploy a public Nginx image to a new Amazon Lightsail container service?”
- The agent will guide you through creating the service, selecting the appropriate power and scale, and deploying the image with a public endpoint.
- “My Lightsail container deployment is failing, how can I check why?”
- The agent will instruct you to use the log retrieval operation to inspect the container logs and identify the root cause of the failure.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/aws/deploying-containers-to-amazon-lightsail/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip deploying-containers-to-amazon-lightsail.zip -d .agents/skills
Documentation by AWS
Deploying containers to Amazon Lightsail
Overview
Amazon Lightsail Container Service runs a container image behind a managed, HTTPS URL for a flat monthly price. The URL, TLS certificate, and load balancing are included — there is no cluster, VPC, load balancer, or registry to set up.
This skill takes a container image from any source to a live, serving Lightsail deployment, and diagnoses one that
won't serve. Creating the service requires two choices: power, the memory and vCPUs of each node, and scale,
how many nodes run, each running a full copy of the deployment. Capacity never changes on its own — there is no
autoscaling and no scale-to-zero — so you raise power or scale yourself when a service needs more.
Prerequisites
Before creating anything:
Clarify the image source, the port the app listens on, and the region.
Discover options at runtime — the available powers and regions — instead of hardcoding them.
Confirm the plan and price. State the flat monthly price (power × scale, charged even with no traffic) and confirm before creating billable resources — unless the user has already told you to proceed. Never create them silently. See the Pricing section below for where to read the figures.
Fixed caps aren't adjustable. The nodes-per-service cap is the ceiling on
scale; containers per deployment and deployment versions are capped too. Read the values in Lightsail quotas rather than offering an increase. An account's actual quota may be lower than the published default if the account was recently created or is used minimally.Permissions. The calling identity needs the Lightsail actions in the Operations table below; a missing one surfaces as an access-denied error on the first call, not as a tooling or quota problem. See the Security considerations section below for scoping them.
Tools: the AWS CLI (v2) is all a public-registry-image deploy needs — and its operations run either through
the AWS MCP tools (preferred, see below) or the CLI directly. A local build or push also needs docker (running)
and — for the push-container-image shortcut — the lightsailctl plugin (the plugin-free push uses docker +
register-container-image instead).
Running AWS operations: prefer the AWS MCP execution tool aws___run_script when it is available, and keep each
call short — one operation that returns right away, not a long-running one (a call still running after ~30
seconds is cut off and drops the session). It isn't required: the same operations run through the local aws CLI,
which is the fallback when no MCP tool is available. Note the build and push of a local image are
Docker/lightsailctl operations that run on your machine, never through the MCP tools.
Installing lightsailctl: needed only for the push-container-image shortcut, and it needs AWS CLI v2 plus a
running Docker:
macOS:
brew install aws/tap/lightsailctlLinux:
curl "https://s3.us-west-2.amazonaws.com/lightsailctl/latest/linux-amd64/lightsailctl" -o /usr/local/bin/lightsailctl && chmod +x /usr/local/bin/lightsailctlWindows: download
https://s3.us-west-2.amazonaws.com/lightsailctl/latest/windows-amd64/lightsailctl.exeand add it toPATH.
If an install is blocked or the plugin still isn't found, see the troubleshooting reference — or skip the plugin entirely with the plugin-free push in references/local-image.md.
References
The step-by-step detail lives in reference files bundled with this skill. You MUST read the reference matching your image source, or the step you're about to do, before doing it — each carries the exact sequence and requirements (ports, image architecture, push method) that are easy to get wrong.
To open one: on the AWS MCP server, retrieve it with the skill's content-retrieval tool; otherwise read it from this
skill's own directory (its location was shown to you when the skill loaded), e.g. <skill-dir>/references/NAME.md.
DON'T read from a bare references/NAME.md — it resolves against your working directory, not the skill, and
fails with "No files found"; if you hit that, prepend the skill directory and retry.
references/public-image.md — a public registry image (no build, no push).
references/local-image.md — build a local image and push it into the service's registry (
docker;push-container-imageor the plugin-free sequence).references/github-source.md — clone and build from a GitHub repo, then follow the local-image path.
references/deployment.md — the deployment shape (
containers+publicEndpoint+ health check), how to poll toACTIVE, roll back, and tear down.references/troubleshooting.md —
lightsailctlnot found, aFAILEDdeployment, 502/503, andexec format error(a CPU-architecture mismatch).
Service, deployment, containers
Container service — the long-lived resource you create first. It owns the capacity (
power×scale), the public HTTPS URL, the private domain, and its own image registry. Billing runs from creation to deletion.Deployment — an immutable, versioned spec of what to run on that service. One is active at a time, and creating another replaces the spec entirely.
Containers — entries inside a deployment (the per-deployment cap is in the Lightsail quotas linked above). Each has a name, an image, and ports; exactly one can be the public endpoint and the rest are reachable only by their siblings, over
localhost.
Pricing
Price is set by capacity under a transfer quota. The monthly cost is the power's price × the scale, charged from creation until deletion whether or not any requests arrive. Each service includes one monthly data-transfer quota — the quota does not change regardless of the power and scale that you choose for your service — and egress above it is charged per GB at a rate that varies by Region. Inbound counts toward the quota but isn't charged when exceeded.
State a price only if you have just read it from one of the sources below — never from memory, and never a placeholder
such as $0.00 for a rate you did not look up. Capacity cost is exact (power price × scale). Egress cost is not,
because it depends on traffic you cannot know, so give the per-GB rate rather than a total.
Power prices —
get-container-service-powersis the single source. It returns each power's monthly price per node, so quote that figure directly.Transfer quota — the
dataTransferQuotaattribute onLightsail Containersrecords, from the AWS Price List operationget-productswith service codeAmazonLightsail.Egress rate — a separate
get-productsrecord, found with aTERM_MATCHfilter onoverageType=ContainerSvc:Data Transfer. UseoverageType, notproductFamily:Lightsail Networkingalso holds CDN, bucket, instance, and DNS overages. Narrow byfromRegionCode, notregionCode, since these records name the location they transfer out of.
Workflow
Create the service with a chosen power and scale; poll
get-container-servicesuntil itsstateisREADY.get-container-service-powersreturns each power'sname(nano) and itspowerId(nano-1) — when you create the service, pass thenameto--power.Get the image in — the one source-specific step; follow the matching reference above.
Deploy a version (its
containersplus onepublicEndpointwith a health check), then poll the deployment toACTIVE— see the deployment reference.Verify and report — only once the deployment is
ACTIVE, read the generated URL from the service (it has a random id — read it, don't construct it), confirm it responds, and report the URL, the monthly price, and the teardown command.
Polling: create and deploy return immediately and finish asynchronously — expect ~5–10 min end to end, and a
still-PENDING/ACTIVATING state is normal. Poll by repeating a short status check with a brief pause between
calls — each check is its own quick call that returns right away, with a short sleep in between. Don't do the
waiting inside one long-running call (a loop inside a single run_script, or a long shell loop) — that's what
trips the execution timeouts (a single call still running after ~30 seconds can be cut off and drop the session).
Return the URL only once the deployment is ACTIVE.
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
| Confirm the monthly price before creating (unless told to proceed) | Create billable resources silently |
| Discover powers, regions, prices, and image versions from the API | Hardcode power, scale, region, prices, or an image version |
| Read the image-source reference before the image step | Guess the build/push sequence |
Poll with repeated short calls + a sleep between; return the URL only once ACTIVE | Wait inside one long-running call (a run_script loop or a long shell loop); return the URL early |
| For a public image, skip the build and push entirely | Require a local build when a registry image already exists |
Read get-container-log to diagnose a failure | Rebuild or redeploy blindly on a 502 or a FAILED deployment |
| Recommend ECS/EKS or ECS Express Mode for microservices/autoscaling | Present Lightsail as the answer to every container question |
| Always give the teardown command | Leave the user unable to stop charges |
Operations
Operation (aws lightsail …) | Purpose | Note |
|---|---|---|
get-container-service-powers | list the available powers with their specs and prices | read these instead of quoting remembered sizes or prices |
create-container-service | create the service | flat price = power × scale |
update-container-service | change capacity (power/scale) on a running service | re-deploys the current deployment automatically, with no downtime and keeps the same deployment version |
get-container-services | check state | READY before deploying; RUNNING after a deployment is active |
push-container-image | push a local image | needs the lightsailctl plugin and a running local Docker |
create-container-service-registry-login | get temporary registry credentials | first step of the plugin-free push |
register-container-image | register an already-pushed image by digest | the plugin-free alternative to push-container-image |
get-container-images | list the image versions in the service's registry | Lightsail assigns the version numbers - read them here rather than assuming them |
create-container-service-deployment | deploy an image | containers{} + publicEndpoint{containerName, containerPort, healthCheck} |
get-container-service-deployments | deployment state and history | ACTIVATING → ACTIVE; roll back by redeploying a prior version |
get-container-log | read container logs | first stop for diagnosing a failed deployment; don't log secrets or customer data |
delete-container-service | tear down | stops charges |
Security considerations
Least-privilege IAM — scope the calling principal to the
lightsail:actions this workflow actually uses (the Operations table above is the list) rather thanlightsail:*or an administrator policy.Secrets —
environmentvalues are stored in the deployment spec and readable throughget-container-service-deployments, and there is no separate secret-injection mechanism, so a credential the container needs has to go there; pass only what it needs. When a value is credential-shaped — a password, token, API key, or connection string — you MUST warn the user before deploying and leave the choice to them; one option is an application that decrypts the value itself, so the deployment spec holds ciphertext and the key ships in the image instead. NEVER print or log those values, or theget-container-service-deploymentsresponse that carries them, back to the user or into any artifact.Public surface — the endpoint is HTTPS-only with an AWS-managed certificate, Shield Standard covers common network-layer DDoS automatically, and only the container named in
publicEndpointis internet-reachable. There is no request throttling or WAF for a container service, and Lightsail does not inject security headers, so input validation, rate limiting, and CSP / HSTS / X-Content-Type-Options / X-Frame-Options are all the application's responsibility.Private network reach — a container has unfiltered network access to your other Lightsail resources in the same account and Region, and no Lightsail firewall rule narrows it. Where VPC peering is active for the Region, the same access extends to your own VPC. The image is therefore the only control, so you MUST warn the user before deploying an image they did not build.
Auditing — CloudTrail records all Lightsail API calls; Event history is on by default, and a trail gives continuous delivery to S3.
Troubleshooting
If anything goes wrong — a deployment fails, or the URL won't serve — read references/troubleshooting.md; start by reading the container log to the root cause.
Files
- ATTRIBUTION.mdAdded by AutoGineer979 B
- LICENSELicence file added by AutoGineer9.9 KiB
- NOTICELicence file added by AutoGineer67 B
- SKILL.md14.5 KiB
- references/deployment.md6.9 KiB
- references/github-source.md941 B
- references/local-image.md3.6 KiB
- references/public-image.md1.4 KiB
- references/troubleshooting.md4.0 KiB
references/deployment.md
Create the deployment and confirm it serves
The shared final step for every path, once the image is available — referenced publicly, or pushed into the service registry.
Deployment shape
A deployment is an immutable version: one or more container entries plus one public endpoint — omit the endpoint only
when the service should be reachable privately rather than from the internet: from your other Lightsail resources in
the same region over its private domain <service>.service.local, or from your own VPC where VPC peering is active —
see SKILL.md Security considerations. Create it with the create-container-service-deployment operation:
aws lightsail create-container-service-deployment \
--service-name NAME \
--containers '{"web":{"image":"public.ecr.aws/nginx/nginx:latest","ports":{"80":"HTTP"}}}' \
--public-endpoint '{"containerName":"web","containerPort":80,"healthCheck":{"path":"/"}}' \
--region REGIONThe parameters:
containers— a map of container name → entry. Each entry:image— a public image name, or a versioned reference from a push (not the local image name). These are immutable snapshots and increment on every push, so a deployment still naming an earlier version serves the old image while reportingACTIVE. Reference:<service>.<label>.latestfor the newest, or the exact number the push printed — see local-image.md.ports— ports to open, e.g.{"80": "HTTP"}. The public-endpoint container must have an HTTP or HTTPS port open here for the load balancer to route to.command/environment— optional launch command and environment variables. Values here are readable viaget-container-service-deployments— see SKILL.md Security considerations.
publicEndpoint— names exactly one container and the port to route to. It is also what makes Lightsail health-check the container; leave it out and the URL will not serve — see below.containerName+containerPort— where to route and probe. The port must match what the app listens on and be in that container'sports.healthCheck.path— the load balancer probes this path and it must return 2xx before the deployment goes live; default/. Its other settings (intervalSeconds,timeoutSeconds,healthyThreshold,unhealthyThreshold,successCodes) all have defaults: raise the interval or the unhealthy threshold for an app that boots slowly, and setsuccessCodeswhen the path deliberately answers a non-2xx code.
A deployment REPLACES the whole spec — it is not a patch. Every deployment must restate everything you want to keep:
Omit
publicEndpointand the service loses its public route: the deployment still reportsACTIVEwhile the default domain answers404 No Such Service, so a URL that was working stops serving.Omit a container and it is removed from the service, so anything that depended on it breaks.
Read the current spec with get-container-service-deployments first, then change only what must change.
Several containers in one deployment
Each entry in containers is independent, with its own image and ports. Only the one named by publicEndpoint is on
the public URL. To open communication between containers in the same deployment, add an environment variable that
references localhost (like CACHE_ADDR below); one that opens no ports, like worker, can still call out but
nothing on the public URL can reach it. From a different Lightsail resource in the same region, reach a service at
<service>.service.local:<port>.
{
"containers": {
"web": {"image": "<web-image>", "ports": {"80": "HTTP"},
"environment": {"CACHE_ADDR": "localhost:6379"}},
"cache": {"image": "<cache-image>", "ports": {"6379": "TCP"}},
"worker": {"image": "<worker-image>"}
},
"publicEndpoint": {
"containerName": "web",
"containerPort": 80,
"healthCheck": {"path": "/"}
}
}CACHE_ADDR is a non-secret address; anything sensitive placed here is readable via
get-container-service-deployments — see SKILL.md Security considerations.
Wait until it serves
Poll get-container-service-deployments for the deployment state (follow SKILL.md Polling — repeated
short checks, never a wait loop inside one call). Don't return the URL before the deployment is ACTIVE.
aws lightsail get-container-service-deployments --service-name NAME --region REGION| Deployment state | Service state | Meaning | What to do |
|---|---|---|---|
ACTIVATING | DEPLOYING | containers are launching | keep polling |
ACTIVE | RUNNING | serving on the public endpoint | read the URL and verify it responds |
FAILED | RUNNING (prior kept) or READY | a container failed to launch | read logs, fix, redeploy — see the troubleshooting reference |
INACTIVE | — | superseded by a newer version | historical only |
Read the generated URL from the service's url field (via get-container-services) — it contains a random id, so
read it, don't construct it — then confirm it responds (e.g. a curl to the URL should return a success code).
When a redeploy "does nothing"
A deployment that fails does not take the service down: if a previous deployment is running, Lightsail keeps that
one active, so the service still reports RUNNING and the URL still returns 200 — serving the old version. "It
looks healthy" is therefore not evidence the update shipped. Check get-container-service-deployments: if the newest
version is FAILED, that update never took, and the log for that version says why.
The other way an update silently doesn't land is referencing a stale image version — see image above.
Change capacity
Change power (size of each node) or scale (number of nodes) on a running service with
update-container-service, at any time and without downtime. Lightsail applies it by re-deploying the current
deployment for you — you don't create a deployment yourself, and you never need to delete and recreate the service.
The re-deploy keeps the same deployment version, and no other deployment can be created until the update finishes.
The monthly cost becomes the new power × scale. Read get-container-service-powers for the available sizes and
prices rather than quoting remembered ones.
Roll back
Every deployment is saved as a version (Lightsail keeps a limited number of the most recent ones — see the Lightsail
quotas for the current limit — past that, the oldest are dropped and can no longer
be redeployed from). Roll back by creating a new deployment from a prior version; that produces a new version whose
spec matches the old one, since there is no "reactivate this version" operation. If you redeploy from a FAILED
version, fix the cause first or it will fail the same way.
Tear down
Deleting the service stops all charges.
aws lightsail delete-container-service --service-name NAME --region REGIONRequirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server, Needs network access, Needs an API key, Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- AWS
- Publisher
- AWS (Official)
- Source
- aws/agent-toolkit-for-aws · skills/specialized-skills/web-and-mobile-development/deploying-containers-to-amazon-lightsail · commit 0a218f8
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- NOTICE (added by AutoGineer from NOTICE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by AWS.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download deploying-containers-to-amazon-lightsail.zip