Skip to content

chawkitariq/gitlab

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GitLab Infrastructure on AWS

Terraform deployment of a production GitLab CE instance on AWS. GitLab runs as Omnibus directly on EC2 using the official GitLab CE AMI — no Docker, no ECS.

Architecture

Dual load balancer pattern with EC2 as the single compute unit:

GitLab AWS Infrastructure

Component Details
EC2 t3.xlarge (4 vCPU, 16 GB RAM) — GitLab Omnibus, IMDSv2, SSM access
EBS gp3 100 GB encrypted — root volume, daily snapshots via AWS Backup (7-day retention)
ALB HTTP→HTTPS redirect, TLS termination (ACM), health check /-/readiness
NLB SSH TCP passthrough port 22
RDS PostgreSQL 17.2, db.t3.medium, Single-AZ, encrypted, deletion protection enabled
ElastiCache Redis 7.0, cache.t4g.small, 1 node, in-transit + at-rest encryption
S3 Artifacts, uploads, LFS, packages, CI secure files — versioning, AES256, TLS-only policy, lifecycle
Secrets Manager RDS password + Redis token auto-generated; SES SMTP password derived from IAM access key
SES Domain identity, DKIM, mail-from — SMTP via email-smtp.<region>.amazonaws.com:587
Route53 gitlab.<domain> → ALB, ssh.gitlab.<domain> → NLB
CloudWatch Log group (30-day retention) + EC2 Auto Recovery alarm

For full architecture decisions and component details, see SPECS.md.

Prerequisites

  • AWS account with appropriate permissions
  • Terraform >= 1.10.0
  • Existing VPC with public and private subnets
  • Route53 hosted zone

Deploy

1. Configure Variables

Create terraform/terraform.tfvars:

aws_region          = "eu-west-3"
project_name        = "gitlab"
vpc_id              = "vpc-xxxxxxxx"
public_subnet_ids   = ["subnet-xxxxxxxx", "subnet-yyyyyyyy"]
private_subnet_ids  = ["subnet-xxxxxxxx", "subnet-yyyyyyyy"]
route53_zone_name   = "example.com"
gitlab_version      = "17.9.1"
rds_master_username = "gitlab"

Optional overrides (defaults shown):

ec2_instance_type = "t3.xlarge"
ebs_volume_size   = 100

gitlab_domain (gitlab.<zone>) and smtp_from_address (gitlab@<zone>) are derived automatically from route53_zone_name.

2. Apply

cd terraform

terraform init \
  -backend-config="bucket=ct-s3-state-backend" \
  -backend-config="key=gitlab-terraform.tfstate" \
  -backend-config="region=eu-west-3"

terraform plan
terraform apply

3. First Access

  • Web UI: https://gitlab.<domain>
  • Git SSH: ssh.gitlab.<domain>
# SSM shell — no SSH key needed
aws ssm start-session --target <instance-id>

# Initial root password — auto-deleted by GitLab after 24h or first login
sudo cat /etc/gitlab/initial_root_password

Runbooks

Upgrade GitLab version

Change the version in terraform.tfvars and apply. The instance is replaced with the new AMI.

EBS is always recreated on instance replacement — it is not preserved. S3 data (artifacts, uploads, LFS, packages) persists. Git repository data and /etc/gitlab/ (including gitlab-secrets.json) live on EBS and will be lost.

Critical: gitlab-secrets.json holds encryption keys for CI variables, 2FA secrets, and tokens. If this file is not restored from an AWS Backup snapshot before running gitlab-ctl reconfigure on the new instance, all encrypted database columns become unreadable. Always restore from the latest snapshot in the gitlab-backup vault before first reconfigure.

gitlab_version = "17.10.0"
terraform apply

Check GitLab health

sudo gitlab-ctl status
curl -s http://localhost/-/readiness | jq .

View application logs

# CloudWatch (remote) — log group = /ec2/<project_name>-gitlab, default: /ec2/gitlab-gitlab
aws logs tail /ec2/gitlab-gitlab --region eu-west-3 --follow

# On instance via SSM
sudo gitlab-ctl tail

Connect to the database

sudo gitlab-rails dbconsole

Troubleshooting

GitLab not responding after deploy

The first boot runs gitlab-ctl reconfigure, which takes 3–5 minutes. Wait and check:

aws ssm start-session --target <instance-id>
sudo gitlab-ctl status
sudo tail -f /var/log/gitlab/gitlab-rails/production.log

ALB health check failing

The ALB checks /-/readiness. GitLab must be fully started and the Rails app healthy. Check:

curl -v https://gitlab.<domain>/-/readiness
sudo gitlab-ctl status

Instance replaced but data is missing

S3 data (artifacts, uploads, LFS, packages) persists across replacements. Git repository data and GitLab config live on EBS — restore from the latest AWS Backup snapshot in the gitlab-backup vault. See the upgrade runbook above for the gitlab-secrets.json critical warning.

SMTP emails not sending

Verify the SES domain is verified and out of sandbox mode in the AWS console. Check GitLab SMTP config:

sudo gitlab-rails console
Notify.test_email('you@example.com', 'Test', 'Test').deliver_now

Security

  • RDS and ElastiCache in private subnets; security groups restrict inter-component traffic
  • IMDSv2 enforced on EC2; no SSH port exposed — access via SSM Session Manager only
  • All credentials in Secrets Manager (no plaintext passwords in Terraform state)
  • S3 access restricted to EC2 instance role; TLS-only enforced via bucket policy
  • Storage encrypted at rest: RDS, EBS, ElastiCache (+ in-transit)

HA Upgrade Path

Variable-only changes — no architectural refactoring required:

Component Current HA upgrade Impact
RDS Single-AZ multi_az = true ~2 min downtime
ElastiCache 1 node num_cache_clusters = 2 Live, no interruption
EC2 Single instance + Auto Recovery ASG Planned migration, architecture refactor

Related Docs

  • SPECS.md — full architecture spec, component config, decisions, and HA cost estimates
  • docs/ — architecture diagrams

About

Deploys a production GitLab instance on AWS using Terraform. GitLab runs as GitLab Omnibus directly on EC2 using the official GitLab CE AMI.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors