<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Linux &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/category/linux/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Mon, 06 Dec 2021 14:19:04 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>AWS: Web Servers in HA config behind Application Load Balancer and Web Application Firewall (WAF)</title>
		<link>https://blog.andreev.it/2021/12/aws-web-servers-in-ha-config-behind-application-load-balancer-and-web-application-firewall-waf/</link>
					<comments>https://blog.andreev.it/2021/12/aws-web-servers-in-ha-config-behind-application-load-balancer-and-web-application-firewall-waf/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Mon, 06 Dec 2021 14:19:04 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[ALB]]></category>
		<category><![CDATA[WAF]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=8991</guid>

					<description><![CDATA[As the title says, I&#8217;ll create two web servers in a private subnet, put&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>As the title says, I&#8217;ll create two web servers in a private subnet, put an Application Load Balancer in front and protect the content with Web Application Firewall (WAF). In addition, I&#8217;ll create a bastion host so I can access the web servers using SSH. Web Servers are not reachable from the Internet. </p>
<h1>Elastic IP</h1>
<p>First thing to do is to create an Elastic IP for the NAT gateway. NAT gateway is needed if you want to give the Web Servers Internet access so they can be patched. Go to <strong>Elastic IPs</strong> under <strong>Network &#038; Security</strong> in EC2 menu and click on <strong>Allocate Elastic IP address</strong> in the top right corner. Accept the defaults and click <strong>Allocate</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-01.png"><img fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-01.png" alt="" width="826" height="763" class="aligncenter size-full wp-image-8994" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-01.png 826w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-01-300x277.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-01-768x709.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-01-585x540.png 585w" sizes="(max-width: 826px) 100vw, 826px" /></a></p>
<h1>VPC</h1>
<p>We&#8217;ll create a VPC with two public and two private subnets. Minimum two public subnets are needed for the Application Load Balancer. You can&#8217;t create an ALB with one public subnet.<br />
Click on Launch VPC Wizard in the VPC menu and select <strong>VPC with Public and Private Subnets</strong>. I&#8217;ll use this CIDR (192.168.100.0/22) which gives me 1024 hosts enough for 4 Class C /24 subnets, you can use whatever CIDR you want. As you can see I&#8217;ll use 192.168.100.0/24 for the first public subnet and 192.168.102.0/24 for the first private subnet. I&#8217;ll create the other public and private subnet later. You&#8217;ll have to associate the Elastic IP that you created in the previous step to the NAT gateway. Click <strong>Create VPC</strong> in the bottom right corner.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-02.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-02.png" alt="" width="711" height="657" class="aligncenter size-full wp-image-8995" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-02.png 711w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-02-300x277.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-02-585x541.png 585w" sizes="(max-width: 711px) 100vw, 711px" /></a><br />
Go to <strong>Subnets </strong>menu click on the public subnet and look at the Availability Zone.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-04.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-04.png" alt="" width="1091" height="552" class="aligncenter size-full wp-image-8997" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-04.png 1091w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-04-300x152.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-04-1024x518.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-04-768x389.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-04-585x296.png 585w" sizes="(max-width: 1091px) 100vw, 1091px" /></a><br />
When you create the next subnet, you have to put it on another zone.<br />
Click on the <strong>Route table</strong> tab. Remember/write-down the route table id (rtb-0e3cbsomething). It will be different for you.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-03.png" alt="" width="613" height="454" class="aligncenter size-full wp-image-8996" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-03.png 613w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-03-300x222.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-03-585x433.png 585w" sizes="(max-width: 613px) 100vw, 613px" /></a><br />
Then click on <strong>Create subnet</strong> in the upper right corner. Choose your VPC, name the subnet (in my case subPublic2), assign an <strong>Availability Zone</strong> (e.g. us-east-1a) and add the CIDR 192.168.101.0/24. Make sure that your 2nd public Availability Zone is different than the 1st Availability Zone. Click <strong>Create subnet</strong>.<br />
If you click on the new subnet now and then click on the Route table tab, you&#8217;ll see that AWS created a route table for you. But as you can notice below, the destination 0.0.0.0/0 goes through the NAT gateway.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-05.png" alt="" width="1088" height="618" class="aligncenter size-full wp-image-8998" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-05.png 1088w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-05-300x170.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-05-1024x582.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-05-768x436.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-05-585x332.png 585w" sizes="(max-width: 1088px) 100vw, 1088px" /></a><br />
We don&#8217;t want that. We want the public subnet to use the Internet gateway, not the NAT gateway. So click on the E<strong>dit route table association</strong> on the right. From the drop down choose the other route table, that&#8217;s the Internet gateway, that&#8217;s the one that you have wrote down earlier. When you change to the other route table, you&#8217;ll see that the destination for 0.0.0.0/0 changes to igw which is the Internet gateway. Click <strong>Save</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-06.png" alt="" width="863" height="572" class="aligncenter size-full wp-image-8999" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-06.png 863w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-06-300x199.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-06-768x509.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-06-780x516.png 780w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-06-585x388.png 585w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-06-263x175.png 263w" sizes="(max-width: 863px) 100vw, 863px" /></a><br />
Now, do the same for the other private subnet. Click on the private subnet and look at the Availability Zone. In my case it&#8217;s us-east-1b. This means, I have to create my 2nd private subnet in another zone.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-07.png" alt="" width="1005" height="462" class="aligncenter size-full wp-image-9000" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-07.png 1005w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-07-300x138.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-07-768x353.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-07-585x269.png 585w" sizes="(max-width: 1005px) 100vw, 1005px" /></a><br />
So, I am creating the 2nd private subnet within my VPC and I named my subnet subPvt2 in us-east-1a and 192.168.103.0/24 CIDR.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-08.png" alt="" width="657" height="634" class="aligncenter size-full wp-image-9001" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-08.png 657w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-08-300x289.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-08-585x565.png 585w" sizes="(max-width: 657px) 100vw, 657px" /></a><br />
Check the route table for this new private subnet. The route table for 0.0.0.0/0 should be the NAT gateway which is correct, but just in case&#8230;<br />
So these are my subnets now.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-09.png" alt="" width="1005" height="133" class="aligncenter size-full wp-image-9002" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-09.png 1005w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-09-300x40.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-09-768x102.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-09-585x77.png 585w" sizes="(max-width: 1005px) 100vw, 1005px" /></a></p>
<h1>Bastion host</h1>
<p>You use a bastion host as a jump server to get to the web servers. If you have any other means to get to them such as VPN or Systems Manager, then go for it. This is just an example of how to get to the web servers.<br />
I&#8217;ll use the AWS Linux for this. It really doesn&#8217;t matter as long you have a SSH client installed on the bastion host. Launch a simple t2.micro instance in any public subnet. Make sure the bastion host has a public IP. Also make sure that this bastion host is accessible from a single IP or some dedicated subnet. You don&#8217;t want this bastion host to be exposed to the world. In my case, the security group for the bastion host is restricted to my home IP only on port 22 for SSH. </p>
<h1>Web Servers</h1>
<p>I&#8217;ll use two AWS Linux instances deployed in the private subnets. Do not assign a public IP for these. That&#8217;s what the bastion host is for. Create a security group that allows traffic for SSH from the security group that you created for the bastion host. In my case it looks like this. Start typing <strong>sg </strong>in the circled field and choose the security group that you create earlier. If you named it properly, you&#8217;ll see it. If not, go get the security group ID for the bastion host.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-10.png" alt="" width="813" height="406" class="aligncenter size-full wp-image-9003" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-10.png 813w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-10-300x150.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-10-768x384.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-10-585x292.png 585w" sizes="(max-width: 813px) 100vw, 813px" /></a><br />
Launch two instances in two different private subnets. </p>
<h2>Test connection</h2>
<p>Log to the bastion host using the key you created. Now, we&#8217;ll connect to the web servers from the bastion host. If you used the same key for bastion host and web servers, copy and paste the PEM certificate in a file called key.pem or whatever. If you used different keys, it doesn&#8217;t matter, just make sure you have the keys as a file on the bastion host. I used the same key, which is not the best practice, but for the sake of simplicity, I have a file called key.pem on the bastion host. Log to each web server using  ssh ec2-user@192.168.102.176 -i key.pem where ec2-user is the user for the AWS Linux (it differs for different Linux distros), 192.168.102.176 is the IP of the first web server and the parameter -i tells which key file certificate to use. Make sure you do <strong>chmod 600 key.pem</strong> so you can log in. You should be able to log in to both web servers. </p>
<h1>Install Apache web server</h1>
<p>Log to each web server and execute these commands to install Apache web server, start it and enable to start on boot. </p>
<pre class="brush: bash; title: ; notranslate">
sudo yum -y install httpd
sudo systemctl start httpd
sudo systemctl enable httpd
</pre>
<p>Switch to root.</p>
<pre class="brush: bash; title: ; notranslate">
sudo su
</pre>
<p>Then on each server do this. Do Server 2 on the second server. This is just an example. You need the same code on both web servers. The difference is because we&#8217;ll test the ALB later and see how the page changes. </p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;Server 1&quot; &gt; /var/www/html/index.html
</pre>
<p>For the 2nd server. </p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;Server 2&quot; &gt; /var/www/html/index.html
</pre>
<h1>Application Load Balancer</h1>
<p>Now, we are moving to the ALB. Before we create the ALB, let&#8217;s create a security group that will allow port 80 from everywhere. Looks like this. Create the security group from the EC2 menu. This is a security group that we&#8217;ll assign to the load balancer.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-11.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-11.png" alt="" width="1198" height="668" class="aligncenter size-full wp-image-9005" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-11.png 1198w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-11-300x167.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-11-1024x571.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-11-768x428.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-11-1170x652.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-11-585x326.png 585w" sizes="(max-width: 1198px) 100vw, 1198px" /></a><br />
From the EC2 menu on the left side, go to <strong>Load Balancing</strong> and click on <strong>Load Balancers</strong>. Click on <strong>Create Load Balancer</strong>. Choose <strong>Application Load Balancer</strong>. Make sure you choose the public subnets and for the security group use the one that we created earlier for the load balancer.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-12.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-12.png" alt="" width="871" height="764" class="aligncenter size-full wp-image-9006" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-12.png 871w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-12-300x263.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-12-768x674.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-12-585x513.png 585w" sizes="(max-width: 871px) 100vw, 871px" /></a><br />
If you scroll down, you&#8217;ll see that you need to create a target group for the ALB. The target is our web servers. Click on <strong>Create target group</strong>. It will open up a new browser window. Choose <strong>Instances</strong>, name the target group, leave HTTP1 for protocol and for the <strong>Health checks</strong> type /index.html. Remember, we created these files earlier.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-13.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-13.png" alt="" width="862" height="712" class="aligncenter size-full wp-image-9007" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-13.png 862w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-13-300x248.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-13-768x634.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-13-585x483.png 585w" sizes="(max-width: 862px) 100vw, 862px" /></a><br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-14.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-14.png" alt="" width="872" height="767" class="aligncenter size-full wp-image-9008" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-14.png 872w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-14-300x264.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-14-768x676.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-14-585x515.png 585w" sizes="(max-width: 872px) 100vw, 872px" /></a><br />
Click <strong>Next</strong>, select the web servers and click on <strong>Include as pending below</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-15.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-15.png" alt="" width="1134" height="570" class="aligncenter size-full wp-image-9009" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-15.png 1134w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-15-300x151.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-15-1024x515.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-15-768x386.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-15-585x294.png 585w" sizes="(max-width: 1134px) 100vw, 1134px" /></a><br />
Finally, click on <strong>Create target group</strong>.<br />
Go back to the original tab when you created the load balancer, click on the refresh button and choose the target group you just created.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-16.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-16.png" alt="" width="1061" height="288" class="aligncenter size-full wp-image-9010" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-16.png 1061w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-16-300x81.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-16-1024x278.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-16-768x208.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-16-585x159.png 585w" sizes="(max-width: 1061px) 100vw, 1061px" /></a><br />
Scroll down and click on <strong>Create load balancer</strong>.<br />
Wait for a couple minutes until you see that the state changes to <strong>Active</strong>. Click Refresh on the right side.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-17.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-17.png" alt="" width="670" height="199" class="aligncenter size-full wp-image-9011" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-17.png 670w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-17-300x89.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-17-585x174.png 585w" sizes="(max-width: 670px) 100vw, 670px" /></a><br />
While you are waiting, if you click on the <strong>Description </strong>tab for the load balancer and  scroll a little bit down, you&#8217;ll see the security group that we create for the load balancer.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-18.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-18.png" alt="" width="727" height="537" class="aligncenter size-full wp-image-9012" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-18.png 727w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-18-300x222.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-18-585x432.png 585w" sizes="(max-width: 727px) 100vw, 727px" /></a><br />
We need to add this security group to the web servers. Right now, the web servers are configured to accept traffic from the bastion host only, but we need for the web servers to accept HTTP traffic as well. Now, the security group for the load balancer allows HTTP from everywhere, but that doesn&#8217;t matter. When we add this security group to the web servers they&#8217;ll also allow HTTP request from everywhere. But the web servers have no public access so it really doesn&#8217;t matter. Does this mean that any other server in these public/private subnets will have access to HTTP to the web servers? Yes. If I create another server in the private/public subnet, it will have access to HTTP to the web servers.<br />
Let&#8217;s add the ALB security group to the instances. In my case it looks like this where the bottom security group is the security group for allowing HTTP from everywhere, the one that we assigned to the ALB.<br />
 <a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-19.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-19.png" alt="" width="1293" height="386" class="aligncenter size-full wp-image-9014" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-19.png 1293w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-19-300x90.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-19-1024x306.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-19-768x229.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-19-1170x349.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-19-585x175.png 585w" sizes="(max-width: 1293px) 100vw, 1293px" /></a><br />
Before you do anything, go to the <strong>Target Groups</strong> menu under <strong>Load Balancing</strong>. You should see both instances as <strong>healthy</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-20.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-20.png" alt="" width="1253" height="757" class="aligncenter size-full wp-image-9016" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-20.png 1253w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-20-300x181.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-20-1024x619.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-20-768x464.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-20-1170x707.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-20-585x353.png 585w" sizes="(max-width: 1253px) 100vw, 1253px" /></a><br />
If this looks good, go back to the load balancer and get the URL.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-21.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-21.png" alt="" width="992" height="332" class="aligncenter size-full wp-image-9017" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-21.png 992w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-21-300x100.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-21-768x257.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-21-585x196.png 585w" sizes="(max-width: 992px) 100vw, 992px" /></a><br />
Open up a new browser window and go to that URL. Click refresh in your browser several times. You&#8217;ll see how it changes from Server 1 to Server 2.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-22.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-22.png" alt="" width="735" height="192" class="aligncenter size-full wp-image-9018" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-22.png 735w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-22-300x78.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-22-585x153.png 585w" sizes="(max-width: 735px) 100vw, 735px" /></a><br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-23.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-23.png" alt="" width="702" height="199" class="aligncenter size-full wp-image-9019" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-23.png 702w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-23-300x85.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-23-585x166.png 585w" sizes="(max-width: 702px) 100vw, 702px" /></a><br />
If everything is OK, proceed further. </p>
<h1>Web Application Firewall</h1>
<p>The good news is that you can directly create your rules from the ALB. Click on the load balancer you created and click on the <strong>Integrated services</strong> tab. Click on C<strong>reate Web ACL</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-24.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-24.png" alt="" width="631" height="655" class="aligncenter size-full wp-image-9021" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-24.png 631w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-24-289x300.png 289w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-24-585x607.png 585w" sizes="(max-width: 631px) 100vw, 631px" /></a><br />
Name the ACL and click on Add AWS resources where we gonna add the ALB.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-25.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-25.png" alt="" width="867" height="660" class="aligncenter size-full wp-image-9022" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-25.png 867w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-25-300x228.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-25-768x585.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-25-585x445.png 585w" sizes="(max-width: 867px) 100vw, 867px" /></a><br />
Here we are. Click <strong>Next </strong>after.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-26.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-26.png" alt="" width="867" height="448" class="aligncenter size-full wp-image-9023" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-26.png 867w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-26-300x155.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-26-768x397.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-26-585x302.png 585w" sizes="(max-width: 867px) 100vw, 867px" /></a><br />
And now you are on your own. You have to add rules. There are some that are templated and there are some that you can buy from the AWS Marketplace.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P157-27.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P157-27.png" alt="" width="869" height="694" class="aligncenter size-full wp-image-9024" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P157-27.png 869w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-27-300x240.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-27-768x613.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P157-27-585x467.png 585w" sizes="(max-width: 869px) 100vw, 869px" /></a><br />
Once you add these rules, you can see what&#8217;s blocked and what&#8217;s not under <strong>Cloud Watch | All metrics | WAFV2</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2021/12/aws-web-servers-in-ha-config-behind-application-load-balancer-and-web-application-firewall-waf/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure: Run WordPress on managed MySQL and App Services</title>
		<link>https://blog.andreev.it/2021/12/azure-run-wordpress-on-managed-mysql-and-app-services/</link>
					<comments>https://blog.andreev.it/2021/12/azure-run-wordpress-on-managed-mysql-and-app-services/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Wed, 01 Dec 2021 20:47:57 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Azure App]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=8946</guid>

					<description><![CDATA[In this post I&#8217;ll explain how to run a WordPress site using Azure services&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post I&#8217;ll explain how to run a WordPress site using Azure services for managed MySQL and App Services for a PHP application.<br />
The basic offerings for MySQL and App Services create these resources in a public subnet, so in order to integrate them with your VNETs, you&#8217;ll have to use the more expensive options. In this post, we&#8217;ll use just that. We&#8217;ll create the MySQL database without any public access and integrate the App Services to connect to the SQL database internally.</p>
<h1>VNET/subnets</h1>
<p>First, we&#8217;ll create a VNET with three subnets. When you integrate an App Services in a VNET, the subnet where the App Services will reside must be empty. The same applies for Flex MySQL servers. You can have multiple Apps in the same dedicated subnet. So, you need a dedicated subnet for both App Service and MySQL Flex, but not for MySQL single server. Single MySQL server can share the subnet with other resources.<br />
For MySQL, there are two options. We can use a private endpoint or a VNET integration. We&#8217;ll go with a private endpoint first. We don&#8217;t need a dedicated subnet for this.<br />
In my case, I&#8217;ll create a VNET with <strong>192.168.100.0/22</strong> CIDR and three subnets, <strong>192.168.100.0/24</strong> for some Infra/MySQL stuff, <strong>192.168.101.0/24</strong> for the App Services and <strong>192.168.102.0/24</strong> for Flex MySQL. I&#8217;ll use a new resource group called <strong>rgWordPress</strong>. The VNET will be called <strong>vnetWordPress</strong> and the subnets, <strong>subInfra</strong>, <strong>subApp</strong> and <strong>subMySQL</strong> respectively.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-01.png" alt="" width="1582" height="1178" class="aligncenter size-full wp-image-8948" /></a></p>
<h2>VM</h2>
<p>I will also create a VM in the <strong>subInfra</strong> subnet. This VM is not needed at all, it will be used to test connectivity. In my case, I&#8217;ll spin a new Debian 1CPU, 1GB VM and I&#8217;ll install the MySQL client.</p>
<pre class="brush: bash; title: ; notranslate">sudo apt install default-mysql-client</pre>
<h1>Managed Single server MySQL</h1>
<p>When it comes to MySQL, there are two options: Flexible server and Single server. Look at this <a href="https://docs.microsoft.com/en-us/azure/mysql/select-right-deployment-type" rel="noopener" target="_blank">link</a> to determine what you want to use. In most of the cases, you&#8217;ll use a Flexible server. But there are some limitations in both use cases. For example, a Flexible server can&#8217;t use private endpoints. You are limited to VNET integration and Single server can&#8217;t be VNET integrated. On top of that, only General Purpose and Memory Optimized servers can have private endpoints. The basic single server can be public only. Flex VNET integrated servers require dedicated and empty subnets. There are other limitations as well, so take a look at the link above.<br />
In my case, I am using a General Purpose server.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-02.png" alt="" width="1514" height="1532" class="aligncenter size-full wp-image-8954" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-02.png 1514w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-02-296x300.png 296w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-02-1012x1024.png 1012w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-02-768x777.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-02-1170x1184.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-02-585x592.png 585w" sizes="(max-width: 1514px) 100vw, 1514px" /></a><br />
Once you create the server, it will be public. As you can see from the <strong>Overview</strong> for the server, there is a public DNS record.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-03.png" alt="" width="1010" height="356" class="aligncenter size-full wp-image-8956" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-03.png 1010w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-03-300x106.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-03-768x271.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-03-585x206.png 585w" sizes="(max-width: 1010px) 100vw, 1010px" /></a><br />
On the left side/blade, under <strong>Security</strong>, click on <strong>Private endpoint connections</strong> and create one.<br />
Name the private link and put it in the same resource group as the other resources.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-04.png" alt="" width="1568" height="802" class="aligncenter size-full wp-image-8957" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-04.png 1568w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-04-300x153.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-04-1024x524.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-04-768x393.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-04-1536x786.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-04-1170x598.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-04-585x299.png 585w" sizes="(max-width: 1568px) 100vw, 1568px" /></a><br />
For the resource type <strong>Microsoft.DBforMySQL/servers</strong> and you&#8217;ll be able to select the newly created MySQL server from the dropdown under <strong>Resource</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-05.png" alt="" width="1544" height="726" class="aligncenter size-full wp-image-8958" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-05.png 1544w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-05-300x141.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-05-1024x481.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-05-768x361.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-05-1536x722.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-05-1170x550.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-05-585x275.png 585w" sizes="(max-width: 1544px) 100vw, 1544px" /></a><br />
Finally, choose the virtual network and subnet where you want to put the private link. Do not use the subnet for App Services. In addition, make sure that the integration with the private DNS zone is set to <strong>Yes</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-06.png" alt="" width="2056" height="994" class="aligncenter size-full wp-image-8959" /></a><br />
If you log to the server that we just built and try to resolve the public DNS for the MySQL server, you&#8217;ll see that it resolves as a private IP. That&#8217;s because you have a private DNZ zone that takes precedence over the public DNS.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-07.png" alt="" width="1600" height="186" class="aligncenter size-full wp-image-8961" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-07.png 1600w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-07-300x35.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-07-1024x119.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-07-768x89.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-07-1536x179.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-07-1170x136.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-07-585x68.png 585w" sizes="(max-width: 1600px) 100vw, 1600px" /></a><br />
In case, you are still getting the public IP, go to the <strong>Private DNS zone</strong> and make sure that it&#8217;s linked to the actual VNET.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-08.png" alt="" width="1888" height="774" class="aligncenter size-full wp-image-8962" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-08.png 1888w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-08-300x123.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-08-1024x420.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-08-768x315.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-08-1536x630.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-08-1170x480.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-08-585x240.png 585w" sizes="(max-width: 1888px) 100vw, 1888px" /></a><br />
Now you can try to connect to the MySQL database. </p>
<pre class="brush: bash; title: ; notranslate">mysql -u klimenta@mysqlwordpress-single -h mysqlwordpress-single.mysql.database.azure.com -p</pre>
<p>Where <strong>-u</strong> specifies the username and the <strong>-h </strong>is the host. These parameters are under <strong>Overview</strong> on the right side. See the screenshot above.<br />
You might get the following error. ERROR 9002 (28000): SSL connection is required. Please specify SSL options and retry.<br />
In that case, download the SSL certificate and try again. </p>
<pre class="brush: bash; title: ; notranslate">
wget https://www.digicert.com/CACerts/BaltimoreCyberTrustRoot.crt.pem
mysql -u klimenta@mysqlwordpress-single -h mysqlwordpress-single.mysql.database.azure.com -p --ssl-ca=BaltimoreCyberTrustRoot.crt.pem
</pre>
<p>In case you are wondering, wait, why this cert? &#8211; The answer is <a href="https://docs.microsoft.com/en-us/azure/mysql/howto-configure-ssl" rel="noopener" target="_blank">here</a>.<br />
As you can see, I am able to connect now.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-09.png" alt="" width="1620" height="806" class="aligncenter size-full wp-image-8964" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-09.png 1620w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-09-300x149.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-09-1024x509.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-09-768x382.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-09-1536x764.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-09-1170x582.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-09-585x291.png 585w" sizes="(max-width: 1620px) 100vw, 1620px" /></a><br />
It is also recommended to disable the public access. Go to <strong>Connection security </strong>under <strong>Settings</strong> and select <strong>Yes</strong> for <strong>Deny public network access</strong>.</p>
<h1>App Services</h1>
<p>Go to App Services and create one. Make sure you use <strong>Premium</strong> offering so you can do a VNET integration. The initial parameters are self explaining. Use the defaults for the rest of the screens. You won&#8217;t be able to do much with PHP anyway.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-10.png" alt="" width="1564" height="1458" class="aligncenter size-full wp-image-8967" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-10.png 1564w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-10-300x280.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-10-1024x955.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-10-768x716.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-10-1536x1432.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-10-1170x1091.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-10-585x545.png 585w" sizes="(max-width: 1564px) 100vw, 1564px" /></a><br />
Once the app is provisioned, on the left side/blade, go to the <strong>Networking</strong> menu under <strong>Settings</strong>. You&#8217;ll see that the VNET integration is not configured. Click on the link.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-11.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-11.png" alt="" width="1992" height="1224" class="aligncenter size-full wp-image-8968" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-11.png 1992w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-11-300x184.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-11-1024x629.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-11-768x472.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-11-1536x944.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-11-1920x1180.png 1920w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-11-1170x719.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-11-585x359.png 585w" sizes="(max-width: 1992px) 100vw, 1992px" /></a><br />
Pretty much, you have to select the VNET and an empty subnet. As you can see, I can only select subApp from the dropdown.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-12.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-12.png" alt="" width="1152" height="1054" class="aligncenter size-full wp-image-8970" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-12.png 1152w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-12-300x274.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-12-1024x937.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-12-768x703.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-12-585x535.png 585w" sizes="(max-width: 1152px) 100vw, 1152px" /></a><br />
Close the blade and from the App menu, click on <strong>SSH</strong> under <strong>Development Tools</strong> on the left. This will open a new tab in your browser with a SSH session.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-13.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-13.png" alt="" width="1000" height="524" class="aligncenter size-full wp-image-8971" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-13.png 1000w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-13-300x157.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-13-768x402.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-13-585x307.png 585w" sizes="(max-width: 1000px) 100vw, 1000px" /></a><br />
We have to create the WordPress database now. You can do that from the test server that we used initially or from the actual SSH session. Let&#8217;s use the SSH session. It already comes with mysql client preinstalled.</p>
<pre class="brush: bash; title: ; notranslate">
wget https://www.digicert.com/CACerts/BaltimoreCyberTrustRoot.crt.pem
mysql -u klimenta@mysqlwordpress-single -h mysqlwordpress-single.mysql.database.azure.com -p --ssl-ca=BaltimoreCyberTrustRoot.crt.pem
</pre>
<p>Once in MySQL client, execute these SQL statements.</p>
<pre class="brush: sql; title: ; notranslate">
CREATE DATABASE dbwordpress;
GRANT ALL PRIVILEGES ON dbwordpress.* TO &quot;wordpressuser&quot;@&quot;%&quot; IDENTIFIED BY &quot;SuperSecret&quot;;
FLUSH PRIVILEGES;
EXIT
</pre>
<p>Replace the values with yours for the database name, MySQL host name, username and password.<br />
Now, you can download WordPress and extract it.</p>
<pre class="brush: bash; title: ; notranslate">
cd /home/site/wwwroot
wget -c http://WordPress.org/latest.tar.gz
tar -xzvf latest.tar.gz
mv WordPress/* /home/site/wwwroot/
rm -rf WordPress
rm -rf latest.tar.gz
</pre>
<p>Once completed, go to the URL for the app. It should be under the <strong>Overview</strong>. You have to provide the database name (dbwordpress), username (wordpressuser@mysqlwordpress-single), password (SuperSecret) and the database host (mysqlwordpress-single.mysql.database.azure.com).<br />
Most likely you&#8217;ll see an error. The easiest way is to disable the SSL requirement for the MySQL database from Connection security under Settings for the database.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-14.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-14.png" alt="" width="2218" height="382" class="aligncenter size-full wp-image-8975" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-14.png 2218w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-300x52.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-1024x176.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-768x132.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-1536x265.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-2048x353.png 2048w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-1920x331.png 1920w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-1170x202.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-14-585x101.png 585w" sizes="(max-width: 2218px) 100vw, 2218px" /></a><br />
If this doesn&#8217;t work for you, you&#8217;ll have to manually specify the parameters in wp-config.php. You can search this on your own.<br />
Once you are done, specify the values in WordPress install screen and you are all set.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-15.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-15.png" alt="" width="1544" height="996" class="aligncenter size-full wp-image-8976" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-15.png 1544w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-15-300x194.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-15-1024x661.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-15-768x495.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-15-1536x991.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-15-1170x755.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-15-585x377.png 585w" sizes="(max-width: 1544px) 100vw, 1544px" /></a></p>
<h1>Flex MySQL server</h1>
<p>Let&#8217;s see how Flex MySQL server works. Go to Azure MySQL but this time provision a flex server.<br />
This is how my setup looks like.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-16.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-16.png" alt="" width="1594" height="1216" class="aligncenter size-full wp-image-8978" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-16.png 1594w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-16-300x229.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-16-1024x781.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-16-768x586.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-16-1536x1172.png 1536w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-16-1170x893.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-16-585x446.png 585w" sizes="(max-width: 1594px) 100vw, 1594px" /></a><br />
&#8230;and this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/11/P156-17.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/11/P156-17.png" alt="" width="1508" height="818" class="aligncenter size-full wp-image-8979" srcset="https://blog.andreev.it/wp-content/uploads/2021/11/P156-17.png 1508w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-17-300x163.png 300w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-17-1024x555.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-17-768x417.png 768w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-17-1170x635.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/11/P156-17-585x317.png 585w" sizes="(max-width: 1508px) 100vw, 1508px" /></a><br />
A flexible MySQL server can&#8217;t have a private endpoint, but it can be VNET integrated, same as the Azure App Services. And if you choose for the flex server to be VNET integrated, you&#8217;ll need a dedicated and empty subnet, same as Azure App Services.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/12/P156-18.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/12/P156-18.png" alt="" width="1524" height="1170" class="aligncenter size-full wp-image-8988" srcset="https://blog.andreev.it/wp-content/uploads/2021/12/P156-18.png 1524w, https://blog.andreev.it/wp-content/uploads/2021/12/P156-18-300x230.png 300w, https://blog.andreev.it/wp-content/uploads/2021/12/P156-18-1024x786.png 1024w, https://blog.andreev.it/wp-content/uploads/2021/12/P156-18-768x590.png 768w, https://blog.andreev.it/wp-content/uploads/2021/12/P156-18-1170x898.png 1170w, https://blog.andreev.it/wp-content/uploads/2021/12/P156-18-585x449.png 585w" sizes="(max-width: 1524px) 100vw, 1524px" /></a><br />
Once you provision the flex MySQL server, you&#8217;ll be able to manage it the same as a single server with a private endpoint. You can also see the entry in the private DNS zone for a flex server, same as with the single server. A flex server also allows you to have a hot standby HA pair but you can&#8217;t use this hot standby as a replica. A HA will double the price and you won&#8217;t be able to create replicas. The HA is in a different zone but in a same region and it allows forced and automatic failovers. And if you want to use a read only replica (up to 10), you have to take care of the SQL proxying using ProxySQL, HAProxy or Nginx.<br />
So, if you want some sort of HA for the MySQL, go with the flexible MySQL. You&#8217;ll have automatic failover within the region. But if you want to recover from a regional failure, use a single MySQL server with a read replica in another region (flexible MySQL can&#8217;t have replica in another region) and when you need to failover, just promote the replica in a standalone server (you&#8217;ll also need an Azure App Service in the DR region). The bad thing is that once you promote a replica in a standalone server and the original regions comes back up, you can&#8217;t revert the DR MySQL server in a replica again. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2021/12/azure-run-wordpress-on-managed-mysql-and-app-services/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Ansible: Quick Start Guide for FreeBSD, CentOS and Ubuntu</title>
		<link>https://blog.andreev.it/2021/02/ansible-quick-start-guide-for-freebsd-centos-and-ubuntu/</link>
					<comments>https://blog.andreev.it/2021/02/ansible-quick-start-guide-for-freebsd-centos-and-ubuntu/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Mon, 08 Feb 2021 17:04:37 +0000</pubDate>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[Ansible]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[freebsd]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=8784</guid>

					<description><![CDATA[In this post/howto, I&#8217;ll explain how to install Ansible as control and managed node&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post/howto, I&#8217;ll explain how to install Ansible as control and managed node on FreeBSD 12, CentOS 8 and Ubuntu 18. Then, I&#8217;ll explain how to create SSH keys so the nodes can communicate and some basic tasks. Then, I&#8217;ll show you how to create a playbook to install the latest updates and also install an Apache server with the default settings. Finally, I&#8217;ll show an example of how to use variables. </p>
<h1>Control and managed nodes</h1>
<p>A control node is where you execute all of your Ansible commands and eventually keep your playbooks, configs, inventory etc. It&#8217;s pretty much your workstation. A managed node is where the actual playbooks are executed. <a href="https://docs.ansible.com/ansible/latest/network/getting_started/basic_concepts.html" rel="noopener" target="_blank">These </a>are the main concepts and the terminology.<br />
In my case, I have 4 VMs/instances. The main one which is the control node and 3 managed nodes.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/01/P153-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/01/P153-01.png" alt="" width="309" height="113" class="aligncenter size-full wp-image-8786" srcset="https://blog.andreev.it/wp-content/uploads/2021/01/P153-01.png 309w, https://blog.andreev.it/wp-content/uploads/2021/01/P153-01-300x110.png 300w" sizes="(max-width: 309px) 100vw, 309px" /></a></p>
<h2>CentOS 8</h2>
<p>If you want to install Ansible on the control node, you have to install Python 3.x first. </p>
<pre class="brush: bash; title: ; notranslate">
sudo dnf install python3
</pre>
<p>This will also install <strong>pip</strong>. Type <strong>python3 </strong>to test, <strong>CTRL-D</strong> to exit and then install ansible.</p>
<pre class="brush: bash; title: ; notranslate">
sudo pip3 install ansible
</pre>
<p>Type <strong>ansible </strong>to test.</p>
<h2>Ubuntu</h2>
<p>Ubuntu comes with python installed, but not with pip. Install pip with:</p>
<pre class="brush: bash; title: ; notranslate">
sudo apt install python3-pip
</pre>
<p>Then install ansible with:</p>
<pre class="brush: bash; title: ; notranslate">
sudo pip3 install ansible
</pre>
<p>Type <strong>ansible </strong>to test.</p>
<h2>FreeBSD</h2>
<p>FreeBSD comes with python installed but pip is not. Check the version and then install the same pip version. </p>
<pre class="brush: bash; title: ; notranslate">
ls -l /usr/local/bin/python*
</pre>
<p>If your output is for example <strong>python37</strong>, install the same pip version.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install py37-pip
</pre>
<p>Then install ansible.</p>
<pre class="brush: bash; title: ; notranslate">
pip install ansible
</pre>
<p>Type <strong>ansible </strong>to test.</p>
<h1>SSH keys</h1>
<p>While Ansible can use standard *nix username/password authentication, it&#8217;s recommended that you use SSH keys to communicate from control node to the managed nodes. For that, you&#8217;ll have to create your SSH keys. Let&#8217;s say you have an account on your control node and the username is admin. You also want to use the user ansible on the managed nodes. It really doesn&#8217;t matter what usernames you are going to choose. You can always override the keys to use, but in this case, I&#8217;ll create a key on the control node and send it to all managed nodes.<br />
On the control node, regardless of your OS, do:</p>
<pre class="brush: bash; title: ; notranslate">
ssh-keygen -b 4096
</pre>
<p>This will create a subfolder <strong>.ssh</strong> with two files: <strong>id_rsa</strong> and <strong>id_rsa.pub</strong>. The former is your private key and the later is your public key.<br />
Copy the key to your managed nodes.</p>
<pre class="brush: bash; title: ; notranslate">
ssh-copy-id ansible@nodeX.andreev.local
</pre>
<p>This will copy my key for the user admin to the node X under the ansible user. Then test the passwordless connection.</p>
<pre class="brush: bash; title: ; notranslate">
ssh ansible@nodeX.andreev.local
</pre>
<p>Mind that the use of FQDN (nodex.andreev.local) vs. hostname (nodex) is important. For SSH these two are different. Once you log to the managed node, the node will be added to the list of known hosts in the file <strong>.ssh/known_hosts</strong>. </p>
<h1>Inventory and the config file</h1>
<p>Ansible uses the inventory files to execute an action against using the options and parameters specified in the config file. The config file is <strong>/etc/ansible/ansible.cfg</strong> for CentOS and Ubuntu and <strong>/usr/local/etc/ansible/ansible.cfg </strong>for FreeBSD. You can also put the inventory file in the same directory and name it as you wish, but you have to specify the inventory as a parameter on the command line or an entry in the config file. In addition, you can have your config file in your current directory or under the <strong>.ansible</strong> directory in your home folder. <strong>ansible.cfg</strong> in the current directory has a precedence over <strong>.ansible.cfg</strong> in the home directory which has a precedence over <strong>/etc/ansible/ansible.cfg</strong>. Here is how that looks.<br />
Let&#8217;s list all the inventory.</p>
<pre class="brush: bash; title: ; notranslate">
ansible --list-hosts all
</pre>
<p>You&#8217;ll get a message that there is no inventory file. Let&#8217;s create one, we&#8217;ll name it <strong>inventory.txt</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;freebsd]
node1.andreev.local
&#x5B;centos]
node2.andreev.local
&#x5B;ubuntu]
node3.andreev.local
&#x5B;bsd]
node1.andreev.local
&#x5B;linux]
node2.andreev.local
node3.andreev.local
</pre>
<p>If we specify the inventory file, we&#8217;ll get this.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ansible --list-hosts all -i inventory.txt
  hosts (3):
    node1.andreev.local
    node2.andreev.local
    node3.andreev.local
</pre>
<p>If we create a config file, we can tell ansible where to look for the inventory. Create a file <strong>ansible.cfg</strong> in the same directory.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;defaults]
inventory=/home/&lt;somewhere&gt;/inventory.txt
</pre>
<p>If you do <strong>ansible &#8211;list-hosts all</strong> now, you&#8217;ll get the same result as before, but without specifying the inventory file.<br />
Or something like this. </p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ansible all -m shell -a &quot;uname -a&quot;
node1.andreev.local | CHANGED | rc=0 &gt;&gt;
FreeBSD node1.andreev.local 12.1-RELEASE FreeBSD 12.1-RELEASE r354233 GENERIC  amd64
node2.andreev.local | CHANGED | rc=0 &gt;&gt;
Linux node2.andreev.local 4.18.0-193.14.2.el8_2.x86_64 #1 SMP Sun Jul 26 03:54:29 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
node3.andreev.local | CHANGED | rc=0 &gt;&gt;
Linux node3.andreev.local 4.15.0-129-generic #132-Ubuntu SMP Thu Dec 10 14:02:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
</pre>
<p>By default, ansible runs on the managed node with the currently logged user that executes the playbook on the control node. If you get an error saying that the previous command cannot connect to the host, you have to specify the same user that you used when you test the connection with <em>ssh -user-@managednode.</em> So, edit <strong>ansible.cfg</strong> and add this line.</p>
<pre class="brush: bash; title: ; notranslate">
remote_user=&lt;user&gt;
</pre>
<p>We can target only the group linux which consists of Linux hosts only in the inventory file. </p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ansible linux -m shell -a &quot;date&quot;
node3.andreev.local | CHANGED | rc=0 &gt;&gt;
Fri Jan  8 15:23:40 UTC 2021
node2.andreev.local | CHANGED | rc=0 &gt;&gt;
Fri Jan  8 10:23:40 EST 2021
</pre>
<h1>Playbooks</h1>
<p>The playbooks are the blueprints of the automation tasks. Instead of running the ansible command to execute each task separately, we combine these tasks in a YAML file and execute them sequentially. Here are 3 playbooks that update each of our managed nodes. There is no update module for FreeBSD, so we use the shell command.</p>
<pre class="brush: yaml; title: ; notranslate">
# freebsd-update.yml
---
  - hosts: freebsd
    become: yes
    tasks:
      - name: Fetch all packages
        shell: freebsd-update fetch
      - name: Install FreeBSD updates
        shell: freebsd-update install
      - name: Reboot
        reboot:
</pre>
<p>For CentOS we&#8217;ll use <strong>yum</strong>. </p>
<pre class="brush: yaml; title: ; notranslate">
# centos-update.yml
---
  - hosts: centos
    become: yes
    tasks:
      - name: Update all packages
        yum: name=* state=latest
      - name: Reboot
        reboot:
</pre>
<p>&#8230;and for Ubuntu we&#8217;ll use <strong>apt</strong>.</p>
<pre class="brush: yaml; title: ; notranslate">
# ubuntu-update.yml
---
  - hosts: ubuntu
    become: yes
    tasks:
      - name: Update all packages
        apt: name=* state=latest
      - name: Reboot
        reboot:
</pre>
<p>Save these files with a YAML extension and you can execute them with the following command.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook &lt;filename&gt;
</pre>
<p>All of them will probably fail. That&#8217;s because your ansible user on the managed nodes is required a password when executing a <strong>sudo </strong>command. In order to fix that, you&#8217;ll have to add a line in the sudoers file. Edit this file using the <strong>visudo </strong>command.</p>
<pre class="brush: bash; title: ; notranslate">
visudo
</pre>
<p>&#8230;and then add this line right before the <strong>@includedir <...></strong> which is the last line in the file.</p>
<pre class="brush: bash; title: ; notranslate">
ansible ALL=(ALL) NOPASSWD:ALL
</pre>
<p>Where <strong>ansible </strong>is the user that runs the playbooks on the managed nodes. FreeBSD doesn&#8217;t come with sudo preinstalled, so you&#8217;ll have to install it first on the managed node.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install sudo
</pre>
<p>These playbooks will update the OS and the packages for the Linux. For FreeBSD, it will update only the OS. Here is another example of playbooks that will install Apache server in a default configuration and change the <strong>ServerName </strong>and <strong>ServerAdmin </strong>lines. We&#8217;ll also install PHP and test our server.<br />
If you have a firewall enabled, make sure you open it up first on CentOS. Ubuntu and FreeBSD do not come with the firewall enabled. </p>
<pre class="brush: bash; title: ; notranslate">
firewall-cmd --zone=public --permanent --add-service=http
firewall-cmd --reload
</pre>
<p>For FreeBSD, the playbook looks like this. </p>
<pre class="brush: yaml; title: ; notranslate">
# freebsd-apache.yml
---
  - hosts: freebsd
    become: yes
    tasks:
      - name: Install apache and php
        pkgng:
          name:
            - apache24
            - php74
            - mod_php74
          state:  present
      - name: Start on reboot
        service: name=apache24 enabled=yes
      - name: Copy index.php
        copy:
          src: ../files/index.php
          dest: /usr/local/www/apache24/data
          mode: 0755
      - name: Copy mod_php.conf
        copy:
          src: ../files/mod_php.conf
          dest: /usr/local/etc/apache24/modules.d
          mode: 0755
      - name: Start apache now
        service: name=apache24 state=started
</pre>
<p>For CentOS, it looks like this.</p>
<pre class="brush: yaml; title: ; notranslate">
# centos-apache.yml
---
  - hosts: centos
    become: yes
    tasks:
      - name: Install apache and php
        yum:
          name:
            - httpd
            - php
          state:  present
      - name: Start apache now and on reboot
        service: name=httpd state=started enabled=yes
      - name: Copy index.php
        copy:
          src: ../files/index.php
          dest: /var/www/html
          mode: 0755
</pre>
<p>&#8230;and for Ubuntu it looks like this.</p>
<pre class="brush: yaml; title: ; notranslate">
# ubuntu-apache.yml
---
  - hosts: ubuntu
    become: yes
    tasks:
      - name: Install apache and php
        apt:
          name:
            - apache2
            - php
          state:  present
      - name: Start apache now and on reboot
        service: name=apache2 state=started enabled=yes
      - name: Copy index.php
        copy:
          src: ../files/index.php
          dest: /var/www/html
          mode: 0755
</pre>
<p>You will also need these two files in a directory called <strong>files</strong>. In my case it&#8217;s one level above the directory where I keep my playbooks.<br />
<strong>index.php</strong></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
  phpinfo();
?&gt;
</pre>
<p><strong>001_mod-php.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
&lt;IfModule dir_module&gt;
    DirectoryIndex index.php index.html
    &lt;FilesMatch &quot;\.php$&quot;&gt;
        SetHandler application/x-httpd-php
    &lt;/FilesMatch&gt;
    &lt;FilesMatch &quot;\.phps$&quot;&gt;
        SetHandler application/x-httpd-php-source
    &lt;/FilesMatch&gt;
&lt;/IfModule&gt;
</pre>
<p>The <strong>index.php</strong> file is the standard test file to test the PHP distributions and the <strong>001_mod-php.conf</strong> is needed for FreeBSD only. As you can see the playbooks differ quite a bit for these three OSes. Once you deploy the playbooks, you can test the result by going to <strong>http://[nodeX]/index.php</strong>.<br />
Looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2021/01/P153-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/01/P153-02.png" alt="" width="983" height="227" class="aligncenter size-full wp-image-8802" srcset="https://blog.andreev.it/wp-content/uploads/2021/01/P153-02.png 983w, https://blog.andreev.it/wp-content/uploads/2021/01/P153-02-300x69.png 300w, https://blog.andreev.it/wp-content/uploads/2021/01/P153-02-768x177.png 768w, https://blog.andreev.it/wp-content/uploads/2021/01/P153-02-585x135.png 585w" sizes="(max-width: 983px) 100vw, 983px" /></a></p>
<h1>Service handlers</h1>
<p>Service handlers are used only when a change is made on the managed node. For example, we can restart a service only if the config file was changed. If the file is not changed, then there is no need to restart. Here is an example of a service handler. We&#8217;ll restart postfix service only if the main.cf file was changed.</p>
<pre class="brush: yaml; highlight: [11,14]; title: ; notranslate">
# service-handler.yml
---
- hosts: centos
  become: yes
  tasks:
  - name: Configure main.cf
    lineinfile:
      path: /etc/postfix/main.cf
      regexp: ^#mydomain
      line: 'mydomain = example.com'
    notify: restart postfix

  handlers:
  - name: restart postfix
    service: name=postfix state=restarted
</pre>
<p>Make sure that the name for the handler is the same (lines 11 and 14), so Ansible knows what service handlers is referred. </p>
<h1>Variables</h1>
<p>When ansible runs a playbook on a managed node, the first task is to gather info about the managed node. The info is a bunch of settings that we can use in our playbooks. For example, if you execute the following command, you can see the IP address, the CPU model, python version etc.</p>
<pre class="brush: bash; title: ; notranslate">
ansible -m setup &lt;node&gt;
</pre>
<p>We can use these settings and use them as variables if we need them. For example, this playbook displays the hostname and the IP.</p>
<pre class="brush: yaml; title: ; notranslate">
# showip.yml
---
  - hosts: freebsd
    become: yes
    tasks:
      - name: Show the IP address
        debug:
          msg: &quot;The hostname is {{ inventory_hostname}}  and the IP is {{ansible_default_ipv4.address }}&quot;
</pre>
<p>And if you run the playbook, you&#8217;ll see something like this.</p>
<pre class="brush: plain; title: ; notranslate">
TASK &#x5B;Show the IP address] *********************************************************************************************
ok: &#x5B;node1.andreev.local] =&gt; {
    &quot;msg&quot;: &quot;The hostname is node1.andreev.local  and the IP is 192.168.1.211&quot;
}
</pre>
<p>Here is another example of using variables. In this case, we&#8217;ll specify a file and change the ownership and the mode.</p>
<pre class="brush: yaml; title: ; notranslate">
# owner.yml
---
  - hosts: centos
    become: yes
    vars:
      filename: &quot;/var/www/html/index.php&quot;
    tasks:
      - name: Change the owner of the file
        file:
          path: &quot;{{ filename }}&quot;
          owner: apache
          group: apache
          mode: '0755'
</pre>
<p>In case we want to assign an output to a variable, we&#8217;ll have to use the keyword <strong>register</strong>. Here is an example of how to get the output from a command and print it on the screen with the keyword <strong>debug</strong>.</p>
<pre class="brush: yaml; title: ; notranslate">
# variables.yml
---
  - hosts: freebsd

    tasks:
    - name: Get the uptime manually
      command: uptime
      register: var_uptime

    - name: Print the uptime
      debug:
        msg: The uptime is &quot;{{ var_uptime }}&quot;
</pre>
<h1>Roles</h1>
<p>Roles let you automatically load related vars_files, tasks, handlers, and other Ansible artifacts based on a known file structure. Once you group your content in roles, you can easily reuse them and share them with other users. The idea is to separate the tasks, handlers and vars in different files. Let&#8217;s see this playbook for example. It changes a line in main.cf file, restarts postfix and copies a file under the postfix main directory.</p>
<pre class="brush: yaml; title: ; notranslate">
# roles.yml
---
  - hosts: centos
    become: yes

    vars:
      filevd: &quot;/etc/postfix/virtual_domains&quot;
      cfgpostfix: &quot;/etc/postfix/main.cf&quot;


    tasks:
    - name: Configure main.cf
      lineinfile:
        path: &quot;{{ cfgpostfix }}&quot;
        regexp: ^#mydomain
        line: 'mydomain = example.com'
      notify: restart postfix
    - name: Copy virtual_domains
      copy:
        src: ../files/virtual_domains
        dest: &quot;{{ filevd }}&quot;
        mode: 0755

    handlers:
    - name: restart postfix
      service: name=postfix state=restarted
</pre>
<p>We can rewrite this file by separating the tasks, variables, files and handlers. Run this command.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-galaxy role init postfix
</pre>
<p>If you look at the file/directory structure of the newly created directory postfix, it looks like this.</p>
<pre class="brush: plain; highlight: [1]; title: ; notranslate">
tree postfix
postfix
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml
</pre>
<p>Create a file <strong>virtual_domains</strong> under the <strong>files </strong>directory.</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;mydomain.com&quot; &gt; postfix/files/virtual_domains
</pre>
<p>Move the config for vars, handlers and tasks in the separate <strong>main.yml</strong> files. For example, this is how my files look like.<br />
<strong>postfix/vars/main.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
---
# vars file for postfix

  filevd: &quot;/etc/postfix/virtual_domains&quot;
  cfgpostfix: &quot;/etc/postfix/main.cf&quot;
</pre>
<p>As you can see the keyword <strong>vars:</strong> does not exists. Ansible knows that this file is for <strong>vars </strong>so there is no need to enter the <strong>vars </strong>keyboard.<br />
<strong>postfix/tasks/main.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
---
# tasks file for postfix

  - name: Configure main.cf
    lineinfile:
      path: &quot;{{ cfgpostfix }}&quot;
      regexp: ^#mydomain
      line: 'mydomain = example.com'
    notify: restart postfix
  - name: Copy virtual_domains
    copy:
      src: ../files/virtual_domains
      dest: &quot;{{ filevd }}&quot;
      mode: 0755
</pre>
<p><strong>postfix/handlers/main.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
---
# handlers file for postfix

  - name: restart postfix
    service: name=postfix state=restarted
</pre>
<p>Finally, create a file called something.yml that will be your main file. This file has to be outside the postfix directory structure.<br />
In my case it looks like this.<br />
<strong>something.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
# something.yml
---
  - hosts: centos
    become: yes
    roles:
      - postfix
</pre>
<p>Now, if you execute this playbook, ansible will automatically execute the rest of the dependant playbooks as well.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook something.yml
</pre>
<h1>Error handling</h1>
<p>Sometimes we want certain changes to be ignored. Sometimes, we know the behavior of certain commands and we know that they might return non-zero code and we want that ignored. For example, consider this part of a playbook.</p>
<pre class="brush: yaml; title: ; notranslate">
- hosts: centos
  tasks: 
  - name: Type something that will fail
    command: thiscommanddoesntexist
    ignore_errors: yes

  - name: Run command remotely
    command: /usr/local/bin/somecommand
    register: cmd_result
    changed_when: cmd_result == 2
</pre>
<p>Ansible would report a task as changed as long as the command (or) script gives zero return code.<br />
In the first part, we know that the task will fail, but we decide to ignore it using the keyword <strong>ignore_errors</strong>. No matter what the command returns, <strong>ignore_errors: yes</strong> will never report to ansible that the command failed.<br />
In the second command we can ignore the error based on the output of the command. For example, if the output is 2, the the error will be ignored. If cmd_result is not equal to 2, the task will be marked as changed.<br />
So whenever this condition is true, the task will be marked as changed. </p>
<h1>Tags</h1>
<p>Tags are used when you have a playbook with several tasks and you need to run only specific parts of it instead of running the entire playbook. You use tags to execute or skip selected tasks. Let&#8217;s say we have this playbook that installs Docker on Centos and has multiple tasks. As you can notice in lines 12, 24, 37 and 45 we have a new line with a keyword <strong>tags</strong> that we use to tag certain tasks. The purpose of this is to include or exclude these tasks from the playbook.</p>
<pre class="brush: yaml; highlight: [12,24,37,45]; title: ; notranslate">
# centos-docker.yml
---
- name: Install docker
  hosts: centos
  become: true

  tasks:
    - name: Install yum utils
      yum:
        name: yum-utils
        state: latest
      tags: install

    - name: Install device-mapper-persistent-data
      yum:
        name: device-mapper-persistent-data
        state: latest
      tags: install

    - name: Install lvm2
      yum:
        name: lvm2
        state: latest
      tags: install

    - name: Add Docker repo
      get_url:
        url: https://download.docker.com/linux/centos/docker-ce.repo
        dest: /etc/yum.repos.d/docer-ce.repo
      become: yes

    - name: Install Docker
      package:
        name: docker-ce
        state: latest
      become: yes
      tags: install

    - name: Start Docker service
      service:
        name: docker
        state: started
        enabled: yes
      become: yes
      tags: start
</pre>
<p>Now, with the command below, we can execute the playbook and only the tasks tagged with <strong>install </strong>will be executed.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook centos-docker.yaml --tags install
</pre>
<p>We can also tell ansible to NOT run those tasks tagged with <strong>install</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook centos-docker.yaml --skip-tags install
</pre>
<p>You can add multiple tags per task, e.g.</p>
<pre class="brush: yaml; title: ; notranslate">
tags:
  - cleanup_app
  - cleanup_web
</pre>
<p>Ansible reserves two tag names for special behavior: <strong>always </strong>and <strong>never</strong>. If you assign the <strong>always </strong>tag to a task or play, Ansible will always run that task or play, unless you specifically skip it (<strong>&#8211;skip-tags always</strong>). If you assign the <strong>never </strong>tag to a task or play, Ansible will skip that task or play unless you specifically request it (<strong>&#8211;tags never</strong>).</p>
<h1>Ansible Vault</h1>
<p>Ansible Vault encrypts variables and files so you can protect sensitive content such as passwords or keys rather than leaving it visible as plaintext in playbooks or roles.<br />
First, you have to create a vaulted file where we&#8217;ll store the passwords. When you run this command it will ask you to create a password and then an empty file will show up.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-vault create secrets.yml
</pre>
<p>Add some passwords there and save the file.</p>
<pre class="brush: bash; title: ; notranslate">
mysql_pwd: &quot;DifficultPassword&quot;
ht_pwd: &quot;PasswordXYZ&quot;
</pre>
<p>If you look at the file now, you&#8217;ll see that it&#8217;s encrypted and you can&#8217;t see the passwords anymore.<br />
If you want to edit the file do <strong>ansible-vault edit secrets.yaml</strong> and enter the vault password.<br />
Create a small playbook that displays the password.</p>
<pre class="brush: yaml; title: ; notranslate">
# centos-vault.yml
---
- hosts: centos
  vars_files:
    - secrets.yml

  tasks:
  - name: Show mysql pwd
    debug:
      msg: &quot;{{ mysql_pwd }}&quot;
</pre>
<p>If you run the playbook now, ansible will throw an error saying ERROR! Attempting to decrypt but no vault secrets found. You have to specify the parameter <strong>&#8211;ask-vault-pass</strong> and enter the vault password when prompted.</p>
<h1>Prompts</h1>
<p>In case you need to pause the playbook execution and ask the user for some input such as confirmation or password, use prompts.<br />
If you want the output to echo, use <strong>private: no</strong>, otherwise what you type won&#8217;t show up on the screen. Here is an example of a playbook that asks you to confirm if a file needs to be copied to the node. If you type <strong>yes</strong> and hit enter, the file will be copied, otherwise it won&#8217;t.</p>
<pre class="brush: yaml; title: ; notranslate">
# centos-prompt.yml
---
- hosts: centos
  become: yes

  vars_prompt:
    name: upload
    private: no
    prompt: &quot;Do you want to upload xyz.txt?&quot;

  tasks:
  - name: Upload xyz.txt
    copy:
      src: xyz.txt
      dest: /var/log
    when: upload == &quot;yes&quot;
</pre>
<h1>Useful options</h1>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook &lt;name&gt; --syntax-check # checks the syntax of the playbook
ansible-playbook &lt;name&gt; --check # does a dry run, reports the will-be changes, but the playbook is not executed
ansible-playbook &lt;name&gt; --step # ask to confirm each-step
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2021/02/ansible-quick-start-guide-for-freebsd-centos-and-ubuntu/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>General: How to stream/broadcast from your phone</title>
		<link>https://blog.andreev.it/2020/05/general-how-to-stream-broadcast-from-your-phone/</link>
					<comments>https://blog.andreev.it/2020/05/general-how-to-stream-broadcast-from-your-phone/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 03 May 2020 13:47:48 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[broadcast]]></category>
		<category><![CDATA[Larix]]></category>
		<category><![CDATA[SRT]]></category>
		<category><![CDATA[streaming]]></category>
		<category><![CDATA[VLC]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=6678</guid>

					<description><![CDATA[In this short article I&#8217;ll describe briefly how to stream/broadcast from your phone&#8217;s camera&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this short article I&#8217;ll describe briefly how to stream/broadcast from your phone&#8217;s camera to the world. In order to do that, you&#8217;ll need the <strong>Larix Broadcaster</strong> app installed on your phone, you will need a server with a public IP and a <strong>Haivision Media Gateway</strong> installed and for the end users, they&#8217;ll need standard <strong>VLC Player</strong> install.<br />
The Larix Broadcaster app and the VLC player are free, but Haivision Media Gateway is not. In addition, if you have your own server and want to install it as a VM, you&#8217;ll have to contact the vendor directly. I&#8217;ll use a much easier option and host it in AWS where it comes as a template from the <a href="https://aws.amazon.com/marketplace/pp/Haivision-Haivision-Media-Gateway-PAYG/B014VA1JZ4" rel="noopener noreferrer" target="_blank">AWS Marketplace</a>.</p>
<h1>Haivision Media Gateway in AWS</h1>
<p>In AWS, launch a new instance from the AWS Marketplace and search for SRT. You&#8217;ll see several options(SRT Gateway vs. Media Gateway and BYOL as PAYG license). I&#8217;ll choose Pay-as-You-Go Media Gateway.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-01.png" alt="" width="1357" height="191" class="aligncenter size-full wp-image-6680" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-01.png 1357w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-300x42.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-1024x144.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-768x108.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-1170x165.png 1170w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-01-585x82.png 585w" sizes="(max-width: 1357px) 100vw, 1357px" /></a><br />
As you can see, the software is not that cheap and you pay as much as you used. So if you are not streaming, just shut down the instance. Another important thing is the size of the instance, how much horse power you need. Is it 2 CPUs, 4 CPUs, 8? Well, nobody knows your needs, but it also depends on what type of stream are you sending, is it going to be a low-res or 1080p, how many users will consume that stream, etc. I strongly suggest that you go over this <a href="https://doc.haivision.com/additional-resources/srt-deployment-guide" rel="noopener noreferrer" target="_blank">document</a>. It describes how to size your environment and it gives you practical guidance on how to configure the Media Gateway. It&#8217; not a necessary read to continue with this post, but it&#8217;s strongly recommended once you have everything up and running.<br />
OK, in my case I&#8217;ll go with a t3.medium instance which is 2 CPUs and 4GB RAM. Create the instance as you normally do, make sure you have a public IP and the ports that are recommended in the security group given are open (22, 80 and 443). Once the instance boots up log with the default username <strong>haiadmin </strong>and the password is your instance id which is <strong>i-0123something</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-02.png" alt="" width="468" height="488" class="aligncenter size-full wp-image-6681" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-02.png 468w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-02-288x300.png 288w" sizes="(max-width: 468px) 100vw, 468px" /></a><br />
I won&#8217;t go into details what each option does and what each keyword means, I&#8217;ll just guide you through creating a route for you to be able to broadcast. So, from the screen that you see, click on the button to add a route.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-03.png" alt="" width="1061" height="137" class="aligncenter size-full wp-image-6682" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-03.png 1061w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-300x39.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-1024x132.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-768x99.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-03-585x76.png 585w" sizes="(max-width: 1061px) 100vw, 1061px" /></a><br />
These are my parameters. For the <strong>Route Name</strong>, enter a description and make sure the checkmark is checked for Start Route. Further down, enter a description for the <strong>Source Name</strong>, in my case it&#8217;s Larix Cam or whatever you want to put here. The <strong>Protocol </strong>is <strong>TS Over SRT</strong> and the port is <strong>50000</strong>. The <strong>Mode </strong>is <strong>Listener </strong>and the rest are the defaults. As I said earlier, if you want a better throughput, read the SRT deployment guide doc that I&#8217;ve sent earlier. It will tell you how to tweak these parameters. So, this tells the Media Gateway to listen on port UDP 50000 for any incoming broadcast.<br />
Now, click on the <strong>Destination </strong>button.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-05.png" alt="" width="1082" height="131" class="aligncenter size-full wp-image-6683" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-05.png 1082w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-300x36.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-1024x124.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-768x93.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-05-585x71.png 585w" sizes="(max-width: 1082px) 100vw, 1082px" /></a><br />
The <strong>Destination </strong>is where the broadcast will be distributed. So, you got the point now. A camera on your phone sends the video to our instance in AWS and this instance (Media Gateway) distributes the feed to numerous viewers. You can&#8217;t stream from your phone directly, because your phone&#8217;s bandwidth and horse power are minuscule, so you need a gateway.<br />
Here is how the <strong>Destination </strong>looks like.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-06.png" alt="" width="657" height="753" class="aligncenter size-full wp-image-6684" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-06.png 657w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-06-262x300.png 262w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-06-585x670.png 585w" sizes="(max-width: 657px) 100vw, 657px" /></a><br />
Name the destination however you like, make sure the <strong>Protocol </strong>is <strong>TS over SRT</strong> and the <strong>Port </strong>is 50001. The Media Gateway passes the signal from UDP 50000 (source) to UDP 50001 (destination). Can you use some other ports? Yes, you can as long as they are not the same and greater than 1024 and less than 65535. Change the <strong>Type </strong>to <strong>Listener </strong>and leave the rest of the parameters as-is. Again, read the SRT Deployment Guide. Click <strong>Add </strong>and once you go back, click <strong>Create </strong>to create the route.<br />
<strong>SUPER IMPORTANT</strong>: Make sure you edit the security group for this instance and open the ports for the source and destination. In my case, you have to add UDP ports 50000 and 50001 to the rules of the security group.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-07.png" alt="" width="1094" height="527" class="aligncenter size-full wp-image-6685" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-07.png 1094w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-300x145.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-1024x493.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-768x370.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-07-585x282.png 585w" sizes="(max-width: 1094px) 100vw, 1094px" /></a></p>
<h1>Larix Broadcaster app</h1>
<p>On your phone download this app from Google Play or App Store. Go to <strong>Settings </strong>(the gear icon), <strong>Connections </strong>and click on the <strong>(+)</strong> sign to add a connection.<br />
Enter a name for your connection, and for the URL enter the public IP of your instance and the port of the listener, so it looks like <strong>srt://public_IP:port</strong>. Make sure you specify <strong>srt://</strong> as prefix. The defaults are 640&#215;480 with audio, but you can change that in the settings for the app. Now, that you have a connection, make sure it&#8217;s active by selecting it and after that just hit the <strong>Record </strong>button. If something is not right, you&#8217;ll see it right away on your camera. It will tell you that the app can&#8217;t connect to the server. And if everything is OK after about 8-10 seconds you&#8217;ll see a green dot next to your source in the Media Gateway.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-09.png" alt="" width="1039" height="134" class="aligncenter size-full wp-image-6687" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-09.png 1039w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-300x39.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-1024x132.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-768x99.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-09-585x75.png 585w" sizes="(max-width: 1039px) 100vw, 1039px" /></a></p>
<h1>VLC PLayer</h1>
<p>There is really nothing much to say here. Go to <a href="https://www.videolan.org/vlc/index.html" rel="noopener noreferrer" target="_blank">this </a>website, download and install <strong>VLC </strong>and from the menu click on <strong>Media | Open Network Stream</strong>. Enter the IP address of the AWS instance and specify the destination port like <strong>srt://public_IP:port</strong>. Make sure you specify the destination port, not the source port and the protocol should be srt.</p>
<h1>Stream a video file (optional)</h1>
<p>In case you want your source to be a video file instead of a camera stream, reconfigure the source or add another route with new source and destination of which the source is RTMP. Configure the source so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/05/P149-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/05/P149-10.png" alt="" width="1096" height="819" class="aligncenter size-full wp-image-6690" srcset="https://blog.andreev.it/wp-content/uploads/2020/05/P149-10.png 1096w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-300x224.png 300w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-1024x765.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-768x574.png 768w, https://blog.andreev.it/wp-content/uploads/2020/05/P149-10-585x437.png 585w" sizes="(max-width: 1096px) 100vw, 1096px" /></a><br />
From another server send the video stream to the Media Gateway using this command (you need ffmpeg installed).</p>
<pre class="brush: bash; title: ; notranslate">
ffmpeg -re -i video-file.mp4 -c copy -f flv rtmp://media_gateway_ip/live/stream
</pre>
<p>In VLC, use the <strong>srt://media_gateway_ip:port</strong> to watch the stream.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2020/05/general-how-to-stream-broadcast-from-your-phone/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CentOS, pfSense: Site-to-site VPN tunnel with strongswan and pfSense</title>
		<link>https://blog.andreev.it/2019/03/150-centos-pfsense-site-to-site-vpn-tunnel-with-strongswan-and-pfsense/</link>
					<comments>https://blog.andreev.it/2019/03/150-centos-pfsense-site-to-site-vpn-tunnel-with-strongswan-and-pfsense/#comments</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sat, 09 Mar 2019 20:32:16 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[pfSense]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[strongswan]]></category>
		<category><![CDATA[VPN]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=4701</guid>

					<description><![CDATA[I have written a lot about pfSense and different types of VPN scenarios (AWS,&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I have written a lot about pfSense and different types of VPN scenarios (AWS, Azure), but never created a post about a site-to-site VPN tunnel with CentOS running strongswan and pfSense. The scenario described here works with CentOS, but it will work with any other Linux of BSD distribution. The syntax for strongswan is the same, it&#8217;s just the configuration file names and locations that are different across distributions. </p>
<h1>Prerequisites</h1>
<p>Both the pfSense box and CentOS need to have public IPs. While it&#8217;s possible to have them behind NAT, this scenario only covers configurations with public IPs. You should disable the firewalld on CentOS (initially). Both of them need two network interfaces. In my case this is how it looks like.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-01.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-01.jpg" alt="" width="896" height="532" class="aligncenter size-full wp-image-8464" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-01.jpg 896w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-01-300x178.jpg 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-01-768x456.jpg 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-01-585x347.jpg 585w" sizes="(max-width: 896px) 100vw, 896px" /></a><br />
It&#8217;s also easier if you create a small spreadsheet so you don&#8217;t loose track of the IPs and subnets.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-02.png" alt="" width="396" height="89" class="aligncenter size-full wp-image-8465" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-02.png 396w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-02-300x67.png 300w" sizes="(max-width: 396px) 100vw, 396px" /></a></p>
<h1>CentOS configuration</h1>
<p>I am using CentOS 7. First, we have to install strongswan and disable the firewall temporarily.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install epel-release
yum -y install strongswan
systemctl enable strongswan
systemctl stop firewalld
systemctl disable firewalld
</pre>
<p>Once installed, change these system variables so you allow IP forwarding and prevent ICMP redirects. </p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;net.ipv4.ip_forward=1&quot; &gt;&gt; /etc/sysctl.conf
echo &quot;net.ipv4.conf.all.accept_redirects=0&quot; &gt;&gt; /etc/sysctl.conf
echo &quot;net.ipv4.conf.all.send_redirects=0&quot; &gt;&gt; /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
</pre>
<p>strongswan on CentOS places its config under <strong>/etc/strongswan</strong> directory. We’ll use a config with pre-shared key because it’s easier to implement. So, edit the <strong>/etc/strongswan/ipsec.conf</strong> file, remove everything there and paste this config. Of course, this assumes that you don’t have any working configs there. Now, look at the highlighted lines. That’s where you have to replace the IPs and the subnets with your values. E.g. line 13 is the private IP of the CentOS server, 14 is the subnet, 15 is the ID of the server (IP or hostname), 17 is the external IP of the pfSense server, 18 is its subnet and line 19 is the ID of the pfSense server (IP or hostname). This is where the small spreadsheet above comes handy.</p>
<pre class="brush: bash; highlight: [13,14,15,17,18,19]; title: ; notranslate">
config setup

conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        authby=secret
        keyexchange=ikev2
        mobike=no

conn net-net
        left=148.27.56.195
        leftsubnet=10.1.96.0/20
        leftid=148.27.56.195
        leftfirewall=no
        right=23.183.125.249
        rightsubnet=192.168.1.1/24
        rightid=23.183.125.249
        ike=aes256-sha256-modp2048!
        esp=aes256-sha256!
        pfs=no
        auto=start
        lifetime=1h
</pre>
<p>Then, edit the <strong>/etc/strongswan/ipsec.secret</strong> file and specify the pre-shared key. This is a password that the servers will use to authenticate. Make sure it’s something more complex in production. In my case, the password is &#8220;<strong>secret</strong>&#8220;.</p>
<pre class="brush: bash; title: ; notranslate">	
# ipsec.secrets - strongSwan IPsec secrets file
148.27.56.195 23.183.125.249 : PSK &quot;secret&quot;
</pre>
<h1>pfSense</h1>
<p>Now that the CentOS strongswan box is configured, we can configure pfSense. In pfSense, go to <strong>VPN | IPSec</strong> from the menu and click on <strong>Add P1</strong> button. Fill out the <strong>General Information</strong> section, so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-03.png" alt="" width="1153" height="431" class="aligncenter size-full wp-image-8466" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-03.png 1153w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-03-300x112.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-03-1024x383.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-03-768x287.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-03-585x219.png 585w" sizes="(max-width: 1153px) 100vw, 1153px" /></a><br />
As you can see, we use <strong>IKEv2 </strong>and our remote gateway is <strong>148.27.56.195</strong> which is the CentOS strongswan box.<br />
For <strong>Phase 1 Proposal (Authentication and Algorithms)</strong>, fill out the section so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-04.png" alt="" width="1160" height="535" class="aligncenter size-full wp-image-8467" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-04.png 1160w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-04-300x138.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-04-1024x472.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-04-768x354.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-04-585x270.png 585w" sizes="(max-width: 1160px) 100vw, 1160px" /></a><br />
From the screenshot above, you can see that the values correspond to what we have in ipsec.conf file.<br />
For the <strong>Advanced Options</strong> section, use the defaults.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-05.png" alt="" width="1173" height="511" class="aligncenter size-full wp-image-8468" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-05.png 1173w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-05-300x131.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-05-1024x446.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-05-768x335.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-05-1170x511.png 1170w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-05-585x255.png 585w" sizes="(max-width: 1173px) 100vw, 1173px" /></a><br />
Click <strong>Save</strong> and then from the main <strong>IPSec | Tunnels</strong> menu, click on <strong>Add P2</strong> button.<br />
For Phase 2, fill out these values for the <strong>General Information</strong> section.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-06.png" alt="" width="1161" height="424" class="aligncenter size-full wp-image-8469" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-06.png 1161w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-06-300x110.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-06-1024x374.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-06-768x280.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-06-585x214.png 585w" sizes="(max-width: 1161px) 100vw, 1161px" /></a><br />
Change the values for <strong>Local Network</strong> and <strong>Remote Network</strong> to suit your needs. These are the local subnets behind pfSense and strongswan.<br />
For <strong>Phase 2 Proposal (SA/Key Exchange)</strong> section, choose these values.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-07.png" alt="" width="1150" height="631" class="aligncenter size-full wp-image-8470" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-07.png 1150w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-07-300x165.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-07-1024x562.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-07-768x421.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-07-585x321.png 585w" sizes="(max-width: 1150px) 100vw, 1150px" /></a><br />
For the <strong>Advanced Configuration</strong> section, you can leave it as is, or put the private IP of the CentOS box so the IPSec protocol sends keep-alive pings. It&#8217;s not mandatory, but if your tunnel fails frequently, you can configure this field.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-08.png" alt="" width="1156" height="131" class="aligncenter size-full wp-image-8471" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-08.png 1156w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-08-300x34.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-08-1024x116.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-08-768x87.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-08-585x66.png 585w" sizes="(max-width: 1156px) 100vw, 1156px" /></a><br />
Click <strong>Save </strong>and the VPN config is done. But, we have to tell pfSense to allow IPSec traffic. So, from the menu go to <strong>Firewall | Rules</strong> and click on <strong>IPSec </strong>submenu. Click <strong>Add </strong>and fill out the form so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-09.png" alt="" width="1156" height="429" class="aligncenter size-full wp-image-8472" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-09.png 1156w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-09-300x111.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-09-1024x380.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-09-768x285.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-09-585x217.png 585w" sizes="(max-width: 1156px) 100vw, 1156px" /></a><br />
&#8230;and this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/03/P127-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/03/P127-10.png" alt="" width="1157" height="442" class="aligncenter size-full wp-image-8473" srcset="https://blog.andreev.it/wp-content/uploads/2019/03/P127-10.png 1157w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-10-300x115.png 300w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-10-1024x391.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-10-768x293.png 768w, https://blog.andreev.it/wp-content/uploads/2019/03/P127-10-585x223.png 585w" sizes="(max-width: 1157px) 100vw, 1157px" /></a><br />
Click <strong>Save </strong>and go back to the CentOS box.</p>
<h1>Site-to-site VPN tunnel</h1>
<p>At this point you can start the VPN.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl start strongswan
</pre>
<p>If everything is OK, the log will look like this.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
tail -f /var/log/messages
Mar  9 16:15:00 titan charon: 09&#x5B;NET] sending packet: from 148.27.56.195&#x5B;500] to 23.183.125.249&#x5B;500] (256 bytes)
Mar  9 16:15:00 titan charon: 10&#x5B;NET] received packet: from 23.183.125.249&#x5B;500] to 148.27.56.195&#x5B;500] (224 bytes)
Mar  9 16:15:00 titan charon: 10&#x5B;ENC] parsed IKE_AUTH response 1 &#x5B; IDr AUTH N(ESP_TFC_PAD_N) SA TSi TSr ]
Mar  9 16:15:00 titan charon: 10&#x5B;IKE] authentication of '23.183.125.249' with pre-shared key successful
Mar  9 16:15:00 titan charon: 10&#x5B;IKE] IKE_SA net-net&#x5B;1] established between 148.27.56.195&#x5B;148.27.56.195]...23.183.125.249&#x5B;23.183.125.249]
Mar  9 16:15:00 titan charon: 10&#x5B;IKE] scheduling reauthentication in 3350s
Mar  9 16:15:00 titan charon: 10&#x5B;IKE] maximum IKE_SA lifetime 3530s
Mar  9 16:15:00 titan charon: 10&#x5B;IKE] received ESP_TFC_PADDING_NOT_SUPPORTED, not using ESPv3 TFC padding
Mar  9 16:15:00 titan charon: 10&#x5B;CFG] selected proposal: ESP:AES_CBC_256/HMAC_SHA2_256_128/NO_EXT_SEQ
Mar  9 16:15:00 titan charon: 10&#x5B;IKE] CHILD_SA net-net{1} established with SPIs c82fdbae_i ce57b856_o and TS 10.1.96.0/20 === 192.168.1.0/24
</pre>
<p>Check the status.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
strongswan status
Security Associations (1 up, 0 connecting):
     net-net&#x5B;3]: ESTABLISHED 3 minutes ago, 148.27.56.195&#x5B;148.27.56.195]...23.183.125.249&#x5B;23.183.125.249]
     net-net{3}:  INSTALLED, TUNNEL, reqid 2, ESP SPIs: c818e2d7_i c34c4c3d_o
     net-net{3}:   10.1.96.0/20 === 192.168.1.0/24
</pre>
<p>If the current CentOS box is not your Internet gateway for the servers behind, you have to add a static route to the pfSense subnet. So, on each server behind CentOS, do something like this.</p>
<pre class="brush: bash; title: ; notranslate">
route add 192.168.1.0 mask 255.255.255.0 10.1.96.3 -p
</pre>
<p>Check the documentation for other OSes. You have to tell the OS to use 10.1.96.3 (internal strongswan IP) as a gateway to 192.168.1.0 subnet. Because my pfSense box is also my gateway, I don&#8217;t have to make these changes. </p>
<h1>Firewall</h1>
<p>Now, everything is up and running, but we have the firewall disabled and the CentOS box is exposed to Internet. Not good. In order to fix that, we have to make some changes and allow the IPSec protocol to flow through the firewall.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl enable firewalld
systemctl start firewalld
firewall-cmd --set-default-zone=dmz
firewall-cmd --zone=dmz --permanent --add-rich-rule='rule protocol value=&quot;esp&quot; accept' 
firewall-cmd --zone=dmz --permanent --add-rich-rule='rule protocol value=&quot;ah&quot; accept' 
firewall-cmd --zone=dmz --permanent --add-port=500/udp 
firewall-cmd --zone=dmz --permanent --add-port=4500/udp 
firewall-cmd --permanent --add-service=&quot;ipsec&quot;
firewall-cmd --zone=dmz --permanent --add-masquerade
firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -m policy --pol ipsec --dir out -j ACCEPT
firewall-cmd --reload
</pre>
<p>&#8230;and you are all set.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2019/03/150-centos-pfsense-site-to-site-vpn-tunnel-with-strongswan-and-pfsense/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>CentOS: NFS &#8211; quick install</title>
		<link>https://blog.andreev.it/2018/12/139-centos-nfs-quick-install/</link>
					<comments>https://blog.andreev.it/2018/12/139-centos-nfs-quick-install/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 09 Dec 2018 00:26:07 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[NFS]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=4180</guid>

					<description><![CDATA[NFS (Network File System) is a distributed file system protocol originally developed by Sun&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>NFS (Network File System) is a distributed file system protocol originally developed by Sun Microsystems in 1984, allowing a user on a client computer to access files over a computer network much like local storage is accessed. NFS, like many other protocols, builds on the Open Network Computing Remote Procedure Call (ONC RPC) system. The NFS is an open standard defined in Request for Comments (RFC), allowing anyone to implement the protocol. That&#8217;s what <a href="https://en.wikipedia.org/wiki/Network_File_System" rel="noopener noreferrer" target="_blank">Wikipedia</a> says.<br />
NFS is used as a file system when two or more instances need access to the same file system. E.g. SQL clusters, VM clusters, Docker Swarm, etc&#8230;<br />
In this post, I&#8217;ll describe a very quick install on a server and show you how to mount that on another CentOS box.</p>
<h1>Server Install</h1>
<p>On the server (in my case 192.168.1.91) I&#8217;ll install the NFS server, start it, make sure it starts at boot and then I&#8217;ll allow the firewall to accept the NFS clients. If you have SELinux enabled, it&#8217;s automatically configured.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install nfs-utils
systemctl start nfs-server
systemctl enable nfs-server
firewall-cmd --permanent --zone=public --add-service nfs
firewall-cmd --reload
</pre>
<p>Let&#8217;s create an empty directory, configure the permissions and create the NFS share. </p>
<pre class="brush: bash; title: ; notranslate">
mkdir /nfs
chown nfsnobody:nfsnobody /nfs
chmod 755 /nfs
</pre>
<p>We have to tell the NFS server about the share. Execute this line that will add the correct line in <strong>/etc/exports</strong>. That&#8217;s where the NFS server expects its shares defined.</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;/nfs    *(rw,sync,no_root_squash,no_subtree_check)&quot; &gt;&gt; /etc/exports
</pre>
<p>The * means that all IPs can have access to this share.  Do <strong>man 5 exports</strong> to see all available options. We have to tell the NFS server to export the share now.</p>
<pre class="brush: bash; title: ; notranslate">
exportfs -a
</pre>
<p>Check the exported share.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
exportfs -s
/nfs  *(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
</pre>
<h1>Client install</h1>
<p>On the client, we&#8217;ll have to install the NFS client. It&#8217;s the same package.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install nfs-utils
</pre>
<p>There is no need to start any service or change any firewall settings.<br />
Let&#8217;s mount the share. I&#8217;ll mount it under <strong>/mnt/nfs</strong> which is a new directory on the client.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir -p /mnt/nfs
mount 192.168.1.91:/nfs /mnt/nfs
</pre>
<p>If you create a file on the share now and go back to the server you&#8217;ll see that the file is there.</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;NFS test&quot; &gt; /mnt/nfs/nfs.txt
</pre>
<p>In order to mount this share anytime you boot the client, you&#8217;ll have to add it to <strong>/etc/fstab</strong> so it mounts on boot.</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;192.168.1.91:/nfs       /mnt/nfs    nfs     defaults 0 0&quot; &gt;&gt; /etc/fstab
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2018/12/139-centos-nfs-quick-install/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CentOS: Setup Samba as an AD Domain Member</title>
		<link>https://blog.andreev.it/2016/09/95-centos-setup-samba-as-an-ad-domain-member/</link>
					<comments>https://blog.andreev.it/2016/09/95-centos-setup-samba-as-an-ad-domain-member/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Tue, 06 Sep 2016 21:33:01 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[AD]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[Samba]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2720</guid>

					<description><![CDATA[This post is a slight modification of the official wiki for setting up Samba&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>This post is a slight modification of the <a href="https://wiki.samba.org/index.php/Setup_Samba_as_an_AD_Domain_Member" target="_blank" rel="noopener noreferrer">official wiki</a> for setting up Samba as an AD Domain Member. </p>
<p>In my lab, I built a Windows 2012R2 domain controller/DNS and a CentOS 7.1 VM running Samba 4.2.10.<br />
My Windows domain is <strong>kdomain.local</strong> and the NETBIOS name is <strong>MYDOMAIN</strong>. They are on the same subnet and the IP of the CentOS VM is in the DNS. Let&#8217;s verify the prerequisites before we install Samba. Make sure that everything checks out. </p>
<p>Check the hostname first.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
hostname
centos7dd.kdomain.local
</pre>
<p>If you need to change the hostname, use <strong>hostnamectl set-hostname your_hostname</strong><br />
Make sure your resolver points to a valid domain controller. </p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
cat /etc/resolv.conf
search kdomain.local
nameserver 192.168.1.19
</pre>
<p>Check your IP.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ip addr show | grep inet
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
    inet 192.168.1.6/24 brd 192.168.1.255 scope global eno16777736
</pre>
<p>Check the resolving. <strong>dc03 </strong>is my domain controller, <strong>centos7dd </strong>is my CentOS member server, the one that I am configuring.</p>
<pre class="brush: bash; title: ; notranslate">
host -t A dc03.kdomain.local
dc03.kdomain.local has address 192.168.1.19
host -t A centos7dd.kdomain.local
centos7dd.kdomain.local has address 192.168.1.6
</pre>
<p>If you get an error that host is an unknown command, install bind-utils with <strong>yum install bind-utils</strong>. You don&#8217;t have to, but make sure that all IPs and resolving works fine.<br />
Some more checks, to see if you don&#8217;t have something messed up in <strong>/etc/hosts</strong> file.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
getent hosts centos7dd
192.168.1.6     centos7dd.kdomain.local
</pre>
<p>Now it&#8217;s time to install samba.</p>
<pre class="brush: bash; title: ; notranslate">
yum install samba samba-devel samba-winbind samba-winbind-clients
</pre>
<p>Before you go further, you need to know what&#8217;s realm, NETBIOS and workgroup in Samba terms. They are kind of misleading as you can see below from the samba config file. On the domain controller, open up a command prompt and type:</p>
<pre class="brush: plain; highlight: [1]; title: ; notranslate">
set | find  &quot;DOMAIN&quot;
USERDNSDOMAIN=KDOMAIN.LOCAL
USERDOMAIN=MYDOMAIN
USERDOMAIN_ROAMINGPROFILE=MYDOMAIN
</pre>
<p>My domain is <strong>KDOMAIN.LOCAL</strong> and the NETBIOS domain name is <strong>MYDOMAIN</strong>. The hostname of my domain controller is <strong>DC03</strong>, but that&#8217;s irrelevant.<br />
Find where the config file is stored.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
smbd -b | grep CONFIGFILE
   CONFIGFILE: /etc/samba/smb.conf
</pre>
<p>Rename the original file as something else and edit <strong>smb.conf</strong> so it&#8217;s an empty file. Add the following lines there.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;global]
        netbios name = centos7dd
        realm = KDOMAIN.LOCAL
        workgroup = MYDOMAIN
        security = ADS
        winbind enum groups = Yes
        winbind enum users = Yes
        winbind nss info = rfc2307
        idmap config *:range = 2000-9999
        idmap config * : backend = tdb
</pre>
<p>Now, you can join the VM to the domain.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
net ads join -U administrator
Enter administrator's password:
Using short domain name -- MYDOMAIN
Joined 'CENTOS7DD' to dns domain 'kdomain.local'
</pre>
<p>Let&#8217;s make sure that Samba starts now and on each boot.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl start smb.service
systemctl start nmb.service
systemctl start winbind.service
systemctl enable smb.service
systemctl enable nmb.service
systemctl enable winbind.service
</pre>
<p>Make sure you get the domain users and groups back.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
wbinfo -u
MYDOMAIN\administrator
MYDOMAIN\guest
MYDOMAIN\klimenta
MYDOMAIN\krbtgt
</pre>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
wbinfo -g
MYDOMAIN\winrmremotewmiusers__
MYDOMAIN\domain computers
MYDOMAIN\domain controllers
MYDOMAIN\schema admins
MYDOMAIN\enterprise admins
....
</pre>
<p>Now, edit <strong>/etc/nsswitch.conf</strong> and modify these three lines. Just add <strong>winbind </strong>after <strong>sss </strong>for <strong>passwd </strong>, <strong>shadow </strong>and <strong>group </strong>entries, so it looks like this. Don&#8217;t change the lines where it says <strong>#passwd:    db files nisplus nis</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
passwd:     files sss winbind
shadow:     files sss winbind
group:      files sss winbind
</pre>
<p>Now, do <strong>getent passwd</strong> and <strong>getent group</strong>. You should recieve both local and domain users and groups as output.</p>
<p>Finally, if you have a firewall, add an exception for Samba services.</p>
<pre class="brush: bash; title: ; notranslate">
firewall-cmd --permanent --zone=public --add-service=samba
firewall-cmd --reload
</pre>
<p>At this point, you&#8217;ll have the OS fully configured as a domain member, but you still can&#8217;t log in to CentOS with a domain account. In order to do that, we&#8217;ll have to run <strong>authconfig-tui</strong>. NOTE: For CentOS 8 use <code>authselect select winbind --force</code>.</p>
<pre class="brush: bash; title: ; notranslate">
authconfig-tui
</pre>
<p>Make sure these options are set. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P074-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P074-01.png" alt="" width="583" height="390" class="aligncenter size-full wp-image-7562" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P074-01.png 583w, https://blog.andreev.it/wp-content/uploads/2016/09/P074-01-300x201.png 300w, https://blog.andreev.it/wp-content/uploads/2016/09/P074-01-263x175.png 263w" sizes="(max-width: 583px) 100vw, 583px" /></a><br />
&#8230;and these. You don&#8217;t have to join to the domain, just select OK. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P074-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P074-02.png" alt="" width="530" height="357" class="aligncenter size-full wp-image-7563" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P074-02.png 530w, https://blog.andreev.it/wp-content/uploads/2016/09/P074-02-300x202.png 300w" sizes="(max-width: 530px) 100vw, 530px" /></a><br />
This utility will change a lot of files, especially those in <strong>/etc/pam.d </strong>directory and it will also change <strong>smb.conf</strong>. Restart the winbind service in order for these changes to take effect.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart winbind.service
</pre>
<p>Make sure you have these lines in <strong>smb.conf</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
template shell = /bin/sh
template homedir = /home/%D/%U
</pre>
<p>Reload Samba config.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl reload smb.service
</pre>
<p>Because of the <strong>template homedir</strong> directive above, all home directories for the domain users will be under <strong>/home/MYDOMAIN</strong> (or whatever domain you have).<br />
Finally, create the home dir and log as the user.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir -p /home/MYDOMAIN/klimenta
cd /home/MYDOMAIN
chown -R klimenta@kdomain.local klimenta
</pre>
<p>Now, you can log as the domain user.</p>
<pre class="brush: bash; highlight: [1,2]; title: ; notranslate">
login as: klimenta@kdomain.local
klimenta@kdomain.local@192.168.1.6's password:
Last login: Wed Sep  7 11:08:10 2016 from 192.168.1.101
-bash-4.2$ pwd
/home/MYDOMAIN/klimenta
</pre>
<p>What if we want to share our home or some other folder on the CentOS server? We have to add a config change in smb.conf file. I&#8217;ll explain how to share the home folder. If you want to share some other folder, make sure that the domain user has rights to that folder. In my case, I&#8217;ll have the domain user klimenta access the shared home folder for the domain user klimenta on the CentOS server. The permissions are already in place. Edit <strong>/etc/samba/smb.conf</strong> file and add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;share]
        comment = klimenta domain user share
        path =  /home/MYDOMAIN/klimenta
        valid users = klimenta@kdomain.local
        guest ok = no
        writable = yes
        browsable = yes
</pre>
<p>Restart both services</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart smb.service
systemctl restart nmb.service
</pre>
<p>Now, from a Windows workstation go to \\<centos_ip> and you&#8217;ll see the folder opened with all the files in there.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/09/95-centos-setup-samba-as-an-ad-domain-member/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>AWS: Elastic File System (EFS) on FreeBSD/RHEL/CentOS/AWS Linux</title>
		<link>https://blog.andreev.it/2016/09/94-amazon-aws-elastic-file-system-efs-on-freebsdrhelcentosaws-linux/</link>
					<comments>https://blog.andreev.it/2016/09/94-amazon-aws-elastic-file-system-efs-on-freebsdrhelcentosaws-linux/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Thu, 01 Sep 2016 19:11:26 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[EFS]]></category>
		<category><![CDATA[freebsd]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2688</guid>

					<description><![CDATA[Recently I was playing with the new Elastic File System (EFS) that AWS provides.&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>Recently I was playing with the new Elastic File System (EFS) that AWS provides. It&#8217;s an NFS v4  implementation and my goal was to use it as a shared repository between two different systems. The access is based on security groups and by default when you create a new file system, the mount targets are created in all availability zones for that region.</p>
<h1>Create NFS security group</h1>
<p>NFS access is based on security groups. So, if you have an instance that needs access to an NFS target, you have to make sure that the instance belongs to the same security group that NFS target belongs. We&#8217;ll create a security group that grants access to TCP port 2049. This is the port that NFS uses.<br />
Go to the main AWS menu, click on <strong>VPC</strong>, then <strong>Security Groups</strong> and click on <strong>Create Security Group</strong>.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-01.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-01.jpg" alt="" width="653" height="265" class="aligncenter size-full wp-image-7550" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-01.jpg 653w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-01-300x122.jpg 300w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-01-585x237.jpg 585w" sizes="(max-width: 653px) 100vw, 653px" /></a><br />
Once created, click on the <strong>Inbound Rules</strong> tab and then click <strong>Edit</strong>.<br />
From the first drop down box on the left choose <strong>NFS (2049)</strong>, for the source choose the same <strong>Group ID</strong> as the group itself and click <strong>Save</strong>. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-02.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-02.jpg" alt="" width="704" height="230" class="aligncenter size-full wp-image-7551" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-02.jpg 704w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-02-300x98.jpg 300w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-02-585x191.jpg 585w" sizes="(max-width: 704px) 100vw, 704px" /></a></p>
<h1>Create EFS</h1>
<p>From the main AWS menu, click on <strong>Elastic File System</strong>.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-03.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-03.jpg" alt="" width="586" height="511" class="aligncenter size-full wp-image-7552" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-03.jpg 586w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-03-300x262.jpg 300w" sizes="(max-width: 586px) 100vw, 586px" /></a><br />
Then, click on <strong>Create file system</strong>. This is how my default looks like.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-04.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-04.jpg" alt="" width="932" height="652" class="aligncenter size-full wp-image-7553" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-04.jpg 932w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-04-300x210.jpg 300w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-04-768x537.jpg 768w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-04-585x409.jpg 585w" sizes="(max-width: 932px) 100vw, 932px" /></a><br />
At this point, you can change the availability zone for the mount target. If you plan to launch instances in different zones, then go with the defaults. Remove the default security group on the right and add the security group that we just created for all of the zones, so the right part looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-05.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-05.jpg" alt="" width="289" height="458" class="aligncenter size-full wp-image-7554" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-05.jpg 289w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-05-189x300.jpg 189w" sizes="(max-width: 289px) 100vw, 289px" /></a></p>
<p>Click on <strong>Next Step</strong> and fill out the optional settings for the tags and the performance. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-06.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-06.jpg" alt="" width="934" height="568" class="aligncenter size-full wp-image-7555" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-06.jpg 934w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-06-300x182.jpg 300w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-06-768x467.jpg 768w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-06-585x356.jpg 585w" sizes="(max-width: 934px) 100vw, 934px" /></a><br />
Click on <strong>Next Step</strong> again, review and click <strong>Create File System</strong>.<br />
This is what you will have once you create your file system.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-07.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-07.jpg" alt="" width="1069" height="340" class="aligncenter size-full wp-image-7556" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-07.jpg 1069w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-07-300x95.jpg 300w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-07-1024x326.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-07-768x244.jpg 768w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-07-585x186.jpg 585w" sizes="(max-width: 1069px) 100vw, 1069px" /></a><br />
If you click on <strong>DNS names</strong>, you&#8217;ll see your server names (for the mount target).</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-08.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-08.jpg" alt="" width="639" height="510" class="aligncenter size-full wp-image-7557" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-08.jpg 639w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-08-300x239.jpg 300w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-08-585x467.jpg 585w" sizes="(max-width: 639px) 100vw, 639px" /></a><br />
And that&#8217;s all what we need.  If you click on <strong>EC2 mount instruction</strong>, you&#8217;ll get a quick guide on how to mount your new file system.</p>
<h1>FreeBSD</h1>
<p>For FreeBSD, we&#8217;ll have to put this one line in <strong>/etc/rc.conf</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
nfs_client_enable=&quot;YES&quot;
</pre>
<p>and then start the nfs client with</p>
<pre class="brush: bash; title: ; notranslate">
service nfsclient start
</pre>
<p>In order to mount the NFS target, we&#8217;ll need to know what zone our instance belongs to. As you can remember from the above, each zone has a different DNS server name for the target. So, if you need your zone you can see that from the EC2 menu or if you have <strong>curl </strong>installed, you can browse your instance metadata.</p>
<pre class="brush: bash; title: ; notranslate">
curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone/
</pre>
<p>Install curl with <strong>pkg install curl</strong> if you don&#8217;t have it.<br />
We also need a mount point. In my case I&#8217;ll mount my new file system under <strong>/root/efs</strong>. I don&#8217;t have the directory created, so I&#8217;ll do.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /root/efs
</pre>
<p>The easiest way to mount the target without looking at the zone where the instance belongs is to run this one liner.</p>
<pre class="brush: bash; title: ; notranslate">
mount -t nfs -o nfsv4 `curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone`.fs-0b864a42.efs.us-east-1.amazonaws.com:/ /root/efs
</pre>
<p>This means mount a new file system of type NFS, make sure it&#8217;s NFSv4 (-o), get the zone with curl and append it to the DNS server name of the NFS server and mount it under <strong>/root/efs</strong>.<br />
If you want to unmount the filesystem, do</p>
<pre class="brush: bash; title: ; notranslate">
umount /root/efs
</pre>
<p>For some reason, under FreeBSD I was getting RPC time out errors, so if you want to remove the mount instantly, force it.</p>
<pre class="brush: bash; title: ; notranslate">
umount -f /root/efs
</pre>
<p>Now, if you reboot your server the mount points are gone, so you&#8217;ll have to make sure that on each reboot your NFS mounts on. Edit <strong>/etc/fstab</strong> and add this line. </p>
<pre class="brush: bash; title: ; notranslate">
us-east-1d.fs-0b864a42.efs.us-east-1.amazonaws.com:/ /root/efs nfs rw,nfsv4 0 0
</pre>
<p>What if you have an image in a load balancing scenario and you have it configured to boot up in a random zone. The above <strong>/etc/fstab</strong> entry won&#8217;t work and you can&#8217;t query that with curl in <strong>fstab</strong>. It&#8217;s a text file, not an executable script. The solution is to put this little script in your image AMI under <strong>User Data</strong>. Any time an image launches, this will be executed once on the first boot. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-09.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-09.jpg" alt="" width="438" height="239" class="aligncenter size-full wp-image-7558" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-09.jpg 438w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-09-300x164.jpg 300w" sizes="(max-width: 438px) 100vw, 438px" /></a></p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh
echo &quot;`curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone`.fs-0b864a42.efs.us-east-1.amazonaws.com:/ /root/efs nfs rw,nfsv4 0 0&quot; &gt;&gt; /etc/fstab
mount -a
</pre>
<h1>RHEL/CentOS</h1>
<p>Red Hat and CentOS don&#8217;t come up with NFS client installed, so you&#8217;ll have to install it first.</p>
<pre class="brush: bash; title: ; notranslate">
yum install nfs-utils
</pre>
<p>In order to mount the NFS target for Red Hat and CentOS servers, we&#8217;ll need to know what zone our instance belongs to. As you can remember from the above, each zone has a different DNS server name for the target. So, if you need your zone you can see that from the EC2 menu or with <strong>curl </strong> you can browse your instance metadata.</p>
<pre class="brush: bash; title: ; notranslate">
curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone/
</pre>
<p>We also need a mount point. In my case I&#8217;ll mount my new file system under <strong>/root/efs</strong>. I don&#8217;t have the directory created, so I&#8217;ll do.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /root/efs
</pre>
<p>The easiest way to mount the target without looking at the zone where the instance belongs is to run this one liner.</p>
<pre class="brush: bash; title: ; notranslate">
mount -t nfs4 -o nfsvers=4.1 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).fs-0b864a42.efs.us-east-1.amazonaws.com:/ /root/efs
</pre>
<p>This means mount a new file system of type NFS, make sure it&#8217;s NFSv4 (-o), get the zone with curl and append it to the DNS server name of the NFS server and mount it under /root/efs.<br />
If you want to unmount the filesystem, do</p>
<pre class="brush: bash; title: ; notranslate">
umount /root/efs
</pre>
<p>Now, if you reboot your server, the mount points are gone, so you&#8217;ll have to make sure that on each reboot, your NFS mounts on. Edit <strong>/etc/fstab</strong> and add this line. </p>
<pre class="brush: bash; title: ; notranslate">
us-east-1d.fs-0b864a42.efs.us-east-1.amazonaws.com:/ /root/efs nfs defaults,vers=4.1 0 0
</pre>
<p>What if you have an image in a load balancing scenario and you have it configured to boot up in a random zone. The above <strong>/etc/fstab</strong> entry won&#8217;t work and you can&#8217;t query that with curl in <strong>fstab</strong>. It&#8217;s a text file, not an executable script. The solution is to put this little script in your image AMI under <strong>User Data</strong>. Anytime an image launches, this will be executed once on the first boot. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/09/P073-10.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/09/P073-10.jpg" alt="" width="438" height="239" class="aligncenter size-full wp-image-7559" srcset="https://blog.andreev.it/wp-content/uploads/2016/09/P073-10.jpg 438w, https://blog.andreev.it/wp-content/uploads/2016/09/P073-10-300x164.jpg 300w" sizes="(max-width: 438px) 100vw, 438px" /></a></p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash
echo &quot;`$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).fs-0b864a42.efs.us-east-1.amazonaws.com:/ /root/efs nfs defaults,vers=4.1 0 0&quot; &gt;&gt; /etc/fstab
mount -a
</pre>
<h1>AWS Linux</h1>
<p>See above for Red Hat and CentOS and just skip the part to install the nfs client. AWS Linux comes up with these utils preinstalled.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/09/94-amazon-aws-elastic-file-system-efs-on-freebsdrhelcentosaws-linux/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Linux: Corrupt AWS Linux AMI</title>
		<link>https://blog.andreev.it/2016/07/92-linux-corrupt-aws-linux-ami/</link>
					<comments>https://blog.andreev.it/2016/07/92-linux-corrupt-aws-linux-ami/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 31 Jul 2016 12:48:29 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[AWS Linux]]></category>
		<category><![CDATA[corrupt AMI]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2650</guid>

					<description><![CDATA[Recently, when I tried to ssh to my AWS Linux AMI, I got an&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>Recently, when I tried to <strong>ssh </strong>to my AWS Linux AMI, I got an error that the key is not valid. First, I thought that somehow my private key was stolen, but upon further investigation in the logs, I found these errors. </p>
<pre class="brush: plain; gutter: false; title: ; notranslate">
/ containts a file system with errors, check forced
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-01.png" alt="" width="874" height="552" class="aligncenter size-full wp-image-7532" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-01.png 874w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-01-300x189.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-01-768x485.png 768w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-01-585x369.png 585w" sizes="(max-width: 874px) 100vw, 874px" /></a></p>
<div style="border:1px solid red; padding:16px;">
<p style="text-align:center;"><strong><span style="color:#800000;">NOTE: At the end I wasn’t able to recover my instance and I have to restore it from the backups, but the steps outlined below might help you.</span> </strong></p>
</div>
<p>The AMI will try to <strong>fsck </strong>automatically. Most of the time, this will fix your problems. In my case it failed and I got a useless AMI that won&#8217;t boot. If <strong>fsck </strong>doesn’t work, check the console. I saw that one of the checks failed. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-02.png" alt="" width="1537" height="534" class="aligncenter size-full wp-image-7533" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-02.png 1537w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-02-300x104.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-02-1024x356.png 1024w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-02-768x267.png 768w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-02-1170x406.png 1170w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-02-585x203.png 585w" sizes="(max-width: 1537px) 100vw, 1537px" /></a><br />
According to AWS and this troubleshooting <a href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/TroubleshootingInstances.html" target="_blank" rel="noopener noreferrer">AWS Troubleshooting</a>, first stop the instance.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-03.png" alt="" width="1014" height="497" class="aligncenter size-full wp-image-7534" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-03.png 1014w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-03-300x147.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-03-768x376.png 768w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-03-585x287.png 585w" sizes="(max-width: 1014px) 100vw, 1014px" /></a><br />
Go to <strong>Volumes</strong>, <strong>Detach volume</strong> and wait until it says available.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-04.png" alt="" width="1626" height="229" class="aligncenter size-full wp-image-7535" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-04.png 1626w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-04-300x42.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-04-1024x144.png 1024w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-04-768x108.png 768w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-04-1536x216.png 1536w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-04-1170x165.png 1170w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-04-585x82.png 585w" sizes="(max-width: 1626px) 100vw, 1626px" /></a><br />
Create a new instance, same AMI type, same resources. Right click the newly created AMI, choose to <strong>Attach volume</strong> and select the instance where this volume will be attached.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-05.png" alt="" width="1366" height="447" class="aligncenter size-full wp-image-7536" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-05.png 1366w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-05-300x98.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-05-1024x335.png 1024w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-05-768x251.png 768w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-05-1170x383.png 1170w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-05-585x191.png 585w" sizes="(max-width: 1366px) 100vw, 1366px" /></a><br />
Once attached, in the new AMI do <strong>fdisk -l</strong> to see the device name for your attached disk. In my case I see <strong>/dev/xvdf</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-06.png" alt="" width="724" height="233" class="aligncenter size-full wp-image-7537" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-06.png 724w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-06-300x97.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-06-585x188.png 585w" sizes="(max-width: 724px) 100vw, 724px" /></a><br />
Try to repair it from here. In my case I got the following errors. </p>
<div style="border:1px solid red; padding:16px;">
<p style="text-align:center;"><strong><span style="color:#800000;">NOTE: The highlighted is what you type, the rest is the output.</span> </strong></p>
</div>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
fsck.ext4 -v /dev/xvdf
e2fsck 1.42.12 (29-Aug-2014)
ext2fs_open2: Bad magic number in super-block
fsck.ext4: Superblock invalid, trying backup blocks...
fsck.ext4: Bad magic number in super-block while trying to open /dev/xvdf

The superblock could not be read or does not describe a valid ext2/ext3/ext4
filesystem.  If the device is valid and it really contains an ext2/ext3/ext4
filesystem (and not swap or ufs or something else), then the superblock
is corrupt, and you might try running e2fsck with an alternate superblock:
    e2fsck -b 8193 &lt;device&gt;
 or
    e2fsck -b 32768 &lt;device&gt;
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-07.png" alt="" width="741" height="303" class="aligncenter size-full wp-image-7538" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-07.png 741w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-07-300x123.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-07-585x239.png 585w" sizes="(max-width: 741px) 100vw, 741px" /></a><br />
We have to find the superblocks that are corrupt. Now, let’s see where my superblocks are kept.</p>
<pre class="brush: bash; highlight: [1,4]; title: ; notranslate">
mke2fs -n /dev/xvdf
mke2fs 1.42.12 (29-Aug-2014)
Found a gpt partition table in /dev/xvdf
Proceed anyway? (y,n) y
Creating filesystem with 2097152 4k blocks and 524288 inodes
Filesystem UUID: 350b4d59-28c8-422f-a3af-ede9daae43e3
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
</pre>
<p><strong>NOTE: You’ll get different numbers. Use yours not mine.</strong> </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-08.png" alt="" width="711" height="237" class="aligncenter size-full wp-image-7539" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-08.png 711w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-08-300x100.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-08-585x195.png 585w" sizes="(max-width: 711px) 100vw, 711px" /></a><br />
Next step is to try to restore the superblocks.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
e2fsck -b 1605632 /dev/xvdf
e2fsck 1.42.12 (29-Aug-2014)
e2fsck: Invalid argument while trying to open /dev/xvdf

The superblock could not be read or does not describe a valid ext2/ext3/ext4
filesystem.  If the device is valid and it really contains an ext2/ext3/ext4
filesystem (and not swap or ufs or something else), then the superblock
is corrupt, and you might try running e2fsck with an alternate superblock:
    e2fsck -b 8193 &lt;device&gt;
 or
    e2fsck -b 32768 &lt;device&gt;
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-09.png" alt="" width="705" height="262" class="aligncenter size-full wp-image-7540" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-09.png 705w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-09-300x111.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-09-585x217.png 585w" sizes="(max-width: 705px) 100vw, 705px" /></a><br />
I tried all superblock numbers and all failed. Finally, I tried with the last resort.</p>
<pre class="brush: bash; highlight: [1,4]; title: ; notranslate">
mke2fs -S /dev/xvdf
mke2fs 1.42.12 (29-Aug-2014)
Found a gpt partition table in /dev/xvdf
Proceed anyway? (y,n) y
Creating filesystem with 2097152 4k blocks and 524288 inodes
Filesystem UUID: 97fc1ad1-b8dc-44ec-ba46-33061541cd60
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done
Writing superblocks and filesystem accounting information: done
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2016/07/P071-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2016/07/P071-10.png" alt="" width="696" height="242" class="aligncenter size-full wp-image-7541" srcset="https://blog.andreev.it/wp-content/uploads/2016/07/P071-10.png 696w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-10-300x104.png 300w, https://blog.andreev.it/wp-content/uploads/2016/07/P071-10-585x203.png 585w" sizes="(max-width: 696px) 100vw, 696px" /></a><br />
Force the checks on the filesystem.</p>
<pre class="brush: bash; title: ; notranslate">
e2fsck -f /dev/xvdf -y
/dev/xvdf: ***** FILE SYSTEM WAS MODIFIED *****
/dev/xvdf: 9001/524288 files (5.0% non-contiguous), 114693/2097152 blocks
</pre>
<p>At the end, mount the volume and see if you see your data. In my case, I got nothing.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ls -l
total 148
drwx------ 516 root root 147456 May 13 23:23 lost+found
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/07/92-linux-corrupt-aws-linux-ami/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>ESX/ESXi: Install VMware Tools on FreeBSD 10.x/11.x/CentOS 7.x</title>
		<link>https://blog.andreev.it/2015/11/vmware-workstation-install-vmware-tools-on-freebsd-10-x/</link>
					<comments>https://blog.andreev.it/2015/11/vmware-workstation-install-vmware-tools-on-freebsd-10-x/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Wed, 25 Nov 2015 18:03:58 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[ESX/ESXi]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[VMWare Tools]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2068</guid>

					<description><![CDATA[VMware Tools is a suite of utilities that enhances the performance of the virtual&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>VMware Tools is a suite of utilities that enhances the performance of the virtual machines guest operating system. Usually, it is a very simple install, especially on Windows OS. The port for FreeBSD is also easy, but there are some quirks that needs to be resolved. First, the instructions for the install assume that you have the cdrom already installed. Second, the tools depend on Perl and since 10.1, Perl was removed from the default install and /usr/bin. So, in order to install VMware Tools on FreeBSD 10.1 or 10.2, we have to do some work. For FreeBSD 11.x and higher, scroll all the way down.</p>
<h1>FreeBSD 10.x</h1>
<p>First, install the compatibility libraries.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install compat6x-amd64
</pre>
<p>If you have a 32-bit FreeBSD, use <strong>compat6x-i386 </strong>instead.<br />
Then, install perl from the packages.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install perl5-5.20.3_8
</pre>
<p>If there is a problem with this version, check what&#8217;s available and install the latest.</p>
<pre class="brush: bash; title: ; notranslate">
pkg search ^perl
</pre>
<p>Check the name of the cdrom drive.</p>
<pre class="brush: bash; title: ; notranslate">
dmesg | grep cd
</pre>
<p>In my case it was <strong>cd0</strong>. Most likely it&#8217;s <strong>cd0</strong>, unless you specified some SCSI cd when creating a custom VM.<br />
Right click the VM and choose Install VMware Tools.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2015/11/P058-01.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2015/11/P058-01.jpg" alt="" width="225" height="362" class="aligncenter size-full wp-image-7383" srcset="https://blog.andreev.it/wp-content/uploads/2015/11/P058-01.jpg 225w, https://blog.andreev.it/wp-content/uploads/2015/11/P058-01-186x300.jpg 186w" sizes="(max-width: 225px) 100vw, 225px" /></a><br />
Create a mount point, mount the tools, copy the tools on the disk and extract them.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /tmp/vt
mount -t cd9660 /dev/cd0 /tmp/vt
cd /tmp/vt
cp vmware-freebsd-tools.tar.gz ../
cd ..
umount /tmp/vt
rm -Rf /tmp/vt
tar xzvf vmware-freebsd-tools.tar.gz
rm vmware-freebsd-tools.tar.gz
cd vmware-tools-distrib
</pre>
<p>If you try to run the tools with <strong>./vmware-install.pl</strong>, you&#8217;ll get an error &#8220;command not found&#8221;. That&#8217;s because the provided script is looking for perl under <strong>/usr/bin</strong>. As of FreeBSD 10.1, perl is no longer a system binary and after the install, the binary is under <strong>/usr/local/bin</strong>.<br />
So, edit the following files and replace <strong>/usr/bin/perl </strong>with <strong>/usr/local/bin/perl </strong>in the following three files. It&#8217;s the first line in all three files.</p>
<pre class="brush: bash; title: ; notranslate">
vmware-install.pl
vmware-install.real.pl (if you have VMware Workstation 12)
bin/vmware-config-tools.pl
bin/vmware-uninstall-tools.pl
</pre>
<p>Once replaced, you can start the installation with:</p>
<pre class="brush: bash; title: ; notranslate">
./vmware-install.pl
</pre>
<p>Look at the choices, but most likely you&#8217;ll accept the defaults and then reboot.</p>
<h1>FreeBSD 11.x</h1>
<p>If you are using FreeBSD 11.x and higher you can install it with or without X11 support (nox11).</p>
<pre class="brush: bash; title: ; notranslate">
pkg install open-vm-tools
pkg install open-vm-tools-nox11
</pre>
<p>Once installed, add these lines in <strong>/etc/rc.conf</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
vmware_guest_vmblock_enable=&quot;YES&quot;
vmware_guest_vmhgfs_enable=&quot;NO&quot;
vmware_guest_vmmemctl_enable=&quot;YES&quot;
vmware_guest_vmxnet_enable=&quot;YES&quot;
vmware_guestd_enable=&quot;YES&quot;
</pre>
<p>Reboot after making changes in <strong>/etc/rc.conf</strong>.</p>
<h1>CentOS</h1>
<p>The installation for CentOS is much simpler. </p>
<pre class="brush: bash; title: ; notranslate">
yum install open-vm-tools
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2015/11/vmware-workstation-install-vmware-tools-on-freebsd-10-x/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
