<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yaroslav Muravskyi</title>
    <description>The latest articles on DEV Community by Yaroslav Muravskyi (@myarik).</description>
    <link>https://dev.to/myarik</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F649802%2F7d31faea-0a38-4260-900b-08e742dd439b.png</url>
      <title>DEV Community: Yaroslav Muravskyi</title>
      <link>https://dev.to/myarik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/myarik"/>
    <language>en</language>
    <item>
      <title>Establishing a Secure Remote Development Environment with AWS EC2 and Terraform</title>
      <dc:creator>Yaroslav Muravskyi</dc:creator>
      <pubDate>Fri, 17 Nov 2023 13:52:08 +0000</pubDate>
      <link>https://dev.to/myarik/establishing-a-secure-remote-development-environment-with-aws-ec2-and-terraform-3dja</link>
      <guid>https://dev.to/myarik/establishing-a-secure-remote-development-environment-with-aws-ec2-and-terraform-3dja</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Remote development environments (RDEs)&lt;/strong&gt; allow software engineers to develop and deploy software remotely rather than on their local machine. RDEs are popular among software engineers for several reasons, including company security policies, requirements for specific resources, access to internal resources, and the ability to develop from different devices.&lt;/p&gt;

&lt;p&gt;This article provides a complete guide on setting up an RDE using an Amazon EC2 instance. We will cover everything from choosing the right instance type to troubleshooting common problems. By the end of this article, you will have a fully configured RDE that you can use to develop and deploy software from anywhere in the world.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up AWS EC2 Instance
&lt;/h3&gt;

&lt;p&gt;We will use Terraform to create an Amazon EC2 instance with EBS volume.  &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt; is an &lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_code"&gt;infrastructure as code&lt;/a&gt; (IaC) tool used for building, changing, and versioning infrastructure through code. This can also be accomplished using the AWS Console or AWS SDK.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup Network Infrastructure
&lt;/h4&gt;

&lt;p&gt;Before provisioning an Amazon EC2 instance, we must establish the necessary network infrastructure. This process involves creating a VPC, subnet, and route table and configuring an internet gateway. If you already have it, you can skip this step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="nx"&gt;VPC&lt;/span&gt;  
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vpc-dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;            &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10.10.0.0/21&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  
  &lt;span class="nx"&gt;enable_dns_hostnames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  
  &lt;span class="nx"&gt;tags&lt;/span&gt;                 &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tomap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev-vpc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
  &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;common_tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="nx"&gt;Public&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;  
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-subnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;              &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;10.10.1.0/24&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-west-2a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="nx"&gt;map_public_ip_on_launch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tomap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev-public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;common_tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;tables&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route_table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-route-table-dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  
  &lt;span class="nx"&gt;tags&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tomap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-route-table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
  &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;common_tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="nx"&gt;Associate&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;newly&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="nx"&gt;tables&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route_table_association&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-route-association&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;public&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;public&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="nx"&gt;Internet&lt;/span&gt; &lt;span class="nx"&gt;Gateway&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;  
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;igw-dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  
  &lt;span class="nx"&gt;tags&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tomap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;publick-igw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
  &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;common_tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt; &lt;span class="nx"&gt;traffic&lt;/span&gt; &lt;span class="nx"&gt;through&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;Internet&lt;/span&gt; &lt;span class="nx"&gt;Gateway&lt;/span&gt;  
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-internet-igw-route-dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;public&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  
  &lt;span class="nx"&gt;gateway_id&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;igw&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  
  &lt;span class="nx"&gt;destination_cidr_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Create Security Group
&lt;/h4&gt;

&lt;p&gt;We'll now create an AWS Security Group to ensure secure network access to an AWS EC2 instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="err"&gt;###&lt;/span&gt; &lt;span class="nx"&gt;Dev&lt;/span&gt; &lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="nx"&gt;Security&lt;/span&gt; &lt;span class="nx"&gt;group&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;traffic&lt;/span&gt; &lt;span class="nx"&gt;Local&lt;/span&gt; &lt;span class="nx"&gt;ssh&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;EC2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_security_group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev_environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dev Environment Security Group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Allows inbound access from the SSH only&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;  

  &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;For&lt;/span&gt; &lt;span class="nx"&gt;connecting&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;EC2&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt; &lt;span class="nx"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;need&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;IP&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;  
  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;  
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;  
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;192.168.0.1/32&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
    &lt;span class="p"&gt;]&lt;/span&gt;  
  &lt;span class="p"&gt;}&lt;/span&gt;  

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;  
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;  
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.0.0.0/0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
    &lt;span class="p"&gt;]&lt;/span&gt;  
  &lt;span class="p"&gt;}&lt;/span&gt;  
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tomap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dev Environment Security Group&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;common_tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This security group restricts SSH connections to only allow access from IP 192.168.0.1. To enable access from your public IP, replace 192.168.0.1 with your public IP address. If you want to allow SSH connections from any IP, replace 192.168.0.1 with 0.0.0.0.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create EC2 Instance
&lt;/h4&gt;

