Skip to content

Verify and harden

An end-to-end checklist, the security checks that matter, and what to change before real users.

About 15 min · Verified 8 October 2026

0 of 5 steps done0%

Do not skip this chapter. A short, deliberate check now saves an hour of confused debugging in the CI/CD guides.

End-to-end test in the browser#

Open <WEB_URL> and:

  1. Confirm the badge says API online.
  2. Create a short link for https://aws.amazon.com/, with the alias hello-aws.
  3. Copy the short link. Its host must be your load balancer hostname (this proves BASE_URL).
  4. Open it in a new tab. You land on aws.amazon.com.
  5. Return to the app and open the link's analytics. The click count is at least 1 and the referrer and device appear.
  6. Create a second link with an expiry in the past or a disabled state and confirm it returns an error page (HTTP 410) instead of redirecting.

Look at the network calls#

Open the browser's developer tools → Network, then reload the page. Every /api/... request should go to your load balancer hostname, with status 200, and there should be no red CORS errors in the Console.

Infrastructure checks#

Confirm the server and database are private#

Your computerThe instance must have no public IP
aws ec2 describe-instances --region ap-south-1 \
  --filters Name=tag:Name,Values=shortlink-api Name=instance-state-name,Values=running \
  --query 'Reservations[].Instances[].{id:InstanceId,publicIp:PublicIpAddress,privateIp:PrivateIpAddress}' --output table

publicIp must be None.

Your computerThe database must not be public
aws rds describe-db-instances --region ap-south-1 --db-instance-identifier shortlink-db \
  --query 'DBInstances[0].PubliclyAccessible'

The answer must be false.

Confirm the target is healthy#

Your computerTarget health
aws elbv2 describe-target-health --region ap-south-1 \
  --target-group-arn "$(aws elbv2 describe-target-groups --region ap-south-1 --names shortlink-app-tg --query 'TargetGroups[0].TargetGroupArn' --output text)" \
  --query 'TargetHealthDescriptions[].{id:Target.Id,state:TargetHealth.State}' --output table
You should see
One row with your instance ID and state: healthy.

Test that the API cannot be reached around the load balancer#

The instance has no public address, so there is nothing to test from the internet. That is the point: the only way in is the load balancer. If you want to see the firewall rule that enforces it, run:

Your computerWho may reach port 3000?
aws ec2 describe-security-groups --region ap-south-1 --filters Name=group-name,Values=shortlink-api-sg \
  --query 'SecurityGroups[0].IpPermissions[].{port:FromPort,sourceGroups:UserIdGroupPairs[].GroupId,cidrs:IpRanges[].CidrIp}'

cidrs must be empty and sourceGroups must contain exactly one ID, the load balancer's group.

What this setup does not give you#

This is a workshop deployment. Be honest about what is missing before you reuse it for anything real.

AreaWhat you haveWhat production needs
TransportPlain HTTP on the website and the APIHTTPS everywhere: a domain, an ACM certificate, an HTTPS listener, and CloudFront in front of S3
AvailabilityOne API server, one database in one zoneTwo or more API servers (Auto Scaling) across zones, and Multi-AZ RDS
DeploysIn-place, with a short outage per releaseRolling or blue/green deployments
SecretsPassword in a root-owned file on the serverAWS Secrets Manager or Parameter Store
ObservabilityLogs on the instance onlyCloudWatch Logs and alarms for target health, 5xx errors and database CPU and storage
Cost controlManual clean-upBudgets, tagging, and scheduled shutdown for non-production

Where to go next#

  • Guide 2: Backend CI/CD on EC2. Stop logging in to deploy. Pushes to your fork update the API.
  • Guide 3: Frontend CI/CD to S3. Pushes to your fork rebuild and publish the website.

You can do either one first, or both. Keep this deployment running while you do them. Remember to run the Clean up chapter when you finish.

Next: troubleshooting.

Found a mistake? Edit this page on GitHub.