Skip to content

Launching an Single Server Instance of Gitlab using AWS CloudFormation



For more information on Gitlab, visit

Gitlab CFT Description

This article will walk though the contents, and usage of the included CloudFormation template that launches a single server instance of Gitlab. Single server instances, include Gitlab, PostgreSQL as the database, and Redis for session storage all wrapped into a single EC2 instance. Running the CloudFormation template will yield a fully functional single server instance installed, configured, and ready for login.

The CloudFormation template that we will be using in this tutorial instantiates the following resources:

  • Gitlab EC2 Instance with Gitlab, PostgreSQL, and Redis installed
  • Additional 25GB EBS volume mounted to /var/opt/gitlab on the EC2 Instance
  • Firewall configured with --add-service=ssh, http, https, smtp
  • Security Group Created and applied to allow TCP/SSH, TCP/HTTP, and TCP/HTTPS open to the IP address or IP Range specified in the SSHLOCATION parameter.

Gitlab CFT Pre-Requisites

You will need the following in order to utilize the content of this article:

1.    Active AWS Account:
You must have an active AWS account, with enough access to be able to create/update/delete CloudFormation stacks and EC2 instances.

Stack Deployment Setup

1.    Log into your AWS account:
Open a browser window and visit the AWS Console Page

2.    Locate and navigate to CloudFormation: From the top left side of the navigational menu bar, click on the Services menu, and then choose CloudFormation by either navigating to the Management Tools section of the listed services, or by typing the first few letters of the service name in the search box, and then choosing it from the filtered list.


3.    Copy CF Template:
We will use the following CloudFormation template in order to launch the Gitlab instance. Copy the CloudFormation template below and save it locally on your drive as gitlab_cf_deployment.yaml. If you are using a remote host to run this lab, then copy the template to your clipboard, and then on the build host, paste the template into a file using vim /media/gitlab_cf_deployment.yaml, i, paste, and save the file by typing esc, :wq!.

AWSTemplateFormatVersion: "2010-09-09"
# Description of what this CloudFormation Template is going to produce
Description: AWS CloudFormation Gitlab Template to create a Stand Alone Gitlab server stack using a single EC2 instance
# Define Parameter Variables that will be used throughout this CloudFormation template.
    Description: The URL that will be used to access Gitlab, and the URL that Gitlab will be listening for.
    Type: String
    Description: Type of EC2 instance to launch for the server. Only Compute type nodes are currently specified.
    Type: String
    Default: t2.medium
    ConstraintDescription: Must be a valid EC2 instance type
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
      - t2.xlarge
      - t2.2xlarge
      - m4.large
      - m4.xlarge
      - m4.2xlarge
      - m4.4xlarge
      - m4.10xlarge
      - m4.16xlarge
      - m5.large
      - m5.xlarge
      - m5.2xlarge
      - m5.4xlarge
      - m5.12xlarge
      - m5.24xlarge
    Description: VPC ID that this stack will be launched in.
    Type: AWS::EC2::VPC::Id
    AllowedPattern: "[a-z0-9-]*"
    Description: VPC Subnet that this stack will be launched in.
    Type: AWS::EC2::Subnet::Id
    AllowedPattern: "[a-z0-9-]*"
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance(s).
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: Must be the name of an existing EC2 KeyPair
    Description: The source IP address (/32) or source IP address range (x.x.x.x/x) that will be allowed to SSH to the EC2 instances
    Type: String
    MinLength: 9
    MaxLength: 18
    AllowedPattern: "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})"
    ConstraintDescription: Must be a valid IP CIDR range of the form x.x.x.x/x
    Description: Instance Name tag that will be used to define the Name of the instance resource(s)
    Type: String
    Default: Gitlab

# Create an easy mapping, simply mapping the region selected to the appropriate Amazon Linux 2 AMI
# AMI ID's Updated 8/20/18
      AMI: 'ami-04681a1dbd79675a5'
      AMI: 'ami-0cf31d971a3ca20d6'
      AMI: 'ami-0782017a917e973e7'
      AMI: 'ami-6cd6f714'