&lt;p&gt;With the network infrastructure in place, we're ready to create an AWS EC2 instance for our remote development environment.&lt;/p&gt;

&lt;p&gt;Ubuntu 22.04 LTS is used in this article because it is a popular and well-supported operating system for remote development environments. However, you can use any operating system that meets your needs.&lt;/p&gt;

&lt;p&gt;Suppose you use IntelliJ IDEA for remote development. To achieve optimal performance and low latency in your remote development environment (RDE), I recommend running an Amazon EC2 instance of type t3.large or r5.large. However, if you are not planning to use IntelliJ IDEA, you can choose a type that suits your needs. Additionally, we will be using a persistent EBS volume for data storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_key_pair&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ssh_key_dev_environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;key_name&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ssh_key_dev_environment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
  &lt;span class="nx"&gt;public_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ssh-rsa AAAAB3Nza&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;  
&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_ami&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ubuntu_22_04&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;most_recent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  

  &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
  &lt;span class="p"&gt;}&lt;/span&gt;  

  &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;architecture&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x86_64&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
  &lt;span class="p"&gt;}&lt;/span&gt;  
  &lt;span class="nx"&gt;owners&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;099720109477&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Canonical&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
  &lt;span class="nx"&gt;development_environment_user_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EOT&lt;/span&gt;&lt;span class="cp"&gt;  
#!/bin/bash  
&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;on_cloud_init&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sh&lt;/span&gt;  
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;----------------------------------------------------------------------------&lt;/span&gt;  
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;during&lt;/span&gt; &lt;span class="nx"&gt;EC2&lt;/span&gt; &lt;span class="nx"&gt;launch&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt;  
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;EC2&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;booted&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;  
&lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;Since&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;scripts&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;executed&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="nx"&gt;there&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s not need for sudo  
# ----------------------------------------------------------------------------  
set -eu  

installPackages() {  
  echo &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;***&lt;/span&gt; &lt;span class="nx"&gt;Installing&lt;/span&gt; &lt;span class="nx"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;***&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;  
  sudo apt-get update  
  sudo apt-get install awscli net-tools mc -y  
}  

installPackages  

export AWS_REGION=eu-central-1  
export PROJECT_DATA_VOLUME_MARKER=/data/.data_volume  

mountDataVolume() {  

  DATA_BLOCK_DEVICE=/dev/xvdf  
  echo &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;***&lt;/span&gt; &lt;span class="nx"&gt;Mounting&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt; &lt;span class="o"&gt;***&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;  

  echo "Wait for data volume to be attached"  
  while ! lsblk $DATA_BLOCK_DEVICE ; do  
    echo "/dev/xvdf is not attached yet. Waiting 5 seconds"  
    sleep 5  
  done  


  echo "Check if filesystem ext is on data volume"  
  if [ "$(lsblk -f $DATA_BLOCK_DEVICE -o FSTYPE -n)" == "ext4" ]  
  then  
    echo "filesystem ext4 is already on data volume"  
  else  
    echo "creating filesystem ext4 on data volume"  
    sudo mkfs -t ext4 $DATA_BLOCK_DEVICE  
  fi  

  echo "mount data volume at /data"  
  sudo mkdir -p /data  
  echo "UUID=$(blkid -s UUID -o value $DATA_BLOCK_DEVICE)  /data  ext4  defaults,nofail  0  2" | sudo tee /etc/fstab -a  
  mount -a  
  sudo mount | grep &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;  
}  

echo "Check if data volume is already mounted"  
if [ -e "$PROJECT_DATA_VOLUME_MARKER" ]  
then  
  echo &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;***&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="nx"&gt;volume&lt;/span&gt; &lt;span class="nx"&gt;already&lt;/span&gt; &lt;span class="nx"&gt;mounted&lt;/span&gt; &lt;span class="o"&gt;***&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;  
else  
  mountDataVolume  
  echo "Marking data volumes as mounted"  
  echo "DO NOT DELETE OR RENAME THIS FILE&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s1"&gt;!" &amp;gt; $PROJECT_DATA_VOLUME_MARKER  
