Kuberns runs on AWS. That sounds like it should make this the easiest migration on the list, and in one way it does: services you want to keep, such as S3 and SQS, can stay exactly where they are.
But Kuberns provisions its own infrastructure. It does not adopt your existing EC2 instances, RDS databases, or load balancers. So this migration is not a transfer of resources. It is a decision, service by service, about what moves and what stays.
That decision is most of the work, and it is worth making deliberately before you touch anything.
Where is your application running now?
The starting point changes the shape of the migration.
- EC2 with systemd. Your application runs because someone configured a server. Most of what makes it work is on the instance, not in Git. This is the largest migration of the four, and the DigitalOcean guide's Droplet section is a good checklist for finding that configuration.
- Elastic Beanstalk. Closest to a like-for-like move. Your Procfile, your environment properties, and your platform's start command translate almost directly.
- ECS or Fargate. Your task definition already declares the container, the command, the port, and the environment. That document is your migration plan.
- EKS. Your deployment manifests hold the same information. Expect the harder questions to be about what else the cluster was doing for you: service mesh, ingress rules, secrets injection, autoscaling behaviour.
What moves, and what should stay
This table is the important part of the page.
| AWS service | Recommendation |
|---|---|
| EC2, ECS, Fargate, Beanstalk, EKS | Moves. This is the workload Kuberns replaces |
| RDS | Either. Move to a managed datastore, or keep it and point environment variables at it, provided the new environment can reach it |
| ElastiCache | Either, on the same reasoning as RDS |
| S3 | Stays. Keep the bucket and move the credentials. See the IAM note below |
| SQS, SNS, EventBridge | Stays. These are reachable from anywhere with credentials |
| Application Load Balancer, target groups | Replaced by custom domains |
| Route 53 | Stays as your DNS provider. Only the records change |
| ACM certificates | Replaced. Kuberns provisions SSL for the domains you add |
| Secrets Manager, Parameter Store | Either. Keep it and read at runtime, or move values into environment variables |
| CloudWatch Logs | Replaced by the environment's logs |
| EventBridge scheduled rules, cron | Needs a new home. An in-application scheduler in a worker, or kept external |
| IAM roles and instance profiles | Needs real work. See below |
Anything in the "stays" column is work you do not have to do, which is why an AWS migration is often smaller than it first appears.
The IAM problem
This is the item most likely to surprise you, so it gets its own section.
On EC2, ECS, or EKS, your application almost certainly gets its AWS credentials ambiently, from an instance profile, a task role, or a service account. Nothing in your code holds a key. The SDK just works.
On Kuberns, that ambient identity does not exist. Any AWS service your application keeps using, S3, SQS, SES, needs explicit credentials supplied as environment variables.
So before you migrate:
- List every AWS API your application calls.
- Create an IAM user scoped to exactly those actions and resources. Do not reuse a broad role.
- Generate an access key for it.
- Supply the key and secret as environment variables on the environment.
- Confirm your code path actually reads credentials from the environment. Most SDKs do this by default, but code written against an instance profile sometimes hard-codes a provider chain.
If your buckets have policies that restrict access by principal or by VPC endpoint, those policies need updating too.
Before you start
Collect:
- The repository, branch, and root directory.
- Your container command and port, from the task definition, the Beanstalk Procfile, or the systemd unit.
- Every environment variable, including anything injected from Secrets Manager or Parameter Store.
- The full list of AWS services the application calls, for the IAM work above.
- Scheduled rules, cron entries, and one-off jobs.
- Custom domains and their current TTLs.
- A fresh database dump.
pg_dump --no-owner --no-acl -Fc \
-h <rds-endpoint> -U <user> -d <database> -f aws-dump.dumpLeave the existing stack running. It is your rollback until Step 8 is verified.
Step 1: Connect the repository
Create the service from your Git provider and select the branch you want to deploy. Deploy it as a non-production environment first, on the Kuberns-provided URL. Your existing AWS stack is unaffected.

Coming from EC2, confirm first that the repository contains everything needed to build. Manually installed dependencies and server-only patches surface at this step.
Step 2: Check what the agent detected
The agent reports the framework, root directory, dependency file, base image, web port, build commands, and process commands.