# Define Resources that will be launched via this template
  # EC2 Server Instance Definition
    Description: Gitlab Standalone EC2 Instance running Gitlab, Redis, and PostgreSQL for the data storage.
    Type: AWS::EC2::Instance
        # configSets is used when there are multiple configs that you want to run, for multiple instances. If not needed then just config (default) is adequate.
          default: [mountVolume, config, gitlabConfig]
        # This configSet will define how we handle the additional EBS volume that we create with the Instance. We will mount the volume in /var/opt/gitlab
              command: sudo mkdir -p /var/opt/gitlab
              command: echo -e "o\nn\np\n1\n\n\nw" | sudo fdisk /dev/sdb
              command: sleep 3
              command: sudo mkfs.ext4 /dev/sdb1
              command: e2label /dev/sdb1 GITLAB
              command: echo -e "LABEL=GITLAB     /var/opt/gitlab    ext4   defaults 0 0" >> /etc/fstab
              command: mount -a

        # This configSet will perform the actual installation of Gitlab
              curl: []
              policycoreutils-python: []
              postfix: []
              command: curl | sudo bash
              command: !Sub |
                sudo export EXTERNAL_URL='${GitlabURL}'; yum install -y gitlab-ce
              command: gitlab-ctl reconfigure
              command: sudo firewall-cmd --permanent --add-service=ssh --add-service=http --add-service=https --add-service=smtp; sudo firewall-cmd --reload
                enabled: true
                ensureRunning: true

        # Default Config, which handles installing the firewall, and CFN components to talk back to CloudFormation
              firewalld: []
              command: yum -y update
              content: !Sub |
              mode: '000400'
              owner: root
              group: root
              content: !Sub |
                action=/opt/aws/bin/cfn-init --verbose --stack=${AWS::StackName} --region=${AWS::Region} --resource=GitlabInstance
                enabled: true
                ensureRunning: true
                  - '/etc/cfn/cfn-hup.conf'
                  - '/etc/cfn/hooks.d/cfn-auto-reloader.conf'
                enabled: true
                ensureRunning: true

    # Properties of the Instance that we are launching. Here we define things like EBS volumes, SG's, The AMI used, etc..
      # Create the 25GB EBS volume that we will use for /var/opt/gitlab
        - DeviceName: /dev/sdb
            DeleteOnTermination: false
            VolumeType: gp2
            VolumeSize: 25
      # Pull the Image or AMI from the RegionMap Map we defined earlier
      ImageId: !FindInMap
        - RegionMap
        - !Ref 'AWS::Region'
        - AMI
      # Pull the Instance Type, Subnet, KeyName, etc from the Parameters we defined earlier
      InstanceType: !Ref InstanceType
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          DeleteOnTermination: true
          SubnetId: !Ref SubnetId
          # This defines the SG that we will place on the ENI, We will create the SG after the instance resource definition
            - !Ref ServerSecurityGroup
      KeyName: !Ref KeyName
       - Key: Name
         Value: !Ref InstanceTagName
      # Use the user data to instantiate the cfn service, which will report back to CloudFormaton once the instance is set up
        Fn::Base64: !Sub |     # No more Fn::Join needed
          #!/bin/bash -x
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource GitlabInstance --region ${AWS::Region}
          /opt/aws/bin/cfn-signal -e $? --region ${AWS::Region} --stack ${AWS::StackName} --resource GitlabInstance
    # Creation Policy will ensure that if the instance isn't complete within the specified window, that a rollback will occur
        Count: '1'
        Timeout: PT15M

  # Define the Security Group that will be appended to the ENI of the Instance we are creating.  
    Type: AWS::EC2::SecurityGroup
      GroupDescription: Security Group that will be used for the Gitlab instance. Open ports 22,80 and 443
      VpcId: !Ref VpcId
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SSHLocation
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref SSHLocation
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !Ref SSHLocation

# Specify any outputs for the stack.
    Description: 'Gitlab Single Server Template'
    Value: 'Gitlab Single Server Template'
    Description: 'The Public IP address of the EC2 Instance'
    Value: !GetAtt GitlabInstance.PublicIp
    Description: 'The public DNS address for this instance'
    Value: !GetAtt GitlabInstance.PublicDnsName
    Description: 'The ID of the gitlab instance that was launched'
    Value: !Ref GitlabInstance

3.    Validate the Template (Optional):
Once the CloudFormation template has been saved to a file on your local drive or remote instance, the template can be validated using the awscli.

aws cloudformation validate-template --template-body file://gitlab_cf_deployment.yaml

Launch Options:

The CloudFormation template above can be launched in 2 ways, via the CLI or the GUI. Both steps have been included below, but ONLY ONE of the methods needs to be performed. DO NOT LAUNCH USING BOTH METHODS to avoid duplicate stacks and/or launch errors.

Stack Deployment from the Console

