DEV Community

JImmyWong for AWS Community Builders

Posted on • Originally published at Medium on

AWS CloudFormation to build your VPN(Wireguard)

First, you need create your AWS account, if you no, you can follow the link to register the new AWS account

How to use AWS for free? (Tips for teaching AWS in College.)

First one, you need to know what is Wireguard, Wireguard is new protocol in vpn area, here has the link to know more details.

https://www.wireguard.com/

in some big vpn company also use this protocol to create the vpn service, something like surfshark vpn

Create the Key pair in AWS console

Login the AWS account and directly input EC2 in the search bar or click EC2 in the console

Select Key pair and remember choose you want region

in the lab, i choose Singapore

in the lab, i choose Singapore

_in this page select Create key pair(i created test key before in this page

in this page select Create key pair(i created test key before in this page)

please type in the key name and keep other default option click create key pair

please type in the key name and keep other default option click create key pair

then, you should created new key wire and auto download the private key in your computer

then, you should created new key wire and auto download the private key in your computer

Create vpn use cloudformation

go to the search bar and go to the cloudformation page

go to the search bar and go to the cloudformation page

select stack

select stack

create stack

create stack

select Upload a template file and Choose file

select Upload a template file and Choose file

Here is the code hints

InstanceType: t2.micro is a small server in the AWS, you can follow the user size to choose server size

KeyName: wire

TZ=Asia/Singapore, choose your time zone, i will put down the link to you about time zone database

Server Size

Time zone database

Please save the code to your computer, i called it wire.yaml( filetype is .yaml, it is cloudformation file type )

Cloudformation Detail

AWSTemplateFormatVersion: '2010-09-09'
Description: aws ec2 wire
Parameters:
  VPCName:
    Description: The name of the VPC being created.
    Type: String
    Default: "VPC Public and Private with NAT"
Mappings:
  SubnetConfig:
    VPC:
      CIDR: "10.0.0.0/16"
    Public0:
      CIDR: "10.0.0.0/24"
    Public1:
      CIDR: "10.0.1.0/24"
    Private0:
      CIDR: "10.0.2.0/24"
    Private1:
      CIDR: "10.0.3.0/24"

  AZRegions:
    ap-southeast-1:
      AZs: ["a", "b"]

Resources:
  WireEIP:
    Type: AWS::EC2::EIP
    Properties:
      InstanceId: !Ref EC2Instance

  EC2Instance:
    Type: AWS::EC2::Instance
    DependsOn: InstanceSecurityGroup
    Properties:
      InstanceType: t2.micro _#Server Size_  
SecurityGroupIds: [!Ref 'InstanceSecurityGroup']
      KeyName: wire _#Your Key name_  
ImageId: ami-0c802847a7dd848c0
      SubnetId: !Ref PublicSubnet0
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe
          sudo yum update -y 
          sudo yum install docker -y
          sudo usermod -a -G docker ec2-user
          sudo systemctl enable docker.service
          sudo systemctl start docker.service
          docker pull linuxserver/wireguard
          docker run -d \
          --name=wireguard \
          --cap-add=NET_ADMIN \
          --cap-add=SYS_MODULE \
          -e PUID=1000 \
          -e PGID=1000 \
          -e TZ=Asia/Singapore \
          -e SERVERPORT=51820 \
          -e PEERS=1 \
          -e PEERDNS=auto \
          -e INTERNAL_SUBNET=10.13.13.0 \
          -e ALLOWEDIPS=0.0.0.0/0 \
          -e LOG_CONFS=true \
          -p 51820:51820/udp \
          -v /wire/appdata/config:/config \
          -v /lib/modules:/lib/modules \
          --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
          --restart unless-stopped \
          linuxserver/wireguard

  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    DependsOn: VPC
    Properties:
      GroupDescription: Enable SSH access via port 22
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: udp
          FromPort: 51820
          ToPort: 51820
          CidrIp: 0.0.0.0/0
      VpcId: !Ref VPC

  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      CidrBlock:
        Fn::FindInMap:
          - "SubnetConfig"
          - "VPC"
          - "CIDR"
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Public"
        - Key: "Name"
          Value: !Ref 'VPCName'

  PublicSubnet0:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId:
        Ref: "VPC"
      AvailabilityZone:
        Fn::Sub:
          - "${AWS::Region}${AZ}"
          - AZ: !Select [0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]
      CidrBlock:
        Fn::FindInMap:
          - "SubnetConfig"
          - "Public0"
          - "CIDR"
      MapPublicIpOnLaunch: "true"
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Public"
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-public-'
              - !Select [0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]

  PublicSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId:
        Ref: "VPC"
      AvailabilityZone:
        Fn::Sub:
          - "${AWS::Region}${AZ}"
          - AZ: !Select [1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]
      CidrBlock:
        Fn::FindInMap:
          - "SubnetConfig"
          - "Public1"
          - "CIDR"
      MapPublicIpOnLaunch: "true"
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Public"
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-public-'
              - !Select [1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]

  PrivateSubnet0:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId:
        Ref: "VPC"
      AvailabilityZone:
        Fn::Sub:
          - "${AWS::Region}${AZ}"
          - AZ: !Select [0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]
      CidrBlock:
        Fn::FindInMap:
          - "SubnetConfig"
          - "Private0"
          - "CIDR"
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Private"
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-private-'
              - !Select [0, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]

  PrivateSubnet1:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId:
        Ref: "VPC"
      AvailabilityZone:
        Fn::Sub:
          - "${AWS::Region}${AZ}"
          - AZ: !Select [1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]
      CidrBlock:
        Fn::FindInMap:
          - "SubnetConfig"
          - "Private1"
          - "CIDR"
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Private"
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-private-'
              - !Select [1, !FindInMap [ "AZRegions", !Ref "AWS::Region", "AZs"] ]

  InternetGateway:
    Type: "AWS::EC2::InternetGateway"
    Properties:
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Public"
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-IGW'

  GatewayToInternet:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      VpcId:
        Ref: "VPC"
      InternetGatewayId:
        Ref: "InternetGateway"

  PublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Public"
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-public-route-table'

  PublicRoute:
    Type: "AWS::EC2::Route"
    DependsOn: "GatewayToInternet"
    Properties:
      RouteTableId:
        Ref: "PublicRouteTable"
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId:
        Ref: "InternetGateway"

  PublicSubnetRouteTableAssociation0:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId:
        Ref: "PublicSubnet0"
      RouteTableId:
        Ref: "PublicRouteTable"

  PublicSubnetRouteTableAssociation1:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId:
        Ref: "PublicSubnet1"
      RouteTableId:
        Ref: "PublicRouteTable"

  PublicNetworkAcl:
    Type: "AWS::EC2::NetworkAcl"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Application"
          Value:
            Ref: "AWS::StackName"
        - Key: "Network"
          Value: "Public"
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-public-nacl'

  InboundHTTPPublicNetworkAclEntry:
    Type: "AWS::EC2::NetworkAclEntry"
    Properties:
      NetworkAclId:
        Ref: "PublicNetworkAcl"
      RuleNumber: "100"
      Protocol: "-1"
      RuleAction: "allow"
      Egress: "false"
      CidrBlock: "0.0.0.0/0"
      PortRange:
        From: "0"
        To: "65535"

  OutboundPublicNetworkAclEntry:
    Type: "AWS::EC2::NetworkAclEntry"
    Properties:
      NetworkAclId:
        Ref: "PublicNetworkAcl"
      RuleNumber: "100"
      Protocol: "-1"
      RuleAction: "allow"
      Egress: "true"
      CidrBlock: "0.0.0.0/0"
      PortRange:
        From: "0"
        To: "65535"

  PublicSubnetNetworkAclAssociation0:
    Type: "AWS::EC2::SubnetNetworkAclAssociation"
    Properties:
      SubnetId:
        Ref: "PublicSubnet0"
      NetworkAclId:
        Ref: "PublicNetworkAcl"

  PublicSubnetNetworkAclAssociation1:
    Type: "AWS::EC2::SubnetNetworkAclAssociation"
    Properties:
      SubnetId:
        Ref: "PublicSubnet1"
      NetworkAclId:
        Ref: "PublicNetworkAcl"

  ElasticIP0:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: "vpc"

  ElasticIP1:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: "vpc"

  NATGateway0:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId:
        Fn::GetAtt:
          - "ElasticIP0"
          - "AllocationId"
      SubnetId:
        Ref: "PublicSubnet0"

  NATGateway1:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId:
        Fn::GetAtt:
          - "ElasticIP1"
          - "AllocationId"
      SubnetId:
        Ref: "PublicSubnet1"

  PrivateRouteTable0:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-private-route-table-0'

  PrivateRouteTable1:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId:
        Ref: "VPC"
      Tags:
        - Key: "Name"
          Value: !Join
            - ''
            - - !Ref "VPCName"
              - '-private-route-table-1'

  PrivateRouteToInternet0:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId:
        Ref: "PrivateRouteTable0"
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId:
        Ref: "NATGateway0"

  PrivateRouteToInternet1:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId:
        Ref: "PrivateRouteTable1"
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId:
        Ref: "NATGateway1"

  PrivateSubnetRouteTableAssociation0:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId:
        Ref: "PrivateSubnet0"
      RouteTableId:
        Ref: "PrivateRouteTable0"

  PrivateSubnetRouteTableAssociation1:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId:
        Ref: "PrivateSubnet1"
      RouteTableId:
        Ref: "PrivateRouteTable1"

Outputs:
  InstanceId:
    Description: InstanceId of the newly created EC2 instance
    Value: !Ref 'EC2Instance'
  AZ:
    Description: Availability Zone of the newly created EC2 instance
    Value: !GetAtt [EC2Instance, AvailabilityZone]
  PublicDNS:
    Description: Public DNSName of the newly created EC2 instance
    Value: !GetAtt [EC2Instance, PublicDnsName]
  PublicIP:
    Description: Public IP address of the newly created EC2 instance
    Value: !GetAtt [EC2Instance, PublicIp]

  VPCId:
    Description: "VPCId of VPC"
    Value:
      Ref: "VPC"
    Export:
      Name: !Sub "${AWS::Region}-${AWS::StackName}-VPC"

  PublicSubnet0:
    Description: "SubnetId of public subnet 0"
    Value:
      Ref: "PublicSubnet0"
    Export:
      Name: !Sub "${AWS::Region}-${AWS::StackName}-PublicSubnet0"

  PublicSubnet1:
    Description: "SubnetId of public subnet 1"
    Value:
      Ref: "PublicSubnet1"
    Export:
      Name: !Sub "${AWS::Region}-${AWS::StackName}-PublicSubnet1"

  PrivateSubnet0:
    Description: "SubnetId of private subnet 0"
    Value:
      Ref: "PrivateSubnet0"
    Export:
      Name: !Sub "${AWS::Region}-${AWS::StackName}-PrivateSubnet0"

  PrivateSubnet1:
    Description: "SubnetId of private subnet 1"
    Value:
      Ref: "PrivateSubnet1"
    Export:
      Name: !Sub "${AWS::Region}-${AWS::StackName}-PrivateSubnet1"

  DefaultSecurityGroup:
    Description: "DefaultSecurityGroup Id"
    Value: !GetAtt VPC.DefaultSecurityGroup
    Export:
      Name: !Sub "${AWS::Region}-${AWS::StackName}-DefaultSecurityGroup"
Enter fullscreen mode Exit fullscreen mode

click Next

click Next

type the stack name you want and Next

type the stack name you want and Next

keep the default option and scroll down click Next

keep the default option and scroll down click Next

keep the default option and scroll down click Create stack

keep the default option and scroll down click Create stack

Waiting the VPN resource create
Waiting the VPN resource create

If you can see Create Complated, then, your VPN is created successfully
If you can see Create Complated, then, your VPN is created successfully

go to the EC2
go to the EC2

Choose Instance
Choose Instance

click connect
click connect

Choose SSH client and click the logo to make a copy
Choose SSH client and click the logo to make a copy

open your cmd or terminal

chmod 400 wire.pem(this is your downloaded key from step 1)

scp -i wire.pem ec2-user@ec2–18–142–192–30.ap-southeast-1.compute.amazonaws.com:/wire/appdata/config/peer1/peer1.png .

(the scp ip address please use yourself , no must 18.142.192.30)

If windows system please use SSH Client to help you finish this step i suggest e.g: Bitvise SSH Client

then you can use wireguard client to scan the peer1.png in your computer

click create by QR code
click create by QR code

the info will auto put in your apps

open the google search check your public ip

Wireguard some config in cloudformation code

docker run -d \
          --name=wireguard \
          --cap-add=NET_ADMIN \
          --cap-add=SYS_MODULE \
          -e PUID=1000 \
          -e PGID=1000 \
          -e TZ=Asia/Singapore \ **#the Time Zone**
          -e SERVERPORT=51820 \ **#here is the listener port**
          -e PEERS=1 \ **#device number if you have many device you can follow you want to add if 1 device, then 1 , two device then 2, of course, it should created two config file in your server, you need copy out the server and scan, if two ,should have peer1 and peer2 in the server**
          -e PEERDNS=auto \
          -e INTERNAL_SUBNET=10.13.13.0 \
          -e ALLOWEDIPS=0.0.0.0/0 \
          -e LOG_CONFS=true \
          -p 51820:51820/udp \ **#here is in out port**
          -v /wire/appdata/config:/config \
          -v /lib/modules:/lib/modules \
          --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
          --restart unless-stopped \
          linuxserver/wireguard
Enter fullscreen mode Exit fullscreen mode

After you can close the ssh port if you no need

go to EC2 page and go to the security page
go to EC2 page and go to the security page

edit inbound
edit inbound

delete 22 port rule(if you down the QR picture use ssh client, please remember open it
delete 22 port rule(if you down the QR picture use ssh client, please remember open it)

Destroy your resource

search and select cloudformation

choose your stuck you want delete

confirm

All resource will delete, should be hold on your key pair(wire), don’t worry, AWS will not charge the fee of you

Next Story: Cloudformation Automation

Source: https://hub.docker.com/r/linuxserver/wireguard

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

Create a simple OTP system with AWS Serverless cover image

Create a simple OTP system with AWS Serverless

Implement a One Time Password (OTP) system with AWS Serverless services including Lambda, API Gateway, DynamoDB, Simple Email Service (SES), and Amplify Web Hosting using VueJS for the frontend.

Read full post