Check the detected result against the authority for your platform: the task definition's command and portMappings, the Beanstalk Procfile, or the systemd ExecStart line. Where they disagree, your existing configuration is right. See agent failures if the result is wrong.
Step 3: Map your processes
Every long-running process in your current stack needs a resource on the environment:
- The application server becomes the server resource.
- Each worker, queue consumer, or sidecar-style process becomes a background worker resource with its own Procfile command.
- Anything outside those categories can use the miscellaneous resource type.
If you were running several ECS services or several Kubernetes deployments from one repository, decide which become separate Kuberns services and which become resources on one service. Separate applications become separate services; multiple process types of one application become resources on a single service.
Step 4: Recreate variables and provision resources
Add your environment variables to the environment, matching key names exactly, including case.
Three groups need attention:
- AWS credentials. From the IAM section above. This is new configuration, not something you copy across.
- Secrets Manager and Parameter Store values. If you keep reading them at runtime, the application still needs credentials with permission to do so. If you move them, they become ordinary environment variables.
- Connection strings. If you are moving RDS or ElastiCache onto Kuberns, these must point at the new resources. If you are keeping them, they carry over unchanged, provided the new environment can reach them.

Create any database, cache, or queue resources you are moving from the environment's Resources tab.

Connection details for a managed database, its name, username, password, and hostname, live on its datastore overview page.
Environment variables apply on the next deploy, and saving them triggers one automatically.
Step 5: Move your data
Skip this entirely if you are keeping RDS. Otherwise, Kuberns gives you an empty managed database and credentials to reach it, and loading the dump is your step.
# PostgreSQL
pg_restore --no-owner --no-acl \
-h <kuberns-hostname> -U <username> -d <database> \
aws-dump.dumpUse mysql or mongorestore for the other supported database types.
Kuberns does not restore a backup into a running datastore for you, in either direction. Its own backups are dumps you download and load the same way. Test that path once now, while nothing depends on it.
Run the import twice: once now against the test environment, and once again as the final sync during cutover.
Step 6: Validate before cutting over
Work through the test environment on its Kuberns URL with production-shaped data.
- The application boots and serves requests.
- Every AWS call still succeeds. Uploads to S3, messages onto SQS, mail through SES. This is where IAM problems appear, and they appear as permission errors rather than crashes.
- Background workers pick up jobs, and every scheduled rule has a working replacement.
- Migrations have run.
- Behaviour your load balancer used to provide, redirects, headers, request size and timeout limits, still holds.
- Outbound integrations and webhooks reach the new environment.

Exercise the AWS calls deliberately rather than waiting to notice them. A missing S3 permission often fails quietly on a code path that runs rarely.
Step 7: Lower your DNS TTL
Do this a day ahead, in Route 53 or wherever your records live. Drop the TTL on the records you are about to change to something short, such as 300 seconds, and wait for the old TTL to expire. Your rollback speed on cutover day is set entirely by the TTL you chose the day before.
Step 8: Move the domain
Add the hostname under the environment's Custom Domains, then replace your existing record, most likely an alias to a load balancer, with the target Kuberns shows you.
Subdomain CNAME api -> <Kuberns hostname shown in the dashboard>
Root domain A @ -> <server IP shown in the dashboard>
The domain moves through DNS verification, SSL provisioning, and activation. See DNS, SSL, and activation if it stalls.
Run the final data sync immediately before the switch, while the old stack is not accepting writes.
Rollback
Keep the existing stack running until you are confident. With a short TTL, rolling back is pointing DNS back at the load balancer.
If you kept RDS and S3 in place, rollback stays clean for as long as both environments can reach them. That is a real argument for moving compute first and data later, rather than doing everything in one cutover.
Common problems
S3 or SQS calls fail with a permission error. The application was relying on an instance profile or task role. It now needs explicit credentials in environment variables.
The build fails although the application ran fine on EC2. A dependency was installed on the instance by hand and is not declared in the repository.
The application cannot reach the database you kept. RDS is not reachable from the new environment. Check its network configuration.
The application is unreachable although the deploy succeeded. The port does not match what the target group was sending to.
Requests fail at a size or timeout that used to work. Those limits were on the load balancer, not in your application.
Scheduled work never runs. EventBridge rules and cron entries do not migrate. Each needs a replacement.