From the CloudFormation console screen, click the Create Stack Button button to get started. If you don't have any existing stacks deployed, then you should have been directed to the CloudFormation dashboard, where you are presented with choice options where you can either create a new stack, or a new stackset. Click Create new stack from this screen. StackSets are a different topic and will not be covered in this tutorial. If you already have pre-existing stacks deployed, then you would have been brought to your main cloudformation stack list console. From this console click the Create Stack button from the top, next to the Actions button.

No Existing Stacks: Getting Started Launch Stack

Existing Stacks: Existing Stacks Launch Stack

1.    Launch Stack with Template Upload:
Once on the Select Template screen, click the second option Upload a template to Amazon S3 and click the Choose File button. In the selector box window, choose the CloudFormation template that you saved to your drive from the earlier step and then click the Next button.

Select CloudFormation Template

2.    Launch Stack with Template Editor (Optional Alternative):
If you don't want to save the CloudFormation template as a file, and upload it via S3, and would instead prefer to just copy and paste your template into the console to run it, then in the CloudFormation console window, you can also choose the Design template option. By selecting the Design Template, CloudFormation will open it's template editor, where you can click on the Template tab (1), where you can paste the template yaml or JSON syntax directly into the editor (2). Once complete, click the Create Stack button (3) in the editor to allow CloudFormation to upload and automatically launch the pasted template.

Select Design Template

CloudFormation Design Editor

3.    Define Stack Parameters:
In the Details window, Type a name for the stack, and then choose the appropriate values for the stack parameters and then click the Next button.

  • InstanceType - Instance family type, and size that you want to use for your Gitlab instance.
  • KeyName - The SSH Key pair that you want assigned to the Gitlab instance.
  • VpcId - The VPC that the Gitlab instance will be launched in.
  • SubnetId - The subnet(s) that the Gitlab instance will be launched in.
  • GitlabURL - The URL that will be configured in the /etc/gitlab/gitlab.rb file, and will tell Gitlab what URL to listen for.
  • SSHLocation - The source IP address or IP address range that will be configured in the security group for allowed ingress traffic to ports 22, 80 and 443.
  • InstanceTagName - The value that will be assigned to the tag "Name" key. This will effectively be what you want the instance to be named.

Specify Template Details

4.    Define Stack Options:
In the Options window, set up any key/value pairs, IAM roles or notifications that you want associated with the cluster, and then click the Next button.

CloudFormation Stack Options

5.    Review and Launch:
In the Review window, review your selected options, and once satisfied, click the I acknowledge that AWS CloudFormation might create IAM resources. check box, and click the Next button to launch the stack.

CloudFormation Parameter Review

Stack Deployment CLI

As an alternative to launching off CloudFormation stacks from the AWS console, if the desire or need to launch a stack from the CLI arises, then the following section may be used instead of the console method illustrated above.


aws cloudformation create-stack --stack-name {{STACK_NAME}} \
--template-body file://{{FILE_NAME}}.yaml \
--capabilities CAPABILITY_IAM \
--parameters \
ParameterKey=KeyName,ParameterValue={{KEYNAME}} \
ParameterKey=VpcId,ParameterValue={{VPCID}} \
ParameterKey=InstanceType,ParameterValue={{INSTANCE_TYPE}} \
ParameterKey=GitlabURL,ParameterValue={{GITLAB_URL}} \
ParameterKey=SSHLocation,ParameterValue={{SSH_LOCATION}} \
ParameterKey=InstanceTagName,ParameterValue={{INSTANCE_TAG_NAME}} \

  • InstanceType - Instance family type, and size that you want to use for your Gitlab instance.
  • KeyName - The SSH Key pair that you want assigned to the Gitlab instance.
  • VpcId - The VPC that the Gitlab instance will be launched in.
  • SubnetId - The subnet(s) that the Gitlab instance will be launched in.
  • GitlabURL - The URL that will be configured in the /etc/gitlab/gitlab.rb file, and will tell Gitlab what URL to listen for.
  • SSHLocation - The source IP address or IP address range that will be configured in the security group for allowed ingress traffic to ports 22, 80 and 443.
  • InstanceTagName - The value that will be assigned to the tag "Name" key. This will effectively be what you want the instance to be named.

Example Request: (Replace KeyName, VpcId, SubnetId, GitLabURL, SSHLocation, InstanceType and InstanceTagName Parameters With Your Values)

aws cloudformation create-stack --stack-name Gitlab \
--template-body file://gitlab_cf_deployment.yaml \
--capabilities CAPABILITY_IAM \
--parameters \
ParameterKey=KeyName,ParameterValue=My_AWS_Key \
ParameterKey=VpcId,ParameterValue=vpc-a12345bc \
ParameterKey=InstanceType,ParameterValue=t2.medium \
ParameterKey=GitlabURL, \
ParameterKey=SSHLocation,ParameterValue= \
ParameterKey=InstanceTagName,ParameterValue=Gitlab \

