Skip to content

Troubleshooting

Symptoms, causes and fixes for the problems people actually hit, plus the commands to find the cause yourself.

About 15 min · Verified 8 October 2026

Find your symptom in the table, apply the fix, then re-run the check that failed. Most problems in this deployment are one of four things: a wrong Region, a wrong hostname, a security group rule, or a missing step in a network route.

Find the cause yourself first#

Run these before guessing. They tell you which layer is broken.

On the EC2 instanceIs the API running, and what did it say?
sudo systemctl status shortlink-api --no-pager
sudo journalctl -u shortlink-api -n 80 --no-pager
curl -fsS http://127.0.0.1:3000/health
On the EC2 instanceWhich hostname is the API configured to use? (password not shown)
sudo sed -n 's/.*@\(.*\):5432.*/\1/p' /etc/shortlink/shortlink.env
Your computerWhat is the database's real hostname right now?
aws rds describe-db-instances --region ap-south-1 --db-instance-identifier shortlink-db \
  --query 'DBInstances[0].Endpoint.Address' --output text
Your computerWhy does the load balancer think the target is unhealthy?
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,reason:TargetHealth.Reason,detail:TargetHealth.Description}'

Network and server#

SymptomLikely causeFix
Console cannot find a resource you just createdYou are in a different RegionCheck the Region selector at the top right. Use ap-south-1 for everything
apt-get or curl on the server hangs or times outThe private subnet has no working path to the internetIn VPCRoute tables the private tables need 0.0.0.0/0 → nat-…. Confirm the NAT gateway is Available
Session Manager tab is greyed out, or the instance is not listed in Systems ManagerMissing role, no outbound path, or too soon after launchAttach shortlink-ec2-role, check the NAT route, wait up to 10 minutes, then reboot the instance
Permission denied when you cd into /home/ubuntuYou are ssm-user, not ubuntuUse sudo -u ubuntu … for app commands, and absolute paths under /opt/shortlink
node: bad option: --env-fileNode.js older than 20.6Install Node 22 from NodeSource (chapter 10) and make sure command -v node prints /usr/bin/node
npm ci fails with EACCESThe command ran as the wrong user or in a folder ubuntu does not ownRun it as sudo -u ubuntu inside /opt/shortlink/repo/…
The password prompt consumed the next commandYou pasted the read block and the next block togetherRun read alone, enter the password, press Enter, then paste the next block

Database#

SymptomLikely causeFix
ETIMEDOUT connecting to the databaseWrong or stale hostname, or shortlink-db-sg does not allow shortlink-api-sgCompare the two hostnames from the commands above. Fix DATABASE_URL, then sudo systemctl restart shortlink-api. Check the security group rule uses the group, not an IP
no pg_hba.conf entry … no encryptionTLS is offSet DB_SSL=true in the env file and restart
password authentication failed for user "postgres"Wrong password, or special characters not encodedRecreate the file with the read and tee steps, which URL-encode for you
database "shortlink" does not existInitial database name was left emptyDelete and recreate the RDS instance with the initial database shortlink
RDS creation says the subnet group does not cover two zonesThe subnet group has subnets in only one Availability ZoneEdit shortlink-db-subnets to include both private subnets
/health returns 503 {"database":"down"}The API runs but cannot query the databaseSame as the first row. Also confirm the database Status is Available

Load balancer#

SymptomLikely causeFix
curl to the ALB returns 503No healthy targetsRegister the instance on port 3000 and wait ~30 seconds. If it stays unhealthy see the next row
Target is Unhealthy: Request timed outshortlink-api-sg does not accept port 3000 from shortlink-alb-sg, or the service is downCheck the rule (source must be the ALB's group) and systemctl is-active shortlink-api
Target is Unhealthy: Health checks failed with these codes: [503]The API is up but the database is not reachableFix the database connection first
ALB times out from the internetALB is in private subnets, or shortlink-alb-sg does not allow port 80Check the ALB's subnets are the public ones, and the inbound rule is HTTP 80 from 0.0.0.0/0
curl cannot resolve the ALB hostnameALB still provisioning, or a typo in the hostnameWait for Active; copy the DNS name again
429 Too Many RequestsThe API's built-in rate limiter (30 creates per minute per IP)Wait a minute

Website#

SymptomLikely causeFix
Website URL returns 403Public read is blockedRe-check the two unticked Block Public Access boxes and the bucket policy. Check account-level Block Public Access too
Website URL returns 404Bucket is empty, or index.html is inside a nested dist/ folderRun aws s3 ls s3://<WEB_BUCKET>/ and make sure index.html is at the root
NoSuchBucketA typo in the bucket name, or the bucket is in another RegionCopy the name from the S3 console
Site loads but the badge says API unreachableThe site was built without VITE_API_BASE_URL, or the API's CORS origin is wrongSee the next two rows
Network tab shows calls to the S3 hostname or /api/…The variable was missing at build timeRebuild with it set and upload again (chapter 11)
Console shows a CORS errorCORS_ORIGIN does not match the website origin exactlySet it to <WEB_URL> (no trailing slash), then sudo systemctl restart shortlink-api
Your browser forces HTTPS and shows a warning pageThe site has no certificate. HTTP-only by design hereChoose to continue to the HTTP site. See "What this setup does not give you"
New short links show the wrong hostBASE_URL in the env file is staleCorrect it and restart the service
Edits to the env file have no effectThe API only reads it at startsudo systemctl restart shortlink-api

Next: clean up.

Found a mistake? Edit this page on GitHub.