fi  

EOT  
}  

resource "aws_instance" "development_environment" {  
  ami           = data.aws_ami.ubuntu_22_04.id  
  instance_type = "t2.micro"  


  subnet_id = aws_subnet.public-subnet.id  

  vpc_security_group_ids = [  
    aws_security_group.dev_environment.id,  
  ]  


  root_block_device {  
    volume_size = 10  
    volume_type = "gp3"  
  }  

  user_data            = local.development_environment_user_data  

  key_name   = aws_key_pair.ssh_key_dev_environment.key_name  
  monitoring = false  

  tags = merge(tomap({  
    Name = "Development Environment"  
  }), local.common_tags)  
}  


# Create and attache EBS  

resource aws_ebs_volume application_data {  
  availability_zone = "eu-west-2a"  
  encrypted         = true  
  size              = 100  
  type              = "gp3"  
  tags              = merge({  
    Name    = "vol-remote-dev-data"  
  }, local.common_tags)  
}  

resource aws_volume_attachment env_data {  
  device_name = "/dev/sdf"  
  instance_id = aws_instance.development_environment.id  
  volume_id   = aws_ebs_volume.application_data.id  
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please replace the provided SSH public key with your own. You can apply the desired changes and complete the EC2 instance provisioning process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;terraform plan
&lt;span class="nv"&gt;$ &lt;/span&gt;terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! You have successfully provisioned an EC2 instance suitable for remote development. To connect to the VM, utilise its public IP address.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to a Remote Environment using an IDE:
&lt;/h3&gt;

&lt;p&gt;IntelliJ IDEA and Visual Studio Code are popular Integrated Development Environments (IDEs) supporting remote development. In this article, we will demonstrate using IntelliJ IDEA. Nevertheless, setting up Visual Studio Code is straightforward and should pose no issues.&lt;/p&gt;

&lt;p&gt;IntelliJ IDEA supports two workflows for remote development: server-to-client and client-to-server.&lt;/p&gt;

&lt;p&gt;The client-to-server workflow is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Choose the "Remote Development" option from the IntelliJ IDEA menu.&lt;/em&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S5h1vcnM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vs6axi33honp1u3shqlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S5h1vcnM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vs6axi33honp1u3shqlx.png" alt="Image description" width="290" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Select a connection via SSH and specify the SSH connection details to establish a connection with your remote instance.&lt;/em&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KDuQf6sO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3bm47jg391789hy7glj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KDuQf6sO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3bm47jg391789hy7glj6.png" alt="Image description" width="800" height="629"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;IntelliJ IDEA will automatically install the necessary IDE components on your remote instance, and you will be ready to start developing. Configuring the server-to-client can be found in the &lt;a href="https://www.jetbrains.com/help/idea/remote-development-overview.html#workflow"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tips
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Easy SSH Access
&lt;/h4&gt;

&lt;p&gt;EC2 instances are assigned dynamic IP addresses by default, meaning the IP address changes each time the instance is stopped and restarted. Consistent instance access can be challenging, especially when working remotely for development purposes. You can address this issue using Elastic IP or a VPN tunnel.&lt;/p&gt;

&lt;p&gt;Elastic IP provides a static IP address that can be associated with your EC2 instance. It ensures the instance has the same IP address, even if it's stopped and restarted. At the same time, Elastic IP incurs a monthly fee.&lt;/p&gt;

&lt;p&gt;If you prefer to avoid the additional cost of Elastic IP, you can create a VPN tunnel between your local machine and the EC2 instance. This tunnel establishes a secure private network connection, allowing you to access the instance as if it were on your local network. For this scenario, I recommend using Tailscale, a user-friendly and free option for up to 100 devices.&lt;/p&gt;
&lt;h4&gt;
  
  
  Port Forwarding
&lt;/h4&gt;

&lt;p&gt;With IntelliJ IDEA, you can effortlessly establish port forwarding from your EC2 instance to your local machine. Alternatively, if you prefer to configure a port forwarding tunnel manually, utilise the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh -N -L &amp;lt;LOCAL PORT&amp;gt;:localhost:&amp;lt;REMOTE PORT&amp;gt; ubuntu@&amp;lt;IP ADDRESS&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This guide covered the process of establishing a remote development environment using AWS EC2 instances and Terraform. The remote development environment offers the flexibility to work from anywhere, eliminates hardware limitations, and enables collaboration among developers. The possibilities are endless, and the power of remote development lies in its adaptability and flexibility.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>development</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