Example Response:

    "StackId": "arn:aws:cloudformation:us-east-2:012345678910:stack/Gitlab/123a4567-8b9c-10d1-d112-13efa1bc4d1e"

Stack Verification

1.    Monitor the Launch:
Once the create button has been pushed, CloudFormation will begin to create the stack and all stack dependencies. You can watch the progress of the launch in the CloudFormation service console window.

CloudFormation Launch Template

2 .    Verify the Stack:
Once the stack has been successfully launched by showing the CREATE_COMPLETE status, test the deployment, by clicking on the Output tab and copying the either the PublicIP, or ServerAddress value from the outputs section of the CloudFormation launch window.

CloudFormation Stack Complete

3 .    Load Gitlab:
Once the address to Gitlab has been copied out of the CloudFormation Console Outputs section, paste the address into a browser and pressing Enter. Once pressed, your browser should load Gitlab correctly.

Gitlab Application Screen

Finalizing your Setup

Now that CloudFormation has successfully launched the Gitlab stack, we need to perform a few administrative actions on the instance in order to get Gitlab ready for usage.

1.    Set your password:
When you first complete the Gitlab initialization, the first thing that you will need is to set a system root password. From the main page, Gitlab will display the set password form. Choose a strong password, confirm the password and then press the Change Your Password button.

Gitlab Root Password

2.    Login as root:
Once you have set the initial root password, login into Gitlab with the username of root, using the password that you just set in the previous section.

Gitlab Login

3.    Create New User:
Once you login, the first task you will want to perform is to set up a new non-root user. In order to do this, go to the menu bar at the top of the page, and click on the wrench icon Admin area button.

Gitlab Admin Area

Next, from the Admin area, click on the Users navigational item from the navigation bar on the left side of the screen. Once the screen has loaded, click on the New user button in the top right hand corner.

Gitlab Users

Next, in the New user screen, fill in the users name, username, email address, and then choose their appropriate access level, along with any other optional data about the user, and click the Create user button.

Valid E-Mail NOTE:

When creating a new user, be sure to use a legitimate email address, as the set password link will be sent via email.

Gitlab Create User

Gitlab User Created

After the user has been created, as the root user you can logout, using the menu item in the top right hand corner of the navigation bar at the top of the screen.

4.    Set New User Password:
Check your email, and you should have received an email message similar to the one below, that will contain a link to set your new users password.


If the email didn't get sent properly for some reason, the user's password can be set via the Admin area by the root user.

Gitlab User Email

Once the link has been clicked, you will be redirected to a set password screen that is identical to what you saw in the setting the root password section above. As before, set the user password, confirm, click on the Change your password button, then login with the new user name and newly set password.

5.    Set New User MFA:
Once you are logged in, then we need to set up our Multi-Factor Security, and configure our SSH key that will be used to push code to the server. These configurations will be set up in your user profile. So from the main login screen, click the user icon in the upper right hand corner of the navigation bar at the top of the screen and then choose Settings from the drop menu.

Gitlab User Profile

From the user menu, on the left hand side, choose the Account option from the menu. In the Account Menu screen click the Enable two factor authentication button. On the MFA screen, register your MFA device such as Authy, or Google Authenticator by scanning the QR Code, and typing in the given PIN.

Gitlab MFA

Gitlab Register MFA

6.    Set New User SSH Keys:
Now that we have our MFA set, next we need to set an SSH key that will be used with Gitlab in order to interact with the Gitlab server. Follow the steps on your platform to generate an SSH key on your workstation. Once generated, copy the public key into your clipboard. From the User Settings menu, click on SSH Keys. In the SSH Keys screen, Paste the public key, name it, and click the Add key button.

Gitlab SSH Keys

We should be all set up now to make our first commit !!

Gitlab CF Conclusion

At this point we have a fully functioning Gitlab CE, single server instance fully configured and ready for code push. This setup is ideal for learning the Gitlab platform or testing different deployment scenarios, however for a full production configuration, Gitlab should be set up in an HA configuration consisting of the Gitlab front end being spread across more then one single AZ, A shared Gitlab directory configured on a network file system such as NFS, EFS, or GlusterFS, a redundant external PostgreSQL replicated database, and an HA instance of Redis.

Gitlab CF Additional Resources

Below you can find additional resources to supplement the information found in this tutorial.

Launch Gitlab Stack

Use the button below to automatically launch this cloudformation template and create your own Gitlab Single Servier instance Stack.

Launch Gitlab Stack

CloudFormation Launch

In order to use the button above you must already be logged into your AWS account. This link will launch the template the us-east-1 region. If you wish to use a different region, then copy the link and change the region=us-east-1# portion of the URL to the appropriate region.

Change Launch URL

Gitlab CloudFormation Template Download

Download the Gitlab CloudFormation Template here

Gitlab Manual Installation

In the event that you don't want to use CloudFormation in order to setup Gitlab, the following steps can be followed to install Gitlab on any Bare Metal (BM) or Virtual Machine (VM) based instance.

RHEL RHEL,   CentOS CentOS,   &   Amazon Linux Amazon Linux

1.    Install Required Packages:
Install the required packages via Yum

yum clean all
yum install -y curl policycoreutils-python postfix

2.    Install the Gitlab Repository:
Now that the pre-requisite packages are installed, its time to install Gitlab.

curl | sudo bash


The following command will install the repository for Gitlab Community Edition (CE), if you wish to install Gitlab Enterprise, then replace the above URL in the command with the Enterprise Edition (EE) URL curl | sudo bash

3.    Set the EXTERNAL_URL Variable:
Gitlab will look for a system variable named EXTERNAL_URL when it is installed. It will use this value to fill in the external_url parameter in its /etc/gitlab/gitlab.rb configuration file. If you don't complete this step, it can be done manually later.

export EXTERNAL_URL=""

4.    Install Gitlab:

yum install -y gitlab-ce


The following command will install Gitlab Community Edition (CE), if you wish to install Gitlab Enterprise Edition (EE), then replace the above command with the enterprise package instead
yum install -y gitlab-ee

5.    Customize the Gitlab Configuration File:
Before launching the Gitlab configuration builder, edit the /etc/gitlab/gitlab.rb file to customize how Gitlab will configure itself. The configuration file will allow you to do things like turn the snippets/pages/runners/docker-registry features on and off. It will also allow you to configure Gitlab to use external PostgreSQL/Redis services instead of installing them locally on the single instance that we have configured above. Parse through the file, edit it to meet your requirements, turning whatever services on and off that you would like, and then move on to the next step to instantiate the Gitlab instance.

vim /etc/gitlab/gitlab.rb

6.    Initiate the Gitlab Configuration:
This step will launch the Chef Gitlab installer using the values set in the /etc/gitlab/gitlab.rb file that we configured in an earlier step. Using the parameters in the config file, Gitlab will configure itself to install all required components locally, instantiate externals PostgreSQL/Redis services instead of locally installing those components, and turn services on or off, such as the CI/CD runners, or built in Docker Registry. The configuration file can always be changed in the future and Gitlab can be reconfigured easily to meet your evolving needs.

gitlab-ctl reconfigure

7.    Firewall Configuration:
In the event that you are using firewalld to further protect your Bare Metal/AWS Instance, the following services/ports need to be open to allow ingress requests/egress responses:

sudo firewall-cmd --permanent --add-service=ssh --add-service=http --add-service=https --add-service=smtp
sudo firewall-cmd --reload

8.    Start Gitlab Required Services:
Now that Gitlab is installed and configured, lets start all of the Gitlab services.

systemctl enable postfix.service
systemctl start postfix.service

Controlling Gitlab with SystemCtl

The Gitlab unit file is installed and configured automatically to start on boot

9.    Controlling the Gitlab Service:
Now that the Gitlab daemon is running, we now can control Gitlab using the built in Gitlab-Ctl service commandlet. This cmdlet can be used to perform tasks such as starting, stopping, restarting, and reconfiguring Gitlab along with all of Gitlab's related services using a single command. Issuing a gitlab-ctl stop for example, will stop not only Gitlab, but also the Gitlab PostgreSQL instance, as well as the Gitlab Redis instance. gitlab-ctl reconfigure is used whenever a change to the /etc/gitlab/gitlab.rb file has been made. The reconfigure command will ensure that any changes made to the configuration file are made to Gitlab as well as all Gitlab support services.

# Start all GitLab components
sudo gitlab-ctl start

# Stop all GitLab components
sudo gitlab-ctl stop

# Restart all GitLab components
sudo gitlab-ctl restart

# Check all GitLab components
sudo gitlab-ctl status

# Reconfigure Gitlab
sudo gitlab-ctl reconfigure

Gitlab CF Site/Information References