<?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>freebsd &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/tag/freebsd/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Fri, 22 Nov 2024 16:36:12 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>FreeBSD: OpenVPN server in a LAN (local network) environment</title>
		<link>https://blog.andreev.it/2024/11/freebsd-openvpn-server-in-a-lan-local-network-environment/</link>
					<comments>https://blog.andreev.it/2024/11/freebsd-openvpn-server-in-a-lan-local-network-environment/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 22 Nov 2024 16:36:12 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[LAN]]></category>
		<category><![CDATA[OpenVPN]]></category>
		<category><![CDATA[pf]]></category>
		<category><![CDATA[VPN]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=10074</guid>

					<description><![CDATA[In this post I&#8217;ll describe a use case that I am currently using. I&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post I&#8217;ll describe a use case that I am currently using. I have a standard Internet connection that goes to my Eero mesh router and behind that I have a homelab on 192.168.1.0/24 network as shown in the diagram. I have a port forwarding configured on the router so I can access one of my Linux servers, but if I want to access other servers, I have to either port forward SSH on some other-than-22/tcp port or use the Linux server as a jump-box. None of this is good, so I decided to create an OpenVPN server. Anytime I VPN to this server I can ssh/rdp to any of the internal servers. The OpenVPN server requires one nic.<br />
<strong>NOTE</strong>: This post is very FreeBSD specific so if you want to use some Linux server as OpenVPN server, this guide won&#8217;t help you at all.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2024/11/P177-01.png"><img fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2024/11/P177-01.png" alt="" width="721" height="491" class="aligncenter size-full wp-image-10078" srcset="https://blog.andreev.it/wp-content/uploads/2024/11/P177-01.png 721w, https://blog.andreev.it/wp-content/uploads/2024/11/P177-01-300x204.png 300w, https://blog.andreev.it/wp-content/uploads/2024/11/P177-01-585x398.png 585w" sizes="(max-width: 721px) 100vw, 721px" /></a><br />
<strong>IMPORTANT</strong>: On your home router port-forward port 1194/udp to your OpenVPN server.</p>
<h1>OpenVPN server</h1>
<p>Let&#8217;s install OpenVPN server first.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install openvpn
</pre>
<p>Make sure it starts on boot and enable the NAT.</p>
<pre class="brush: bash; title: ; notranslate">
sysrc openvpn_enable=YES
sysrc gateway_enable=YES
</pre>
<p>Next, we need a directory where we&#8217;ll store our config files and the PKI.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /usr/local/etc/openvpn
cd /usr/local/etc/openvpn
</pre>
<p>Create the PKI structure.</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa init-pki
</pre>
<p>Go to the newly created <em>pki </em>directory and make a copy of the <em>vars.example</em> file.</p>
<pre class="brush: bash; title: ; notranslate">
cd pki
cp vars.example vars
</pre>
<p>Now edit this file and uncomment the following lines and change to match your needs. It&#8217;s optional and you can keep everything-as-is.</p>
<pre class="brush: bash; title: ; notranslate">
set_var EASYRSA_REQ_COUNTRY     &quot;US&quot;
set_var EASYRSA_REQ_PROVINCE    &quot;NJ&quot;
set_var EASYRSA_REQ_CITY        &quot;Allentown&quot;
set_var EASYRSA_REQ_ORG         &quot;iAndreev&quot;
set_var EASYRSA_REQ_EMAIL       &quot;mail@somemail.com&quot;
set_var EASYRSA_REQ_OU          &quot;iAndreev&quot;
set_var EASYRSA_CA_EXPIRE       3650
set_var EASYRSA_CERT_EXPIRE     825
</pre>
<p>Now create the Certificate Authority based on these values.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/openvpn
easyrsa build-ca
</pre>
<p>This command will prompt you to create a password that you will you to sign the certificates for the server and the clients.<br />
Then create the DH parameters. It might take 30+ seconds.</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa gen-dh
</pre>
<p>Create the server request and sign it.</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa build-server-full server nopass
</pre>
<p>You have to type <em>yes </em>to confirm and then use the password that you created above to sign the cert.<br />
The command will create some files under the <em>pki </em>directory and we&#8217;ll need those later.<br />
Next, we&#8217;ll create the same for the client. In my case it&#8217;s a Dell laptop, so I use the word dell, but you can use client, client1, something-whatever&#8230;</p>
<pre class="brush: bash; title: ; notranslate">
easyrsa build-client-full dell nopass
</pre>
<p>Same thing, answer <em>yes </em>and then use the password to sign the certs.<br />
Copy the OpenVPN config example file that comes with the package.</p>
<pre class="brush: bash; title: ; notranslate">
cp /usr/local/share/examples/openvpn/sample-config-files/server.conf /usr/local/etc/openvpn/openvpn.conf
</pre>
<p>Edit<em> openvpn.conf</em> and make sure these values are changed and match the certs you created earlier.</p>
<pre class="brush: bash; title: ; notranslate">
ca /usr/local/etc/openvpn/pki/ca.crt
cert /usr/local/etc/openvpn/pki/issued/server.crt
key /usr/local/etc/openvpn/pki/private/server.key

dh /usr/local/etc/openvpn/pki/dh.pem
</pre>
<p>In addition to that, find the line that says push route and create a new one that matches your internal subnet. In my case it looks like this.</p>
<pre class="brush: bash; title: ; notranslate">
push &quot;route 192.168.1.0 255.255.255.0&quot;
</pre>
<p>If you have internal DNS and you want to send that as well, uncomment the following line and change to match your DNS IP.</p>
<pre class="brush: bash; title: ; notranslate">
push &quot;dhcp-option DNS 208.67.222.222&quot;
</pre>
<p>Now, you can start the OpenVPN server. Make sure you check the syslog for any errors.</p>
<pre class="brush: bash; title: ; notranslate">
service openvpn start
tail /var/log/messages
</pre>
<h1>OpenVPN client</h1>
<p>On your laptop that you want to use as a VPN client, download the OpenVPN client from <a href="https://openvpn.net/community-downloads/" target="_blank">here</a>. When you install the client, you&#8217;ll have a generic config file under <em>C:\Program Files\OpenVPN\sample-config</em> folder. Copy that file under <em>c:\users\[your_username]\OpenVPN\config</em>.<br />
Then, edit the file and change the following lines.</p>
<pre class="brush: bash; title: ; notranslate">
remote public-ip-or-hostname-of-your-router 1194
ca ca.crt
cert dell.crt
key dell.key
</pre>
<p>NOTE: Make sure you copy <em>ca.crt</em> from <em>/usr/local/etc/openvpn/pki</em>, <em>dell.crt</em> or client.crt or whatever.crt from <em>/usr/local/etc/openvpn/pki/issued</em> and<em> dell.key</em> or client.key or whatever.key from <em>/usr/local/etc/openvpn/pki/private</em> directories to the same <em>c:\users\[your-user-name]\OpenVPN\config</em> folder. There should be 4 files there. The config file, the CA certificate, the client certificate and the private key for the client.<br />
Start the OpenVPN client and connect. You shouldn&#8217;t have any problems and you&#8217;ll get 10.8.0.2 IP assigned to your laptop. If you try to ping 10.8.0.1 you&#8217;ll get a response. Do route print and you&#8217;ll see that the routes for 192.168.1.0 are going over 10.8.0.1. But, if you try to ping some server internally, e.g. 192.168.1.21, you won&#8217;t get any response. That&#8217;s because that server doesn&#8217;t know the route back. You can easily add the route to each server but it&#8217;s not practical. Let&#8217;s make one more change to the server.</p>
<h1>OpenVPN server</h1>
<p>Add these two lines to <em>/etc/rc.conf</em>. That&#8217;s the FreeBSD pf firewall.</p>
<pre class="brush: bash; title: ; notranslate">
pf_enable=&quot;YES&quot;
pf_rules=&quot;/etc/pf.conf&quot;
</pre>
<p>Now, create this config file in <em>/etc/pf.conf</em>. Many thanks to <a href="https://gundersen.net/openvpn-server-on-freebsd-with-pf-firewall/" target="_blank">this </a>guy. </p>
<pre class="brush: bash; title: ; notranslate">
vpnclients = &quot;10.8.0.0/24&quot;
# The name of your NIC. I am using a VM on ESXi and vmx0 is my NIC.
wanint = &quot;vmx0&quot;
# put your tunnel interface here, it is usually tun0
vpnint = &quot;tun0&quot;
# OpenVPN by default runs on udp port 1194
udpopen = &quot;{1194}&quot;
# Open the SSH port.
tcpopen = &quot;{22}&quot;
icmptypes = &quot;{echoreq, unreach}&quot;

set skip on lo
# the essential line
nat on $wanint inet from $vpnclients to any -&gt; $wanint

block in
pass in on $wanint proto udp from any to $wanint port $udpopen
pass in on $wanint proto tcp from any to $wanint port $tcpopen
# the following two lines could be made stricter if you don&#039;t trust the clients
pass out quick
pass in on $vpnint from any to any
pass in inet proto icmp all icmp-type $icmptypes
</pre>
<p>Reboot the OpenVPN server and if you reconnect from the client, you can use the internal IPs directly to connect.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2024/11/freebsd-openvpn-server-in-a-lan-local-network-environment/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 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 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>FreeBSD, pfSense: Site-to-site VPN IPsec tunnel between FreeBSD and pfSense using strongswan</title>
		<link>https://blog.andreev.it/2020/08/freebsd-pfsense-site-to-site-vpn-ipsec-tunnel-between-freebsd-and-pfsense-using-strongswan/</link>
					<comments>https://blog.andreev.it/2020/08/freebsd-pfsense-site-to-site-vpn-ipsec-tunnel-between-freebsd-and-pfsense-using-strongswan/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 28 Aug 2020 20:49:59 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[pfSense]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[IPSec]]></category>
		<category><![CDATA[strongswan]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=6991</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 FreeBSD running strongswan and pfSense. The scenario described here works with FreeBSD, but it will work with any other Linux distribution with some small OS dependand changes. The syntax for strongswan is the same, it’s just the configuration file names and locations that are different across distributions. For CentOS, see my other <a href="https://blog.andreev.it/?p=4701" rel="noopener noreferrer" target="_blank">post</a>.</p>
<h1>Prerequisites</h1>
<p>Both the pfSense box and FreeBSD 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 firewall on FreeBSD. Both of pfSense and FreeBSD box need two network interfaces. In my case this is how it looks like.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-01.png" alt="" width="337" height="559" class="aligncenter size-full wp-image-6995" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-01.png 337w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-01-181x300.png 181w" sizes="(max-width: 337px) 100vw, 337px" /></a><br />
It&#8217;s much easier if you enter these values in a small spreadsheet so you don&#8217;t get confused later.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-02.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-02.jpg" alt="" width="716" height="198" class="aligncenter size-full wp-image-6996" /></a></p>
<h1>FreeBSD configuration</h1>
<p>First, we have to install strongswan, configure the 2nd internal NIC if it&#8217;s not configured and allow FreeBSD to act as a gateway for other servers behind it (e.g. servers srv1 and srv2).<br />
Install strongswan from packages.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install strongswan
</pre>
<p>Edit <strong>/etc/rc.conf</strong> and add this line, so strongswan starts on boot.</p>
<pre class="brush: bash; title: ; notranslate">
strongswan_enable=&quot;YES&quot;
</pre>
<p>While editing that file, add this line too.</p>
<pre class="brush: bash; title: ; notranslate">
gateway_enable=&quot;YES&quot;
</pre>
<p>&#8230;and if your internal NIC is not configured, you can assign the IP there too.</p>
<pre class="brush: bash; title: ; notranslate">
ifconfig_vtnet1=&quot;inet 10.39.96.3 netmask 255.255.240.0&quot;
</pre>
<p>where <strong>vtnet1 </strong>is the name of the NIC. You can see the name of your NIC by doing <strong>ifconfig -a</strong>.<br />
Next, we&#8217;ll configure strongswan. The config files are under <strong>/usr/local/etc.</strong> Edit <strong>ipsec.conf</strong> and delete everything then paste these lines. </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=140.82.31.124
        leftsubnet=10.39.96.0/20
        leftid=140.82.31.124
        leftfirewall=no
        right=67.81.194.50
        rightsubnet=192.168.1.0/24
        rightid=67.81.194.50
        ike=aes256-sha256-modp2048!
        esp=aes256-sha256!
        auto=start
        lifetime=1h
</pre>
<p>If you look at <strong>lines 13, 14</strong> and <strong>15 </strong>you&#8217;ll see that <strong>line 13</strong> is the external IP of our FreeBSD box, <strong>line 14</strong> is the internal subnet for FreeBSD and <strong>line 15</strong> is just a description for this connection. In my case I used the IP. The same applies for <strong>lines 17, 18</strong> and <strong>19</strong>. <strong>Line 17</strong> is the external IP of the pfSense, <strong>line 18 </strong>is the internal subnet for the resources behind pfSense and <strong>line 19</strong> is just an ID for this connection.<br />
<strong>NOTE:</strong> if you change the IDs, e.g. <strong>lines 15</strong> and <strong>19</strong>, then you have to change the same in the secrets file.<br />
The secrets file is a password that will be used to communicate between FreeBSD and pfSense. Another option is to use certificates and it&#8217;s not that difficult to reconfigure that, but that&#8217;s not in this scope. So, edit <strong>/usr/local/etc/ipsec.secrets</strong> and add this line.</p>
<pre class="brush: bash; title: ; notranslate">
140.82.31.124 67.81.194.50 : PSK &quot;supersecretpassword&quot;
</pre>
<p>Don&#8217;t use tabs. Spaces only or it won&#8217;t work. As you can see you are specifying the <strong>leftid</strong>, then the <strong>rightid </strong>and some password. <strong>PSK </strong>means <strong>pre-shared key</strong> or password. The parameter <strong>leftid </strong>and <strong>rightid </strong>in <strong>ipsec.conf</strong> must be the same with the parameters here. So, if I change the <strong>line 14</strong> to be <strong>leftid=@freebsd</strong>, I have to do the same in <strong>ipsec.secrets</strong>. I have to specify<strong> @freebsd</strong> instead of <strong>140.82.31.124</strong>. </p>
<h1>pfSense</h1>
<p>Now that the FreeBSD 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 section</strong>, so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-03.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-03.jpg" alt="" width="1166" height="442" class="aligncenter size-full wp-image-7007" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-03.jpg 1166w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-03-300x114.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-03-1024x388.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-03-768x291.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-03-585x222.jpg 585w" sizes="(max-width: 1166px) 100vw, 1166px" /></a><br />
As you can see, we use <strong>IKEv2 </strong>and our remote gateway is <strong>140.82.31.124</strong> which is the FreeBSD strongswan box.<br />
For <strong>Phase 1 Proposal (Authentication and Algorithms)</strong>, fill out the section so it looks like this. The <strong>Pre-Shared Key</strong> is what you put in <strong>/usr/local/etc/ipsec.secrets</strong> file, remember?<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-04.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-04.jpg" alt="" width="1164" height="274" class="aligncenter size-full wp-image-7010" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-04.jpg 1164w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-04-300x71.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-04-1024x241.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-04-768x181.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-04-585x138.jpg 585w" sizes="(max-width: 1164px) 100vw, 1164px" /></a><br />
Then for <strong>Phase 1 Proposal (Algorithms)</strong>, use these values. If you look at your <strong>ipsec.conf</strong>, you&#8217;ll see how they match.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-05.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-05.jpg" alt="" width="1165" height="280" class="aligncenter size-full wp-image-7021" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-05.jpg 1165w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-05-300x72.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-05-1024x246.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-05-768x185.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-05-585x141.jpg 585w" sizes="(max-width: 1165px) 100vw, 1165px" /></a><br />
&#8230;and use the defaults for the <strong>Advanced Options</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-06.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-06.jpg" alt="" width="1151" height="486" class="aligncenter size-full wp-image-7013" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-06.jpg 1151w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-06-300x127.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-06-1024x432.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-06-768x324.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-06-585x247.jpg 585w" sizes="(max-width: 1151px) 100vw, 1151px" /></a><br />
Once you click <strong>Save </strong>at the bottom, pfSense will bring you back. Just click <strong>Apply Changes</strong>.<br />
Do the phase 2 now, click on <strong>Show Phase 2 Entries</strong> and then click <strong>Add P2</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-07.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-07.jpg" alt="" width="1168" height="119" class="aligncenter size-full wp-image-7014" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-07.jpg 1168w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-07-300x31.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-07-1024x104.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-07-768x78.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-07-585x60.jpg 585w" sizes="(max-width: 1168px) 100vw, 1168px" /></a><br />
For the phase 2, enter the following information. Choose <strong>Network </strong>instead of <strong>LAN </strong>and add the subnets for both pfSense and FreeBSD. In my case it looks like this. Phase 2 is very important because you have to make sure you enter the proper values. One extra checkmark and you&#8217;ll be endlessly troubleshooting why it&#8217;s not working. So, pay attention please!<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-08.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-08.jpg" alt="" width="1158" height="430" class="aligncenter size-full wp-image-7015" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-08.jpg 1158w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-08-300x111.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-08-1024x380.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-08-768x285.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-08-585x217.jpg 585w" sizes="(max-width: 1158px) 100vw, 1158px" /></a><br />
For the <strong>Phase 2 Proposal (SA/Key Exchange)</strong> i have <strong>AES 256 bit</strong> instead of <strong>Auto </strong>and <strong>SHA256 </strong>instead of <strong>SHA1</strong>. <strong>Lifetime </strong>is also 3600.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-09.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-09.jpg" alt="" width="1165" height="632" class="aligncenter size-full wp-image-7016" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-09.jpg 1165w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-09-300x163.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-09-1024x556.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-09-768x417.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-09-585x317.jpg 585w" sizes="(max-width: 1165px) 100vw, 1165px" /></a><br />
And you can leave the <strong>Advanced Configuration</strong> as is. If you notice that your tunnel drops because there is 0 activity, you can enter the IP address of the FreeBSD box or an IP for a server that&#8217;s behind FreeBSD. This will send ping ICMP packets to the destination so it keeps the tunnel alive. It&#8217;s not necessary, but you never know. Click <strong>Save</strong> then <strong>Apply Changes</strong> again.<br />
By default, pfSense will block the IPsec traffic, so you have to enable it. 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/2020/08/P150-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-10.png" alt="" width="1156" height="429" class="aligncenter size-full wp-image-7017" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-10.png 1156w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-10-300x111.png 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-10-1024x380.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-10-768x285.png 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-10-585x217.png 585w" sizes="(max-width: 1156px) 100vw, 1156px" /></a><br />
…and this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-11.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-11.png" alt="" width="1157" height="442" class="aligncenter size-full wp-image-7018" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-11.png 1157w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-11-300x115.png 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-11-1024x391.png 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-11-768x293.png 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-11-585x223.png 585w" sizes="(max-width: 1157px) 100vw, 1157px" /></a><br />
Click <strong>Save </strong>and go back to the FreeBSD box. Reboot the FreeBSD.</p>
<h1>Site-to-site VPN tunnel</h1>
<p>Once FreeBSD comes back up, do:</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ipsec status
Security Associations (1 up, 0 connecting):
     net-net&#x5B;1]: ESTABLISHED 8 seconds ago, 140.82.31.124&#x5B;140.82.31.124]...67.81.194.50&#x5B;67.81.194.50]
     net-net{1}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: ca009d9e_i cc8a8b76_o
     net-net{1}:   10.39.96.0/20 === 192.168.1.0/24
</pre>
<p>&#8230;and if you go to pfSense, under <strong>Status | IPsec</strong> you can see the tunnel established.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2020/08/P150-12.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2020/08/P150-12.jpg" alt="" width="1138" height="229" class="aligncenter size-full wp-image-7023" srcset="https://blog.andreev.it/wp-content/uploads/2020/08/P150-12.jpg 1138w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-12-300x60.jpg 300w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-12-1024x206.jpg 1024w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-12-768x155.jpg 768w, https://blog.andreev.it/wp-content/uploads/2020/08/P150-12-585x118.jpg 585w" sizes="(max-width: 1138px) 100vw, 1138px" /></a><br />
If you try to ping the FreeBSD from a server behind your pfSense, you&#8217;ll get a response. But if you try to ping something behind pfSense from the FreeBSD box, it won&#8217;t work.<br />
Check the routes in FreeBSD. </p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
netstat -nr | grep 192
192.168.1.0/24     140.82.30.1        US       vtnet0
</pre>
<p>This is a wrong route that strongswan injected. Delete the route and add the proper one.</p>
<pre class="brush: bash; highlight: [1,3]; title: ; notranslate">
route delete 192.168.1.0
delete net 192.168.1.0
route add -net 192.168.1.0/24 10.39.96.3
add net 192.168.1.0: gateway 10.39.96.3
</pre>
<p>Now if you ping something, it will work. But wait! Once we reboot, everything will be messed up again? Correct!<br />
First, add this line in <strong>/etc/rc.conf</strong>. It creates a permanent static route.</p>
<pre class="brush: bash; title: ; notranslate">
route_vpn=&quot;-net 192.168.1.0/24 10.39.96.3&quot;
</pre>
<p>Second, prevent strongswan to mess up with the routes. Edit <strong>/usr/local/etc/strongswan.conf</strong> and above line <strong>load_modular = yes</strong>, add <strong>install_routes = no</strong>. It looks like this.</p>
<pre class="brush: bash; title: ; notranslate">
......
charon {
        install_routes = no
        load_modular = yes
        plugins {
                include strongswan.d/charon/*.conf
        }
}
......
</pre>
<p>After this change, restart strongswan.</p>
<pre class="brush: bash; title: ; notranslate">
service strongswan restart
</pre>
<p><strong>NOTE</strong>: For any resource behind FreeBSD, you have to add a static route for the 192.168.1.0/24 network. For example, for Windows type <strong>route add 192.168.1.0/24 10.39.96.3 -p</strong> otherwise that resource will use the default gateway. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2020/08/freebsd-pfsense-site-to-site-vpn-ipsec-tunnel-between-freebsd-and-pfsense-using-strongswan/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CentOS, FreeBSD: Secure SSH with fail2ban and blacklistd with MFA (Google Authenticator)</title>
		<link>https://blog.andreev.it/2020/03/centos-freebsd-secure-ssh-with-fail2ban-and-blacklistd-with-mfa-google-authenticator/</link>
					<comments>https://blog.andreev.it/2020/03/centos-freebsd-secure-ssh-with-fail2ban-and-blacklistd-with-mfa-google-authenticator/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 27 Mar 2020 18:57:52 +0000</pubDate>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[blacklistd]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[fail2ban]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[Google Authenticator]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MFA]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=6612</guid>

					<description><![CDATA[I have some servers that are exposed to the Internet on port 22 and&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I have some servers that are exposed to the Internet on port 22 and I see a lot of brute force attacks coming. The easiest and best way to protect is to block port 22 for everyone except a handful of IPs or safe subnets. But sometimes, these servers need to be available for some other people who work from who knows where, so you can&#8217;t just restrict IPs anymore. In this case, the best practice is to enforce MFA (multi factor authentication). But, this won&#8217;t work if you have some service accounts that need to log to the server. You can&#8217;t MFA a service account.To balance between security and availability, you can also install some tools that will block the repeated offenders, IPs that crawl the network and try to login to your network over SSH. In this post I&#8217;ll describe how to use fail2ban for CentOS and blacklistd for FreeBSD. fail2ban for FreeBSD is too complex to setup while blacklistd is a native tool and does the same job. </p>
<h1>CentOS</h1>
<p>I have a CentOS box with both <strong>SELinux </strong>and <strong>firewalld </strong>enabled. I am not using keys to log to the server, I have a generic user that uses password and the root is NOT allowed to log to the server using ssh (<strong>PermitRootLogin no in /etc/ssh/sshd_config</strong>).</p>
<h2>Log with SSH keys (optional)</h2>
<p>If you want to have some users that need to log with SSH keys, you have to do the following. Log as that user and run <strong>ssh-keygen</strong> and hit enter for the defaults.</p>
<pre class="brush: bash; highlight: [1,3,5,6]; title: ; notranslate">
ssh-keygen -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/test/.ssh/id_rsa):
Created directory '/home/test/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/test/.ssh/id_rsa.
Your public key has been saved in /home/test/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:CmYzEZq7u4IilphSEC/cdTFKQY2+fjQgkw8acCXZjIo test@localhost.localdomain
The key's randomart image is:
+---&#x5B;RSA 4096]----+
|  .*+++o.        |
|o ++++.o.        |
|+=+ =..          |
|Eo.B +           |
| o+ @ o S        |
| ..+ * +         |
|ooo . o .        |
|Oo . . .         |
|=.o.  .          |
+----&#x5B;SHA256]-----+
</pre>
<p>You have two files created for the <strong>test </strong>user, a private (<strong>id_rsa</strong>) and a public (<strong>id_rsa.pub</strong>) file.<br />
You need the private file in order to use it with putty. But putty uses it&#8217;s own PPK file, so you have to convert that with <a href="https://www.puttygen.com/convert-pem-to-ppk">puttygen</a>. You can use the Windows version or you can install putty and convert it. <strong>NOTE</strong>: putty is a GUI program so don&#8217;t install it on a server because it will install a bunch of GUI libraries.<br />
Install epel-release repo.</p>
<pre class="brush: bash; title: ; notranslate">
yum install -y epel-release
</pre>
<p>&#8230;and then install putty.</p>
<pre class="brush: bash; title: ; notranslate">
yum install -y putty
</pre>
<p>Log as the user and convert the file from PEM to PPK. </p>
<pre class="brush: bash; title: ; notranslate">
puttygen .ssh/id_rsa -o private.ppk -O private
</pre>
<p>Your key will be in the home directory as <strong>private.ppk</strong>. Use this key to log to your server. But, you have to authorize your public key first. Logged as test user do:</p>
<pre class="brush: bash; title: ; notranslate">
cat .ssh/id_rsa.pub &gt;&gt; .ssh/authorized_keys
chmod 0600 .ssh/authorized_keys
</pre>
<p>Now, you can log as test user with a key using putty. This will affect only the <strong>test </strong>user to log with a key. The other users will continue logging as they used to do before. Mind that at this point you can log as a test user using a key and the password. If you want to completely disable password logins make sure that these settings are configured under <strong>/etc/ssh/sshd_config</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
</pre>
<p>Restart sshd (<strong>systemctl restart sshd</strong>) anytime you make a change in that file.</p>
<h2>Google Authenticator</h2>
<p>In order to enable MFA, we&#8217;ll have to install Google Authenticator on the server and a client on a phone or a desktop. I use <a href="https://authy.com/" rel="noopener noreferrer" target="_blank">authy </a>for that. You can use any MFA client you want on your phone. I will also use key only logins and no passwords so go ahead and change those 3 lines above in <strong>sshd_config</strong>.  Also, make sure that you can login with at least one user that can sudo or you&#8217;ll be locked. The only way to get in will be thru the console which does not use ssh so it&#8217;s not affected.<br />
To install Google Authenticator, you need the epel repo. Skip this step if you already completed any of the previous steps.</p>
<pre class="brush: bash; title: ; notranslate">
yum install -y epel-release
</pre>
<p>Then install Google Authenticator.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install google-authenticator
</pre>
<p>Now, you can go two ways. Mandate that all accounts use MFA or only certain ones. It depends on your server usage case. If you have some automated scripts that use SSH to do some work, the first option is not viable. For each account that you want to use MFA, you have to configure the authenticator. I&#8217;ll use my <strong>test </strong>account. Logged as the test user, type <strong>google-authenticator</strong>. I answered <strong>y</strong> on all of the questions. </p>
<pre class="brush: bash; highlight: [1,2,15,19,30,35]; title: ; notranslate">
google-authenticator
Do you want authentication tokens to be time-based (y/n) y
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
  https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/test@localhost.l....
                                                                                
Your new secret key is: HF52123FWAGRKLGX5EJ4567CLE
Your verification code is 880933
Your emergency scratch codes are:
  94310385
  95472197
  98736692
  31351434
  83561212

Do you want me to update your &quot;/home/test/.google_authenticator&quot; file? (y/n) y

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

By default, a new token is generated every 30 seconds by the mobile app.
In order to compensate for possible time-skew between the client and the server,
we allow an extra token before and after the current time. This allows for a
time skew of up to 30 seconds between authentication server and client. If you
experience problems with poor time synchronization, you can increase the window
from its default size of 3 permitted codes (one previous code, the current
code, the next code) to 17 permitted codes (the 8 previous codes, the current
code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
between client and server.
Do you want to do so? (y/n) y

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting? (y/n) y
</pre>
<p>In a console session you&#8217;ll see a barcode but it&#8217;s garbled. Instead scroll up and you&#8217;ll see a URL (line 4). Go to that URL and scan the barcode with your MFA app.<br />
Open <strong>/etc/ssh/sshd_config</strong>, scroll all the way down and add this line as the last line.</p>
<pre class="brush: bash; title: ; notranslate">
AuthenticationMethods publickey,password publickey,keyboard-interactive
</pre>
<p>Then change this line to <strong>yes</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
ChallengeResponseAuthentication yes
</pre>
<p>Edit <strong>/etc/pam.d/sshd</strong> and after these two lines, add the <strong>auth </strong>line.</p>
<pre class="brush: bash; highlight: [3]; title: ; notranslate">
# Used with polkit to reauthorize users in remote sessions
-session   optional     pam_reauthorize.so prepare
auth required pam_google_authenticator.so nullok
</pre>
<p><strong>nullok </strong>means that you are allowing some accounts to log as usual, without MFA. If you remove <strong>nullok</strong>, all accounts will be required to use MFA.<br />
Also, comment this line like this.</p>
<pre class="brush: bash; title: ; notranslate">
#auth       substack     password-auth
</pre>
<p>Restart the <strong>sshd </strong>daemon now.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart sshd
</pre>
<p>At this point, you&#8217;ll be able to login only with a public key and an MFA for the users that have google-authenticator and a public key configured. The password users won&#8217;t be able to log in. The console logins are not affected. So, if you have some users without a public key and google-authneticator, they&#8217;ll still be able to login with a password from a console.</p>
<h2>fail2ban</h2>
<p>In order to install <a href="https://www.fail2ban.org/wiki/index.php/Main_Page" rel="noopener noreferrer" target="_blank">fail2ban </a>you have to install the <strong>epel-release</strong> first. Skip this step if you followed the previous step because you already installed epel repo.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install epel-release
</pre>
<p>Then install fail2ban.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install fail2ban
</pre>
<p>Make sure it starts on boot.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl enable fail2ban
</pre>
<p>The config files for fail2ban are under <strong>/etc/fail2ban</strong>, but you shouldn&#8217;t change any of the existing files. Instead create a new file called <strong>sshd.conf</strong> under <strong>/etc/fail2ban/jail.d</strong> directory. Here is mine.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;sshd]
enabled = true

# &quot;ignoreip&quot; can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
# will not ban a host which matches an address in this list. Several addresses
# can be defined using space (and/or comma) separator.
ignoreip = 127.0.0.1/8

# &quot;bantime&quot; is the number of seconds that a host is banned.
# add m for minutes or hr for hours
bantime  = 10m

# A host is banned if it has generated &quot;maxretry&quot; during the last &quot;findtime&quot;
# seconds.
findtime = 300

# &quot;maxretry&quot; is the number of failures before a host get banned.
maxretry = 3
</pre>
<p>It is very self explanatory with the included comments. In my example, I&#8217;ll ban an IP for 10 minutes if I see that IP try and fail 3 times to login in 300 seconds (5 mins). You can start/restart the service now.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl start fail2ban
</pre>
<p>The fail2ban log file is under <strong>/var/log/fail2ban.log</strong> and the SSH logs are under <strong>/var/log/secure</strong>.<br />
Most of the hits that you&#8217;ll see in the <strong>/var/log/secure</strong> are IPs that will try to log as admin or root, but only once in a hour or two. So, they won&#8217;t be caught with these settings. You should add all of your subnets under <strong>ignoreip </strong>setting and change the <strong>maxretry </strong>to 1 and <strong>bantime </strong>to 8760h (1 year). It will ultimately block the IP for a year for anyone that makes any unauthorized attempt. It&#8217;s up to you what settings you use.<br />
Here is an example in the <strong>/var/log/secure</strong> of an IP (3.92.82.165) trying to log as root.</p>
<pre class="brush: bash; title: ; notranslate">
Mar 21 10:26:13 localhost sshd&#x5B;13207]: pam_succeed_if(sshd:auth): requirement &quot;uid &gt;= 1000&quot; not met by user &quot;root&quot;
Mar 21 10:26:15 localhost sshd&#x5B;13207]: Failed password for root from 3.92.82.165 port 60362 ssh2
Mar 21 10:26:16 localhost unix_chkpwd&#x5B;13211]: password check failed for user (root)
Mar 21 10:26:16 localhost sshd&#x5B;13207]: pam_succeed_if(sshd:auth): requirement &quot;uid &gt;= 1000&quot; not met by user &quot;root&quot;
Mar 21 10:26:18 localhost sshd&#x5B;13207]: Failed password for root from 3.92.82.165 port 60362 ssh2
Mar 21 10:26:18 localhost sshd&#x5B;13207]: Connection closed by 3.92.82.165 port 60362 &#x5B;preauth]
Mar 21 10:26:18 localhost sshd&#x5B;13207]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=ec2-3-92-82-165.compute-1.amazonaws.com  user=root
</pre>
<p>&#8230;and the IP got banned. You can see that from /var/log/fail2ban.</p>
<pre class="brush: bash; title: ; notranslate">
2020-03-21 10:26:12,259 fail2ban.filter         &#x5B;13131]: INFO    &#x5B;sshd] Found 3.92.82.165 - 2020-03-21 10:26:12
2020-03-21 10:26:15,382 fail2ban.filter         &#x5B;13131]: INFO    &#x5B;sshd] Found 3.92.82.165 - 2020-03-21 10:26:15
2020-03-21 10:26:18,887 fail2ban.filter         &#x5B;13131]: INFO    &#x5B;sshd] Found 3.92.82.165 - 2020-03-21 10:26:18
2020-03-21 10:26:19,286 fail2ban.actions        &#x5B;13131]: NOTICE  &#x5B;sshd] Ban 3.92.82.165
</pre>
<p>You can also see the banned IPs using this command. <strong>sshd </strong>is the name of the jail. If you scroll up, you&#8217;ll see that I named my jail like that <strong>[sshd]</strong> in the conf file above.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed: 1
|  |- Total failed:     8
|  `- Journal matches:  _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
   |- Currently banned: 2
   |- Total banned:     2
   `- Banned IP list:   3.81.85.240 3.92.82.165
</pre>
<p>But mistakes happen. If someone gets banned, you can unban the IP with this command, where sshd is the jail name and the IP you want unbanned.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
fail2ban-client set sshd unbanip 3.92.82.165
1
</pre>
<p>You should get 1 as an output. Means OK, True. If you get 0, it means the IP wasn&#8217;t there. If you can&#8217;t see all banned IPs, do:</p>
<pre class="brush: bash; title: ; notranslate">
zgrep 'Ban' /var/log/fail2ban.log*
</pre>
<h1>FreeBSD</h1>
<p>I have a FreeBSD box with no firewall enabled for now. For the <strong>blacklistd </strong>part, I&#8217;ll use <strong>pf</strong>. If you use <strong>ipfirewall </strong>or <strong>ipfilter</strong>, then you have to find another guide. I am not using keys to log to the server, I have a generic user that uses password and the root is NOT allowed to log to the server using ssh (<strong>PermitRootLogin no</strong> in <strong>/etc/ssh/sshd_config</strong>).</p>
<h2>Log with SSH keys (optional)</h2>
<p>If you want to have some users that need to log with SSH keys, you have to do the following. Log as that user and run <strong>ssh-keygen</strong> and hit enter for the defaults.</p>
<pre class="brush: bash; highlight: [1,3,5]; title: ; notranslate">
ssh-keygen -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/test/.ssh/id_rsa):
Created directory '/home/test/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/test/.ssh/id_rsa.
Your public key has been saved in /home/test/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:rT2m3a/KrC/jk1lxHUPMwuXM5g/5LpjkurrC29EO1z8 test@bsd.andreev.local
The key's randomart image is:
+---&#x5B;RSA 4096]----+
|                 |
|                 |
|           .     |
|        ..o o    |
|     . =S..+     |
|.   . + B+.      |
|o. o + @+.+o     |
|..o * o.OE+o     |
| ..o.+o.+@@.oo.  |
+----&#x5B;SHA256]-----+
</pre>
<p>You have two files created for the test user, a private (<strong>id_rsa</strong>) and a public (<strong>id_rsa.pub</strong>) file.<br />
You need the private file in order to use it with putty. But putty uses it&#8217;s own PPK file, so you have to convert that with <a href="https://www.puttygen.com/convert-pem-to-ppk">puttygen</a>. You can use the Windows version or you can install putty and convert it. </p>
<pre class="brush: bash; title: ; notranslate">
pkg install putty-nogtk
</pre>
<p>Log as the user and convert the file from PEM to PPK. </p>
<pre class="brush: bash; title: ; notranslate">
puttygen .ssh/id_rsa -o private.ppk -O private
</pre>
<p>Your key will be in the home directory as <strong>private.ppk</strong>. Use this key to log to your server. But, you have to authorize your public key first. Logged as test user do:</p>
<pre class="brush: bash; title: ; notranslate">
cat .ssh/id_rsa.pub &gt;&gt; .ssh/authorized_keys
chmod 0600 .ssh/authorized_keys
</pre>
<p>Now, you can log as test user with a key using putty. This will affect only the <strong>test </strong>user to log with a key. The other users will continue logging as they used to do before. Mind that at this point you can log as a test user using a key and the password. If you want to completely disable password logins make sure that these settings are configured under <strong>/etc/ssh/sshd_config</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes
</pre>
<p>Restart sshd <strong>(service sshd restart)</strong>  anytime you make a change in that file.</p>
<h2>Google Authenticator</h2>
<p>In order to enable MFA, we&#8217;ll have to install Google Authenticator on the server and a client on a phone or a desktop. I use <a href="https://authy.com/" rel="noopener noreferrer" target="_blank">authy </a>for that. You can use any MFA client you want on your phone. I will also use key only logins and no passwords so go ahead and change those 3 lines above in <strong>sshd_config</strong>. Also, make sure that you can login with at least one user that can sudo or you’ll be locked. The only way to get in will be thru the console which does not use ssh so it’s not affected. To install Google Authenticator type:</p>
<pre class="brush: bash; title: ; notranslate">
pkg install pam_google_authenticator
</pre>
<p>Now, you can go two ways. Mandate that all accounts use MFA or only certain ones. It depends on your server usage case. If you have some automated scripts that use SSH to do some work, the first option is not viable. For each account that you want to use MFA, you have to configure the authenticator. I&#8217;ll use my <strong>test </strong>account. Logged as the test user, type <strong>google-authenticator</strong>. I answered <strong>y</strong> on all of the questions and <strong>-1</strong> to skip. </p>
<pre class="brush: bash; highlight: [1,2,6,15,19,30,35]; title: ; notranslate">
$ google-authenticator
Do you want authentication tokens to be time-based (y/n) y
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
  https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/test@bsd.andreev.local%3Fsecret%3D24345SOFKCTVX44YXYZVYOQKCA%26issuer%3Dbsd.andreev.local                                                                                                                                                         
Your new secret key is: 24HJ3SOFKCTVZ33YVBKVYOKEDB
Enter code from app (-1 to skip): -1
Code confirmation skipped
Your emergency scratch codes are:
  34344229
  32681543
  80840666
  32593123
  29994070

Do you want me to update your &quot;/home/test/.google_authenticator&quot; file? (y/n) y

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

By default, a new token is generated every 30 seconds by the mobile app.
In order to compensate for possible time-skew between the client and the server,
we allow an extra token before and after the current time. This allows for a
time skew of up to 30 seconds between authentication server and client. If you
experience problems with poor time synchronization, you can increase the window
from its default size of 3 permitted codes (one previous code, the current
code, the next code) to 17 permitted codes (the 8 previous codes, the current
code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
between client and server.
Do you want to do so? (y/n) y

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting? (y/n) y
</pre>
<p>In a console session you&#8217;ll see a barcode but it&#8217;s garbled. Instead scroll up and you&#8217;ll see a URL (line 4). Go to that URL and scan the barcode with your MFA app.<br />
Now, log as root or sudo to open <strong>/etc/ssh/sshd_config</strong> file. Change this line to <strong>yes</strong>. </p>
<pre class="brush: bash; title: ; notranslate">
ChallengeResponseAuthentication yes
</pre>
<p>Scroll all the way down and add this line as the last line.</p>
<pre class="brush: bash; title: ; notranslate">
AuthenticationMethods publickey,password publickey,keyboard-interactive
</pre>
<p>Edit <strong>/etc/pam.d/sshd</strong> and after these two lines, add the last <strong>auth </strong>line but commend the line above so it looks like this.</p>
<pre class="brush: bash; highlight: [3]; title: ; notranslate">
#auth           sufficient      pam_ssh.so              no_warn try_first_pass
#auth            required        pam_unix.so             no_warn try_first_pass
auth            required        pam_google_authenticator.so nullok
</pre>
<p><strong>nullok </strong>means that you are allowing some accounts to log as usual, without MFA. If you remove <strong>nullok</strong>, all accounts will be required to use MFA. Restart the <strong>sshd </strong>daemon now.</p>
<pre class="brush: bash; title: ; notranslate">
service sshd restart
</pre>
<p>At this point, you’ll be able to login only with a public key and an MFA for the users that have google-authenticator and a public key configured. The password users won’t be able to log in. The console logins are not affected. So, if you have some users without a public key and google-authneticator, they’ll still be able to login with a password from a console.<br />
If you don&#8217;t want to use public key and prefer passwords and MFA, then remove the last line from <strong>sshd_config AuthenticationMethod</strong>s and uncomment <strong>pam_unix.so</strong> in <strong>/etc/pam.d/sshd</strong> above <strong>google_authenticator</strong> line. Restart sshd.</p>
<h2>blacklistd</h2>
<p>fail2ban is available for FreeBSD, but it takes some time to configure it right with the proper firewalls. Instead, I use blacklistd which comes preinstalled. The only prerequisite is a firewall and I&#8217;ll be using pf for that. So, first let&#8217;s enable pf and blacklistd by adding these lines in <strong>/etc/rc.conf</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
pf_enable=&quot;YES&quot;
pflog_enable=&quot;YES&quot;
blacklistd_enable=&quot;YES&quot;
blacklistd_flags=&quot;-r&quot;
</pre>
<p>Let&#8217;s create a very simple pf config file <strong>/etc/pf.conf</strong>.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ext_if = &quot;vmx0&quot;
set skip on lo0
anchor &quot;blacklistd/*&quot; in on $ext_if
table &lt;blocked_subnets&gt; persist file &quot;/etc/blocked_subnets&quot;
block all
block in log quick on $ext_if from &lt;blocked_subnets&gt; to any
block out log quick on $ext_if from any to &lt;blocked_subnets&gt;
pass in on $ext_if proto tcp from any to any port {ssh} keep state
pass out quick on $ext_if keep state
</pre>
<p>Make sure you replace the name of your network card under line #1. You can get the name from <strong>ifconfig </strong>output. Also, if you want to block certain subnets by default, you can list them under <strong>/etc/blocked_subnets </strong>file. The subnet(s) should be in CIDR format. For example, if you want to block certain countries, you can look at this <a href="https://www.countryipblocks.net/acl.php" rel="noopener noreferrer" target="_blank">website</a>. BTW, the subnets blocking is part of pf not blacklistd. You can reboot now to make sure everything comes back OK and you are able to login. But before doing that, edit the <strong>sshd </strong>daemon and let it know that we&#8217;ll use <strong>blacklistd</strong>. Find <strong>UseBlacklist </strong>in <strong>/etc/ssh/sshd_conf</strong> and change it to:</p>
<pre class="brush: bash; title: ; notranslate">
UseBlacklist yes
</pre>
<p>The reboot will start pf and blacklistd. The blacklistd conf file is <strong>/etc/blacklistd.conf</strong>. You can read more about blacklistd <a href="https://www.freebsd.org/doc/handbook/firewalls-blacklistd.html" rel="noopener noreferrer" target="_blank">here</a>. For example, if I want to whitelist certain subnets from being blacklisted, I&#8217;ll add them under the <strong>[remote]</strong> section. In my case, I am whitelisting my home subnet and an external subnet.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;remote]
172.16.1.0/24:ssh      *       *       *               =       *       *
154.21.3.0/24:ssh      *       *       *               =       *       *
</pre>
<p>You can see your SSH activity in <strong>/var/log/auth.log.</strong> To see who is blocked, run:</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
blacklistctl dump -br
        address/ma:port id      nfail   remaining time
  213.74.176.36/32:22   OK      8/3     23h58m57s
</pre>
<p>This IP will be blocked for 24hrs by default. You can change that under the <strong>disable </strong>column in <strong>/etc/blacklistd.conf</strong>.<br />
You can also see the blocked IPs by looking at the pf <strong>blacklistd </strong>table.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
pfctl -a blacklistd/22 -t port22 -T show
   213.74.176.36
</pre>
<p>And if you want to remove an IP or a subnet do:</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
pfctl -a blacklistd/22 -t port22 -T delete 213.74.176.36/32
1/1 addresses deleted.
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2020/03/centos-freebsd-secure-ssh-with-fail2ban-and-blacklistd-with-mfa-google-authenticator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>FreeBSD, CentOS: Install Jenkins behind a nginx reverse proxy using SSL certificates</title>
		<link>https://blog.andreev.it/2019/07/freebsd-centos-install-jenkins-behind-a-nginx-reverse-proxy-using-ssl-certificates/</link>
					<comments>https://blog.andreev.it/2019/07/freebsd-centos-install-jenkins-behind-a-nginx-reverse-proxy-using-ssl-certificates/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sat, 20 Jul 2019 13:06:24 +0000</pubDate>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[install]]></category>
		<category><![CDATA[Jenkins]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=5482</guid>

					<description><![CDATA[In this post, I&#8217;ll explain how to install Jenkins on FreeBSD and CentOS. Jenkins&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post, I&#8217;ll explain how to install <strong>Jenkins </strong>on FreeBSD and CentOS. <strong>Jenkins </strong>runs on port 8080 (8180 in FreeBSD), so sometimes it&#8217;s not possible to access these ports because of corporate firewalls. We&#8217;ll put <strong>Jenkins </strong>behind <strong>nginx </strong>that will act as a reverse proxy. We&#8217;ll use port 80 (HTTP) and 443 (HTTPS) if you want to have SSL certificates. The installation is very simple.</p>
<h1>CentOS</h1>
<p>The <strong>Jenkins </strong>package is not part of the default CentOS repository, so we have to download that one first, install <strong>Jenkins</strong>, enable it to start on boot and then start it. You can skip the first line if you have <strong>wget </strong>installed. By default, it is not installed.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install wget
wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
yum -y install jenkins java
systemctl enable jenkins
systemctl start jenkins
</pre>
<p>If you have a firewall enabled, you have to open the port for 8080.</p>
<pre class="brush: plain; title: ; notranslate">
firewall-cmd --permanent --zone=public --add-port=8080/tcp
firewall-cmd --reload
</pre>
<p>Now, go to <strong>http://[ip]:8080</strong> and replace the <ip> with the IP of your server and you should see this greeting page.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/07/P134-01.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/07/P134-01.jpg" alt="" width="869" height="355" class="aligncenter size-full wp-image-8637" srcset="https://blog.andreev.it/wp-content/uploads/2019/07/P134-01.jpg 869w, https://blog.andreev.it/wp-content/uploads/2019/07/P134-01-300x123.jpg 300w, https://blog.andreev.it/wp-content/uploads/2019/07/P134-01-768x314.jpg 768w, https://blog.andreev.it/wp-content/uploads/2019/07/P134-01-585x239.jpg 585w" sizes="(max-width: 869px) 100vw, 869px" /></a><br />
Cat out that file, copy &#038; paste the value in the browser and click <strong>Continue</strong>.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
cat /var/lib/jenkins/secrets/initialAdminPassword
7f09cb85a4b843bdab66c768020a7c6e
</pre>
<p>And that&#8217;s it. Follow the prompts to install plugins, provide admin password etc&#8230;</p>
<h2>nginx as reverse proxy</h2>
<p>In order to access the server with out the need to specify the port 8080 and use a DNS name, we&#8217;ll have to use <strong>nginx </strong>that will listen on port 80 or 443 and redirect the traffic to 8080. Let&#8217;s install and configure it. In my case, I&#8217;ll access the server as <strong>jenkins.domain.com</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
yum -y install epel-release
yum -y install nginx
systemctl enable nginx
</pre>
<p>Edit <strong>/etc/nginx/nginx.conf</strong> and delete everything after this line around line 36. The <strong>include </strong>line should stay and the last line <strong>&#8220;}&#8221;</strong> should stay as well. So, the last lines should look like this.</p>
<pre class="brush: bash; title: ; notranslate">
       include /etc/nginx/conf.d/*.conf;
}
</pre>
<p>Go to <strong>/etc/nginx/conf.d</strong> folder and create a new file called <strong>jenkins.conf</strong>.<br />
This is how my <strong>jenkins.conf</strong> file looks like. Change the domain in the highlighted line.</p>
<pre class="brush: bash; highlight: [3]; title: ; notranslate">
server {
    listen 80;
    server_name jenkins.domain.com;

    location / {
        proxy_set_header   X-Forwarded-For $remote_addr;
        proxy_set_header   Host $http_host;
        proxy_pass         &quot;http://127.0.0.1:8080&quot;;
    }
}
</pre>
<p>Don&#8217;t forget to open port 80 in your firewall.</p>
<pre class="brush: plain; title: ; notranslate">
firewall-cmd --permanent --zone=public --add-port=80/tcp
firewall-cmd --reload
</pre>
<p>If you have SELinux, you&#8217;ll have to allow HTTP traffic.</p>
<pre class="brush: bash; title: ; notranslate">
setsebool -P httpd_can_network_connect 1
</pre>
<p>And restart nginx for changes to take effect.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart nginx
</pre>
<p>Now, you can access the server as <strong>jenkins.domain.com</strong>.<br />
For HTTPS traffic, the configuration is different. You&#8217;ll need certificates specified in lines 15 and 16 (under <strong>/etc/nginx</strong>) and the domain changed in 7,13 and 31. Here is the config (<strong>/etc/nginx/conf.d/jenkins.conf</strong>) in order to access jenkins over SSL. </p>
<pre class="brush: bash; highlight: [7,13,15,16,31]; title: ; notranslate">
upstream jenkins {
  server 127.0.0.1:8080 fail_timeout=0;
}

server {
  listen 80;
  server_name jenkins.domain.com;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  server_name jenkins.domain.com;

  ssl_certificate public_cert.pem;
  ssl_certificate_key private_cert.key;
  client_max_body_size 4M;

  location / {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;
    proxy_redirect http:// https://;
    proxy_pass              http://jenkins;
    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # workaround for https://issues.jenkins-ci.org/browse/JENKINS-45651
    add_header 'X-SSH-Endpoint' 'jenkins.domain.com:50022' always;
  }
}
</pre>
<p>Make sure you open port 443 on the firewall as we did for port 80 and change SELinux with <strong>setsebool</strong>. </p>
<pre class="brush: bash; title: ; notranslate">
firewall-cmd --permanent --zone=public --add-port=443/tcp
firewall-cmd --reload
</pre>
<p>SELinux change.</p>
<pre class="brush: bash; title: ; notranslate">
setsebool -P httpd_can_network_connect 1
</pre>
<p>You should also restart <strong>nginx </strong>for the changes to take effect.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart nginx
</pre>
<p>That&#8217;s it. You should be able to access <strong>Jenkins </strong>as <strong>jenkins.domain.com</strong> over https.</p>
<h1>FreeBSD</h1>
<p>The installation on FreeBSD is a little bit different. You can install <strong>Jenkins </strong>from the packages. It will install JDK as well.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install jenkins
</pre>
<p>The OpenJDK installation depends on these &#8220;memory filesystems&#8221;. Mount them now.</p>
<pre class="brush: bash; title: ; notranslate">
mount -t fdescfs fdesc /dev/fd
mount -t procfs proc /proc
</pre>
<p>&#8230;and make sure they are mounted on boot.</p>
<pre class="brush: bash; title: ; notranslate">
cat &lt;&lt;EOF &gt;&gt; /etc/fstab
fdesc   /dev/fd         fdescfs         rw      0       0
proc    /proc           procfs          rw      0       0
EOF
</pre>
<p>We need to make sure <strong>jenkins </strong>starts on boot.</p>
<pre class="brush: bash; title: ; notranslate">
sysrc jenkins_enable=YES
</pre>
<p>Now, we can start <strong>jenkins</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
service jenkins start
</pre>
<p>Go to <strong>http://[IP]:8180/jenkins</strong> and you should see the welcome screen. Replace the <strong>[IP]</strong> with the IP address of your server. You should see this screen.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/07/P134-02.jpg"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/07/P134-02.jpg" alt="" width="861" height="355" class="aligncenter size-full wp-image-8638" srcset="https://blog.andreev.it/wp-content/uploads/2019/07/P134-02.jpg 861w, https://blog.andreev.it/wp-content/uploads/2019/07/P134-02-300x124.jpg 300w, https://blog.andreev.it/wp-content/uploads/2019/07/P134-02-768x317.jpg 768w, https://blog.andreev.it/wp-content/uploads/2019/07/P134-02-585x241.jpg 585w" sizes="(max-width: 861px) 100vw, 861px" /></a><br />
Cat out that file, copy &#038; paste the value in the browser and click <strong>Continue</strong>.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
cat /usr/local/jenkins/secrets/initialAdminPassword
c33a584df234433d9a88e19d8e14c289
</pre>
<p>And that’s it. Follow the prompts to install plugins, provide admin password etc…The jenkins installation on FreeBSD is accessed with a suffix <strong>/jenkins</strong>. If you try to access it without the suffix, you&#8217;ll get this error.</p>
<pre class="brush: bash; title: ; notranslate">
HTTP ERROR 404
Problem accessing /. Reason:
    Not Found
</pre>
<p>It&#8217;s much easier to do the redirects with nginx without the suffix, so we&#8217;ll change it.<br />
Edit this file <strong>/usr/local/etc/rc.d/jenkins</strong> and around line 54 find this.</p>
<pre class="brush: bash; title: ; notranslate">
: ${jenkins_args=&quot;--webroot=${jenkins_home}/war --httpPort=8180 --prefix=/jenkins&quot;}
</pre>
<p>Change it so it looks like this.</p>
<pre class="brush: bash; title: ; notranslate">
: ${jenkins_args=&quot;--webroot=${jenkins_home}/war --httpPort=8180 --prefix=/&quot;}
</pre>
<p>Restart <strong>Jenkins </strong>and you&#8217;ll be able to access it as <strong>http://[IP]:8180</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
service jenkins restart
</pre>
<h2>nginx as reverse proxy</h2>
<p>In order to access the server with out the need to specify the port 8180 and use a DNS name, we&#8217;ll have to use nginx that will listen on port 80 or 443 and redirect the traffic to 8180. Let&#8217;s install and configure <strong>nginx</strong>. In my case, I&#8217;ll access the server as <strong>jenkins.domain.com</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install nginx
</pre>
<p>Run on boot.</p>
<pre class="brush: bash; title: ; notranslate">
sysrc nginx_enable=YES
</pre>
<p>Edit <strong>/usr/local/etc/nginx/nginx.conf</strong> and delete everything after this line around line 39 after <strong>#gzip on</strong> directive. Add the include line, so the last three lines look like this.</p>
<pre class="brush: bash; title: ; notranslate">
    #gzip  on;
    include /usr/local/etc/nginx/conf.d/*.conf;
}
</pre>
<p>Create a new <strong>conf.d</strong> folder <strong>mkdir /usr/local/etc/nginx/conf.d</strong> and create a new file called <strong>jenkins.conf</strong>.<br />
This is how my <strong>jenkins.conf</strong> file looks like. Change the domain in the highlighted line.</p>
<pre class="brush: bash; highlight: [3]; title: ; notranslate">
server {
    listen 80;
    server_name jenkins.domain.com;

    location / {
        proxy_set_header   X-Forwarded-For $remote_addr;
        proxy_set_header   Host $http_host;
        proxy_pass         &quot;http://127.0.0.1:8180&quot;;
    }
}
</pre>
<p>Restart <strong>Jenkins </strong>and you should be able to access the site now with http://jenkins.domain.com.<br />
For HTTPS traffic, the configuration is different. You&#8217;ll need certificates specified in lines 15 and 16 (under <strong>/usr/local/etc/nginx</strong>) and the domain changed in 7,13 and 31. Here is the config (<strong>/usr/local/etc/nginx/conf.d/jenkins.conf</strong>) in order to access jenkins over SSL. </p>
<pre class="brush: bash; highlight: [7,13,15,16,31]; title: ; notranslate">
upstream jenkins {
  server 127.0.0.1:8180 fail_timeout=0;
}

server {
  listen 80;
  server_name jenkins.domain.com;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl;
  server_name jenkins.domain.com;

  ssl_certificate public_cert.pem;
  ssl_certificate_key private_cert.key;
  client_max_body_size 4M;

  location / {
    proxy_set_header        Host $host:$server_port;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Proto $scheme;
    proxy_redirect http:// https://;
    proxy_pass              http://jenkins;
    # Required for new HTTP-based CLI
    proxy_http_version 1.1;
    proxy_request_buffering off;
    proxy_buffering off; # Required for HTTP-based CLI to work over SSL
    # workaround for https://issues.jenkins-ci.org/browse/JENKINS-45651
    add_header 'X-SSH-Endpoint' 'jenkins.domain.com:50022' always;
  }
}
</pre>
<p>You should also restart <strong>nginx </strong>for the changes to take effect.</p>
<pre class="brush: bash; title: ; notranslate">
service nginx restart
</pre>
<p>That&#8217;s it. You should be able to access <strong>Jenkins </strong>as <strong>jenkins.domain.com</strong> over https.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2019/07/freebsd-centos-install-jenkins-behind-a-nginx-reverse-proxy-using-ssl-certificates/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>FreeBSD: Install Prometheus, Node Exporter and Grafana</title>
		<link>https://blog.andreev.it/2019/04/freebsd-install-prometheus-node-exporter-and-grafana/</link>
					<comments>https://blog.andreev.it/2019/04/freebsd-install-prometheus-node-exporter-and-grafana/#comments</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sat, 20 Apr 2019 22:49:05 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[grafana]]></category>
		<category><![CDATA[node_exporter]]></category>
		<category><![CDATA[prometheus]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=5289</guid>

					<description><![CDATA[FreeBSD comes out of the box with three great tools for monitoring. If you&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>FreeBSD comes out of the box with three great tools for monitoring. If you need more info about how these tools work, please read the official documentation. I&#8217;ll explain the installation only and creating a simple dashboard.<br />
The installation is very simple. These amazing tools don&#8217;t need any external libraries. We&#8217;ll install the packages and enable them to start on boot.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install prometheus node_exporter grafana5
sysrc prometheus_enable=YES
sysrc node_exporter_enable=YES
sysrc grafana_enable=YES
</pre>
<p>Add these lines at the very end in <strong>/usr/local/etc/prometheus.yml</strong>. Make sure you have the proper spacing. Check the <strong>job_name</strong> above. They have to be in line.</p>
<pre class="brush: plain; title: ; notranslate">
- job_name: 'node_exporter'
  scrape_interval: 5s
  static_configs:
    - targets: &#x5B;'localhost:9100']
</pre>
<p>Looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-01.png" alt="" width="564" height="227" class="aligncenter size-full wp-image-8529" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-01.png 564w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-01-300x121.png 300w" sizes="(max-width: 564px) 100vw, 564px" /></a><br />
Now start the services. </p>
<pre class="brush: bash; title: ; notranslate">
service prometheus start
service node_exporter start
service grafana start
</pre>
<p>Go to http://your_ip:9090. This is how it should look like.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-02.png" alt="" width="504" height="499" class="aligncenter size-full wp-image-8530" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-02.png 504w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-02-300x297.png 300w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-02-150x150.png 150w" sizes="(max-width: 504px) 100vw, 504px" /></a><br />
Type <strong>prometheus_http_requests_total</strong> or <strong>node_memory_active_bytes</strong> in the Expression field and click on <strong>Execute</strong>. You should see some output below.</p>
<p>Now go to Grafana at http://your_ip:3000. Log as admin/admin and you&#8217;ll be prompted to change your password. From the <strong>Home Dashboard</strong> click on Add Source, right in the middle.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-03.png" alt="" width="1162" height="602" class="aligncenter size-full wp-image-8531" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-03.png 1162w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-03-300x155.png 300w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-03-1024x531.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-03-768x398.png 768w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-03-585x303.png 585w" sizes="(max-width: 1162px) 100vw, 1162px" /></a><br />
Click on the Prometheus icons from the choice of the others. You&#8217;ll be prompted to fill out this form. Just make sure the URL is http://localhost:9090. Click <strong>Save &#038; Test</strong> and make sure it&#8217;s OK.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-04.png" alt="" width="699" height="897" class="aligncenter size-full wp-image-8532" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-04.png 699w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-04-234x300.png 234w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-04-585x751.png 585w" sizes="(max-width: 699px) 100vw, 699px" /></a><br />
Now, in the upper left corner where the Grafana logo is, click on the <strong>Plus (+)</strong> sign and choose <strong>Import</strong>. In another browser tab go to this <a href="https://grafana.com/dashboards/1860" rel="noopener noreferrer" target="_blank">link </a>and on the right side click on <strong>Download JSON</strong>. Save it somewhere. Go back to your Grafana dashboard and click on <strong>Upload .json file</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-05.png" alt="" width="1069" height="636" class="aligncenter size-full wp-image-8533" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-05.png 1069w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-05-300x178.png 300w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-05-1024x609.png 1024w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-05-768x457.png 768w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-05-585x348.png 585w" sizes="(max-width: 1069px) 100vw, 1069px" /></a><br />
Find the JSON file that you saved in the previous step and upload it. You&#8217;ll see this screen. Just make sure to choose <strong>Prometheus </strong>under <strong>localhost </strong>parameter and click <strong>Import</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-06.png" alt="" width="1019" height="452" class="aligncenter size-full wp-image-8534" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-06.png 1019w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-06-300x133.png 300w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-06-768x341.png 768w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-06-585x259.png 585w" sizes="(max-width: 1019px) 100vw, 1019px" /></a><br />
That&#8217;s it. You&#8217;ll see the node_exporter&#8217;s dashboard.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-07.png" alt="" width="734" height="283" class="aligncenter size-full wp-image-8535" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-07.png 734w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-07-300x116.png 300w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-07-585x226.png 585w" sizes="(max-width: 734px) 100vw, 734px" /></a><br />
Now, you can add dashboards. Click on the (+) on the left, click on <strong>Dashboard</strong>, click on the arrow next to <strong>Panel Title</strong> and select <strong>Edit</strong>. Add some metrics such as this example below and click on <strong>Add Query</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-08.png" alt="" width="456" height="346" class="aligncenter size-full wp-image-8536" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-08.png 456w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-08-300x228.png 300w" sizes="(max-width: 456px) 100vw, 456px" /></a><br />
Finally click on the floppy icon on top to save the dashboard. It looks like this after.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2019/04/P131-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2019/04/P131-09.png" alt="" width="989" height="458" class="aligncenter size-full wp-image-8537" srcset="https://blog.andreev.it/wp-content/uploads/2019/04/P131-09.png 989w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-09-300x139.png 300w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-09-768x356.png 768w, https://blog.andreev.it/wp-content/uploads/2019/04/P131-09-585x271.png 585w" sizes="(max-width: 989px) 100vw, 989px" /></a><br />
You can also go to this <a href="https://grafana.com/grafana/dashboards?orderBy=name&#038;direction=asc">site </a>and use some community dashboards for various metrics and applications.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2019/04/freebsd-install-prometheus-node-exporter-and-grafana/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>FreeBSD: Install an authoritative DNS server (BIND)</title>
		<link>https://blog.andreev.it/2018/10/137-freebsd-install-an-authoritative-dns-server-bind/</link>
					<comments>https://blog.andreev.it/2018/10/137-freebsd-install-an-authoritative-dns-server-bind/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Tue, 23 Oct 2018 14:13:54 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[BIND]]></category>
		<category><![CDATA[DNS]]></category>
		<category><![CDATA[freebsd]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=4096</guid>

					<description><![CDATA[In this post I&#8217;ll explain how to install and configure BIND DNS server to&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post I&#8217;ll explain how to install and configure BIND DNS server to act as an authoritative server for a public domain in a master/slave configuration. This is not a setup for a server that will act as a DNS server in your local environment and does DNS resolution for your local network. In this post, the DNS server won&#8217;t resolve any DNS queries except for the domain that it is authoritative for. The domain that I&#8217;ll use is <strong>cloudwerk.us</strong> registered with Go Daddy, so some of the configurations will apply to Go Daddy only. The IPs and keys that I&#8217;ll use will be visible. The setup will be gone by the time you read this.<br />
So, I have my master server, <strong>ns1.cloudwerk.us (104.248.47.54)</strong> and the slave server <strong>ns2.cloudwerk.us (142.93.201.231)</strong>.<br />
I will be using FreeBSD 11.2 and BIND 9.12.2-P2. Before you start, make sure you have your domain purchased and you have 2 servers with public IPs up and running. You can leave the default registrant&#8217;s DNS servers for now. </p>
<h1>Installation, startup and control</h1>
<p>First, I&#8217;ll install BIND on both servers. All commands below are executed as root.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install bind912
</pre>
<p>When the installation is done after 10-15 seconds, you&#8217;ll see some text that requires attention. I am not using a jailed install, so I can skip that part. The only part that&#8217;s important is to create the key for the <strong>rndc (Remote Name Daemon Control) </strong>utility. This utility allows management of the <strong>named </strong>(DNS) daemon. Moreover, you can manage remote DNS servers and I&#8217;ll explain how. So, let&#8217;s create the keys (highlighted line is what you type, the rest is output). Do this on the master server only.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
rndc-confgen -a
wrote key file &quot;/usr/local/etc/namedb/rndc.key&quot;
</pre>
<p>As you can see, there is a file called <strong>rndc.key</strong> created under <strong>/usr/local/etc/namedb</strong> directory. This is the default directory where BIND expects to find its config files and zones.<br />
Now, copy this file to the second server in the same location. You can use scp, copy &#038; paste in a terminal session, it doesn&#8217;t matter. What matters is that you have to change the permissions and the owner of the file. BIND runs under the <strong>bind </strong>user, not root. Do this on both servers. </p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/namedb
chown root:bind rndc.key
chmod 640 rndc.key
</pre>
<p>Let&#8217;s make sure that BIND starts on boot. On both servers, execute:</p>
<pre class="brush: bash; title: ; notranslate">
sysrc named_enable=&quot;YES&quot;
</pre>
<p>Now, we can start the BIND daemon on both. </p>
<pre class="brush: bash; title: ; notranslate">
service named start
</pre>
<p>Check the logs.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
tail /var/log/messages
Oct 22 15:11:11 ns1 named&#x5B;1161]: ----------------------------------------------------
Oct 22 15:11:11 ns1 named&#x5B;1161]: BIND 9 is maintained by Internet Systems Consortium,
Oct 22 15:11:11 ns1 named&#x5B;1161]: Inc. (ISC), a non-profit 501(c)(3) public-benefit
Oct 22 15:11:11 ns1 named&#x5B;1161]: corporation.  Support and training for BIND 9 are
Oct 22 15:11:11 ns1 named&#x5B;1161]: available at https://www.isc.org/support
Oct 22 15:11:11 ns1 named&#x5B;1161]: ----------------------------------------------------
Oct 22 15:11:11 ns1 named&#x5B;1161]: command channel listening on 127.0.0.1#953
Oct 22 15:11:11 ns1 named&#x5B;1161]: command channel listening on ::1#953
Oct 22 15:11:11 ns1 named&#x5B;1161]: all zones loaded
Oct 22 15:11:11 ns1 named&#x5B;1161]: running
</pre>
<p>We can&#8217;t start the server with the <strong>rndc </strong>utility, but we can stop it if needed with <strong>rndc stop</strong> or simply <strong>service named stop</strong>.<br />
To control the slave server from the master, we have to modify the main BIND configuration file, <strong>named.conf</strong> on the slave server. Also, the keys have to be the same, but we already took care of that part above.<br />
So, in the same <strong>/usr/local/etc/namedb</strong> directory, edit <strong>named.conf</strong> and add these lines, right before the options directive. Do this on the slave server, not the master.</p>
<pre class="brush: bash; title: ; notranslate">
include &quot;/usr/local/etc/namedb/rndc.key&quot;;

controls {
        inet 127.0.0.1 allow { localhost; } keys { &quot;rndc-key&quot;; };
        inet 142.93.201.231 allow { 104.248.47.54; } keys { &quot;rndc-key&quot;; };
};
</pre>
<p>If you look at my IPs below, this means that the rndc utility will be accepted from the localhost and from the the IP 104.248.47.54 which is the master server. But, we also have to tell BIND to listen on the public IP. By default, it listens on the <strong>localhost </strong>only.<br />
Do this on BOTH servers. In <strong>named.conf</strong> find the <strong>options </strong>directive and modify the <strong>listen-on</strong> option so it looks like this. You should put the public IP of each server there, so the line will differ on both servers. </p>
<pre class="brush: bash; title: ; notranslate">
//Master server
listen-on       { 127.0.0.1; 104.248.47.54; };
</pre>
<pre class="brush: bash; title: ; notranslate">
//Slave server
listen-on       { 127.0.0.1; 142.93.201.231; };
</pre>
<p>Restart BIND on both.</p>
<pre class="brush: bash; title: ; notranslate">
service named restart
</pre>
<p>Now, you can manage them with rndc.</p>
<pre class="brush: bash; title: ; notranslate">
rndc reload
rndc status
</pre>
<p>From the master server, try to reload the slave server.</p>
<pre class="brush: bash; title: ; notranslate">
rndc -s 142.93.201.231 reload
server reload successful
</pre>
<p>If you have a firewall, make sure port 953 TCP is open for communication.<br />
What we also want to do is tell the OS that from now on, the default DNS server will be our local DNS.<br />
So, edit <strong>/etc/resolv.conf</strong> and add this line as the first line on both. </p>
<pre class="brush: bash; title: ; notranslate">
nameserver 127.0.0.1
</pre>
<p>If we try to ping google.com we should get a response or at least an IP resolved. That&#8217;s good. From another computer, try to use any of our servers as a DNS. This is what you should get: Query refused. That&#8217;s good too, because we don&#8217;t want our server to be used as a DNS server for other domains. But, also, we want to access the Internet from the server, for example to update the server. Name resolution for other domains from localhost is OK, but not OK from outside. </p>
<pre class="brush: bash; highlight: [1,5,9]; title: ; notranslate">
C:\Users\Elite&gt;nslookup
Default Server:  ns-cache.above.net
Address:  207.126.96.248

&gt; server 142.93.201.231
Default Server:  ns2.cloudwerk.us
Address:  142.93.201.231

&gt; www.google.com
Server:  ns2.cloudwerk.us
Address:  142.93.201.231

*** ns2.cloudwerk.us can't find www.google.com: Query refused
</pre>
<p>You can allow this server to act as a forwarder by including <strong>recursion yes</strong>; option under <strong>options </strong>and <strong>allow-access</strong> to all IPs, but that&#8217;s not the intended use of an authoritative DNS server. </p>
<h1>Zone file</h1>
<p>Now that we have the servers up and running, let&#8217;s create the zone file. The zone file tells where the records can be found. On the master server only, edit <strong>named.conf</strong> and add these two lines right after the <strong>listen-on</strong> option. We are allowing the transfer of the zones to the slave server only</p>
<pre class="brush: bash; title: ; notranslate">
allow-transfer { localhost; 142.93.201.231; };
notify yes;
</pre>
<p>Go all the way at the bottom and add these line to define the zone file.<br />
<strong>NOTE:</strong> If you don&#8217;t want to use the dynamic directory, make sure that your zone file directory is owned by the <strong>bind </strong>user and group (e.g. <em>mkdir somedir, chown -R bind:bind somedir</em>).</p>
<pre class="brush: bash; title: ; notranslate">
zone &quot;cloudwerk.us&quot; {
        type master;
        file &quot;/usr/local/etc/namedb/dynamic/db.cloudwerk.us&quot;;
};
</pre>
<p>Now, go to the <strong>/usr/local/etc/namedb/dynamic </strong>directory and create the zone file to look like this. The file should be called <strong>db.cloudwerk.us</strong>. Do this on the master server only. You might want to read the following <a href="https://help.dyn.com/how-to-format-a-zone-file" rel="noopener noreferrer" target="_blank">link </a>if you are not familiar with the syntax of a zone file. </p>
<pre class="brush: bash; title: ; notranslate">
$TTL    604800
@       IN      SOA     ns1.cloudwerk.us.       admin.cloudwerk.us. (
                        2018101901;     Serial
                        3H;             Refresh
                        15M;            Retry
                        2W;             Expiry
                        1D );           Minimum

; name servers - NS records
        IN      NS      ns1.cloudwerk.us.
        IN      NS      ns2.cloudwerk.us.

; name servers - A records
ns1.cloudwerk.us.       IN      A       104.248.47.54
ns2.cloudwerk.us.       IN      A       142.93.201.231

; other servers - A records
www.cloudwerk.us.       IN      A       52.71.63.84
</pre>
<p>All you have to do now is to reload the new config with <strong>rndc reload</strong>. At this point we have the master server up and running. Now, we have to configure the slave server. Edit the <strong>named.conf</strong> file and add these lines at the bottom. Very self-explanatory. </p>
<pre class="brush: bash; title: ; notranslate">
zone &quot;cloudwerk.us&quot; {
        type slave;
        masters { 104.248.47.54; };
        file &quot;/usr/local/etc/namedb/dynamic/db.cloudwerk.us&quot;;
};
</pre>
<p>Restart the <strong>named </strong>daemon and if you go to <strong>/usr/local/etc/namedb/dynamic</strong> directory, you&#8217;ll see that the zone file replicated from the master.<br />
At this point, we have both the master and the slave servers configured, up and running. But no one on the Internet knows that our servers are authoritative servers. You have to make this change at your domain registrant. In my case, I&#8217;ve purchased the domain from Go Daddy, so I went to the DNS management panel and add two A records for ns1.cloudwerk.us and ns2.cloudwerk.us. Then, at the bottom of the web contol panel, I&#8217;ve changed the DNS from xy.domaincontrol.com to custom and added my servers. I&#8217;ve encountered some issues, but the on-line chat with the support resolved this in 5 minutes. In essence, if you open up the DNS console, scroll all the way down and under <strong>Advanced Features</strong>, you&#8217;ll see <strong>Host names</strong> link. Click on this one and create two records, ns1 and ns2 with your IPs. Now, you can switch to <strong>Custom Nameserves</strong> on the same page.<br />
Leave some time for replication. It might take up to 24 hrs, but in my case it took less than 20 mins.<br />
You should know that you are in charge when these commands return your servers. In Windows:</p>
<pre class="brush: bash; highlight: [1,5,6]; title: ; notranslate">
C:\Users\Elite&gt;nslookup
Default Server:  ns-cache.above.net
Address:  207.126.96.248

&gt; set query=soa
&gt; cloudwerk.us
Server:  ns-cache.above.net
Address:  207.126.96.248

Non-authoritative answer:
cloudwerk.us
        primary name server = ns1.cloudwerk.us
        responsible mail addr = admin.cloudwerk.us
        serial  = 2018101901
        refresh = 10800 (3 hours)
        retry   = 900 (15 mins)
        expire  = 1209600 (14 days)
        default TTL = 86400 (1 day)

cloudwerk.us    nameserver = ns2.cloudwerk.us
cloudwerk.us    nameserver = ns1.cloudwerk.us
ns1.cloudwerk.us        internet address = 104.248.47.54
ns2.cloudwerk.us        internet address = 149.93.201.231
</pre>
<p>In Linux/BSD if you use <strong>dig</strong>:</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
dig +short NS cloudwerk.us
ns2.cloudwerk.us.
ns1.cloudwerk.us.
</pre>
<p>Or, if you want to do it <a href="https://mxtoolbox.com/dnscheck.aspx" rel="noopener noreferrer" target="_blank">on-line</a>.<br />
This is what I got.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-01.png" alt="" width="1482" height="764" class="aligncenter size-full wp-image-8279" /></a><br />
It says that the slave server is leaking the zone which means anyone can list all the records. In order to prevent that, we have to edit <strong>named.con</strong>f on the slave server and add this line after <strong>listen-on </strong>option.</p>
<pre class="brush: bash; title: ; notranslate">
allow-transfer { localhost; 104.248.47.54; };
</pre>
<p>Do <strong>rndc reload</strong> after and if you re-execute the test, you&#8217;ll see that everything looks OK.</p>
<h1>DNSSEC (optional)</h1>
<p>I won&#8217;t go into details of what is DNSSEC, I&#8217;ll just explain how to configure and secure your DNS server. It&#8217;s pretty much a PKI infrastructure for securing your records by signing them with a private key. If you need more info, you can find tons of info by googling DNSSEC.<br />
On the master server, add these lines after <strong>listen-on</strong> option in <strong>named.conf</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
dnssec-enable yes;
key-directory &quot;/usr/local/etc/namedb/keys&quot;;
</pre>
<p>On the slave server, add this line after <strong>listen-on</strong> option in <strong>named.conf</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
dnssec-enable yes;
</pre>
<p>Add these lines in the same file on the master server  only. They should be below <strong>file </strong>directive where your zone is defined (at the bottom of the file).</p>
<pre class="brush: bash; title: ; notranslate">
auto-dnssec maintain;
inline-signing yes;
</pre>
<p>On the master server only, create they <strong>keys </strong>directory.</p>
<pre class="brush: bash; title: ; notranslate">
mkdir /usr/local/etc/namedb/keys
cd /usr/local/etc/namedb/keys
</pre>
<p>Let&#8217;s create the KSK and ZSK keys. Master server only.</p>
<pre class="brush: bash; title: ; notranslate">
dnssec-keygen -r /dev/urandom -a RSASHA256 -b 2048 -f KSK -n ZONE cloudwerk.us
ls -l
echo &quot;Take a note of the key file&quot;
dnssec-keygen -r /dev/urandom -a RSASHA256 -b 2048 -n ZONE cloudwerk.us
</pre>
<p>You&#8217;ll see 4 files created. Scribble down the first key file that was created, see the output from above. Step one directory up and change the ownership so BIND can read these files.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/etc/namedb
chown -R bind:bind keys
rndc reload
</pre>
<p>If you go to the <strong>dynamic </strong>directory where your zone file is, you&#8217;ll see three more files. These are the signed files.</p>
<pre class="brush: bash; title: ; notranslate">
ls -l /usr/local/etc/namedb/dynamic
</pre>
<p>If you go on the slave server in the same <strong>dynamic </strong>directory, you&#8217;ll see that signed <strong>.jnl</strong> file also transferred.<br />
Let&#8217;s do a test. Go to this <a href="https://dnssec-analyzer.verisignlabs.com/" rel="noopener noreferrer" target="_blank">link</a>, type your domain name and hit enter.<br />
You should see something like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-02.png" alt="" width="470" height="519" class="aligncenter size-full wp-image-8280" /></a><br />
Now, stop the master server with <strong>rndc stop</strong> and refresh the web page. The test will take a little bit longer, because NS1 is down, but eventually you&#8217;ll get something like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-03.png" alt="" width="504" height="540" class="aligncenter size-full wp-image-8281" /></a><br />
That&#8217;s normal. It tells us that ns1 is down. What&#8217;s not normal is the red X mark that says <strong>&#8220;No DS records found for coudwerk.us in the us zone&#8221;</strong>. This translates as, yes you signed your zone, but no one can validate it. It&#8217;s like a fake certificate. So, we need to tell our registrant that we really own the domain and that we signed it.<br />
This portion is also registrant&#8217;s  dependent. I&#8217;ll describe how to overcome this error with Go Daddy.<br />
So, go to the <strong>keys </strong>directory and execute this command against the first file. </p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
cd /usr/local/etc/namedb/keys
dnssec-dsfromkey Kcloudwerk.us.+008+23956.key
cloudwerk.us. IN DS 23956 8 1 2DA94FECA549E0A2B137FA6C64D09D2CBADF8864
cloudwerk.us. IN DS 23956 8 2 8CC2CB79E1B8A6767F11230485C7499D52162135E1F6DAA503ADEC4470E417A9
</pre>
<p>Now go to the DNS management panel for your domain at Go Daddy and you&#8217;ll see something like this. Click on <strong>DNSSEC</strong> and then click <strong>ADD</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-04.png" alt="" width="419" height="529" class="aligncenter size-full wp-image-8282" /></a><br />
Looks confusing but it&#8217;s very simple. Just look at the output from the <strong>dnssec-dsfromkey</strong> and add accordingly. You&#8217;ll have to add both hash values.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-05.png" alt="" width="800" height="573" class="aligncenter size-full wp-image-8283" /></a><br />
For <strong>Key Tag</strong> enter <strong>23956</strong>, <strong>Algorithm</strong> is <strong>8</strong>, <strong>Digest Type</strong> is <strong>1</strong>, <strong>Digest </strong>is the hash value and <strong>Key Data Algorithm</strong> is also <strong>8</strong>, the value of <strong>Algorithm</strong>. Click <strong>Update </strong>, do the 2nd line of the output and wait 30-45 mins. Sometimes, even more. It depends on your registrant.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-06.png" alt="" width="861" height="892" class="aligncenter size-full wp-image-8284" /></a><br />
At the end it should look like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-07.png" alt="" width="1478" height="325" class="aligncenter size-full wp-image-8285" /></a><br />
And if you analyze your domain again, the result should look like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/10/P114-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/10/P114-08.png" alt="" width="713" height="929" class="aligncenter size-full wp-image-8286" /></a><br />
Or if you use dig, use the Google&#8217;s DNS server to check.</p>
<pre class="brush: bash; title: ; notranslate">
dig +trace +noadditional DS cloudwerk.us. @8.8.8.8 | grep DS
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2018/10/137-freebsd-install-an-authoritative-dns-server-bind/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows, CentOS, FreeBSD: ssh, RDP &#8211; Bypass your corporate firewall</title>
		<link>https://blog.andreev.it/2018/03/125-ssh-rdp-bypass-your-corporate-firewall/</link>
					<comments>https://blog.andreev.it/2018/03/125-ssh-rdp-bypass-your-corporate-firewall/#comments</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 23 Mar 2018 17:04:18 +0000</pubDate>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[bypass]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[firewall]]></category>
		<category><![CDATA[freebsd]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=3765</guid>

					<description><![CDATA[If you are behind a firewall and want to access some resources over SSH&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>If you are behind a firewall and want to access some resources over SSH or RDP, most likely you won&#8217;t be able to do that. It&#8217;s because most of the corporate firewalls allow only ports 80 and 443 outbound. But you can still bypass that by tunneling everything over port 443. You will need a software called shellinabox to tunnel SSH over 443 and RDP gateway to tunnel the RDP traffic over 443. I&#8217;ll present the shellinabox solution for both CentOS 7 and FreeBSD 11. Both of these servers will be sitting somewhere in the cloud or behind your home firewall. The only requirement is to have port 443 opened and accessible on Internet. You might have a public IP or your home firewall will forward the traffic to 443, it doesn&#8217;t matter. Another option for connecting to any port is to use putty and a Linux/FreeBSD instance. I&#8217;ll describe that option last.</p>
<h1>CentOS 7</h1>
<p>shellinabox doesn&#8217;t come up with the default packages, so you have to install the EPEL release first. </p>
<pre class="brush: bash; title: ; notranslate">
yum install epel-release
yum install shellinabox
systemctl enable shellinaboxd
</pre>
<p>Edit the configuration file for shellinabox which is <strong>/etc/sysconfig/shellinaboxd</strong>. Make sure it looks like this. </p>
<pre class="brush: bash; title: ; notranslate">
# Shell in a box daemon configuration
# For details see shellinaboxd man page
# Basic options
USER=shellinabox
GROUP=shellinabox
CERTDIR=/var/lib/shellinabox
PORT=4200
OPTS=&quot;--css white-on-black.css -t -s /:SSH:localhost&quot;
#OPTS=&quot;--css color.css -t -s /:SSH:localhost&quot;
</pre>
<p>shellinabox runs on port 4200 by default. You can change it to run on 443, but you have to run as root. A better solution is to install Apache and use the mod_proxy so the Apache will listen on 443 and forward the traffic to 4200. </p>
<pre class="brush: bash; title: ; notranslate">
yum install httpd mod_ssl
systemctl enable httpd
</pre>
<p>Create the configuration file for the Apache server. In my case, I&#8217;ll access the SSH over HTTPS as sshtest.iandreev.com. Change the config below to suit your needs. </p>
<pre class="brush: bash; title: ; notranslate">
cd /etc/httpd/conf.d
touch httpd-vhosts.conf
</pre>
<p>Edit httpd-vhosts.conf and paste the following. </p>
<pre class="brush: bash; title: ; notranslate">
&lt;VirtualHost *:443&gt;
    SSLEngine On
    SSLCertificateFile /etc/pki/tls/certs/sshtest.iandreev.com.crt
    ServerAdmin klimenta@iandreev.com
    ServerName sshtest.iandreev.com
    ErrorLog &quot;/var/log/httpd/sshtest.iandreev.com-error_log&quot;
    CustomLog &quot;/var/log/httpd/sshtest.iandreev.com-access_log&quot; combined
    ProxyRequests On
    ProxyPreserveHost On
    &lt;Proxy *&gt;
        AuthUserFile /var/www/sshtest.iandreev.com/.htpasswd
        AuthName EnterPassword
        AuthType Basic
        require user ssh.admin
        Order deny,allow
        Allow from all
    &lt;/Proxy&gt;
    ProxyPass / http://localhost:4200/
    ProxyPassReverse / http://localhost:4200/
&lt;/VirtualHost&gt;
</pre>
<p>HTTPS requires a certificate, we&#8217;ll create a fake one. If you have a valid certificate, just put it under <strong>/etc/pki/tls/certs</strong> as <strong>sshtest.iandreev.com.crt</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
cd /etc/pki/tls/certs
./make-dummy-cert sshtest.iandreev.com.crt
</pre>
<p>shellinabox when started will give you a SSH prompt so you can login to your server. A more secure solution is to protect the access even more with a username and password. Anytime you access your server, you&#8217;ll get prompted with a username and password and then you&#8217;ll get prompted with your SSH credentials.</p>
<pre class="brush: bash; title: ; notranslate">
cd /var/www
mkdir sshtest.iandreev.com
cd sshtest.iandreev.com
htpasswd -c .htpasswd ssh.admin
cd ..
chown -R apache:apache sshtest.iandreev.com
</pre>
<p>I&#8217;ve created a user called ssh.admin and the commands above will ask you for a password.<br />
Now, it&#8217;s time to start shellinabox.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl start httpd
systemctl start shellinaboxd
</pre>
<p>On a laptop behind your comporate firewall, go to https://sshtest.yourdomain.com and you should get prompted for ssh.admin&#8217;s password. Once you pass that you&#8217;ll see the login prompt in your browser. From here you can SSH to any server that has port 22 opened.<br />
shellinabox comes with two styles. If you see above in it&#8217;s config, we provided these two lines.</p>
<pre class="brush: bash; title: ; notranslate">
OPTS=&quot;--css white-on-black.css -t -s /:SSH:localhost&quot;
#OPTS=&quot;--css color.css -t -s /:SSH:localhost&quot;
</pre>
<p>If you prefer black on white background, uncomment the last line, save the config file and restart shellinabox.<br />
Depending on your CentOS install, you might have firewall and SElinux enabled. If these are not configured, shellinabox won&#8217;t work. For the firewall, you&#8217;ll have to allow port 443 inbound. </p>
<pre class="brush: bash; title: ; notranslate">
firewall-cmd --add-service=https --permanent
firewall-cmd --reload
</pre>
<p>For SElinux, you&#8217;ll have to allow Apache to make outbound connections.</p>
<pre class="brush: bash; title: ; notranslate">
/usr/sbin/setsebool -P httpd_can_network_connect 1
</pre>
<p>At the end, it will look like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-01.png" alt="" width="698" height="281" class="aligncenter size-full wp-image-8195" /></a><br />
&#8230;and this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-02.png" alt="" width="475" height="219" class="aligncenter size-full wp-image-8196" /></a></p>
<h1>FreeBSD 11</h1>
<p>We have to install Apache and shellinabox first. </p>
<pre class="brush: bash; title: ; notranslate">
pkg install shellinabox apache24
</pre>
<p>Make sure they start on boot. Add these two lines in <strong>/etc/rc.d</strong></p>
<pre class="brush: bash; title: ; notranslate">
apache24_enable=&quot;YES&quot;
shellinaboxd_enable=&quot;YES&quot;
shellinaboxd_flags=&quot;--disable-ssl --css=/usr/local/www/sshtest.iandreev.com/style.css&quot;
</pre>
<p>Go to the Apache config directory and edit the config file <strong>/usr/local/etc/apache24/httpd.conf</strong>. Make sure these lines are uncommented. </p>
<pre class="brush: bash; title: ; notranslate">
Include etc/apache24/extra/httpd-vhosts.conf
LoadModule authn_socache_module libexec/apache24/mod_authn_socache.so
LoadModule socache_shmcb_module libexec/apache24/mod_socache_shmcb.so
LoadModule ssl_module libexec/apache24/mod_ssl.so
Include etc/apache24/extra/httpd-ssl.conf
LoadModule proxy_module libexec/apache24/mod_proxy.so
LoadModule proxy_http_module libexec/apache24/mod_proxy_http.so
ServerName www.example.com:80
</pre>
<p>Go to <strong>/usr/local/etc/apache24/extra</strong> folder and make sure you have the definitiopn for the virtual host there. Change it to suit your needs. </p>
<pre class="brush: bash; title: ; notranslate">
&lt;VirtualHost *:443&gt;
    SSLEngine On
    SSLCertificateFile /usr/local/share/certs/sshtest.iandreev.com.crt
    SSLCertificateKeyFile /usr/local/share/certs/sshtest.iandreev.com.key
    ServerAdmin klimenta@iandreev.com
    ServerName sshtest.iandreev.com
    ErrorLog &quot;/var/log/sshtest.iandreev.com-error_log&quot;
    CustomLog &quot;/var/log/sshtest.iandreev.com-access_log&quot; combined
    ProxyRequests On
    ProxyPreserveHost On
    &lt;Proxy *&gt;
        AuthUserFile /usr/local/www/sshtest.iandreev.com/.htpasswd
        AuthName EnterPassword
        AuthType Basic
        require user ssh.admin
        Order deny,allow
        Allow from all
    &lt;/Proxy&gt;
    ProxyPass / http://localhost:4200/
    ProxyPassReverse / http://localhost:4200/
&lt;/VirtualHost&gt;
</pre>
<p>In the same directory, edit <strong>httpd-ssl.conf</strong> file and make sure it looks like this.</p>
<pre class="brush: bash; title: ; notranslate">
SSLRandomSeed startup file:/dev/urandom 512
Listen 443
SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4
SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4
SSLHonorCipherOrder on
SSLProtocol all -SSLv3
SSLProxyProtocol all -SSLv3
SSLPassPhraseDialog  builtin
SSLSessionCache        &quot;shmcb:/var/run/ssl_scache(512000)&quot;
SSLSessionCacheTimeout  300
</pre>
<p>We&#8217;ll protect shellinabox with extra username (ssh.admin) and password. </p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/www
mkdir sshtest.iandreev.com
cd sshtest.iandreev.com
htpasswd -c .htpasswd ssh.admin
</pre>
<p>We&#8217;ll need a certificate for the HTTPS site. Use your own or create a fake one. Hit ENTER for everything prompted. It&#8217;s a fake certificate.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/share/certs
openssl genrsa -out sshtest.iandreev.com.key 2048
openssl req -new -key sshtest.iandreev.com.key -out sshtest.iandreev.com.csr
openssl x509 -req -days 3650 -in sshtest.iandreev.com.csr -signkey sshtest.iandreev.com.key -out sshtest.iandreev.com.crt
</pre>
<p>Unlike CentOS, FreeBSD shellinabox doesn&#8217;t come up with CSS files for the color, so we can use these two. Copy these files under <strong>/usr/local/www/sshtest.iandreev.com</strong> as <strong>blackonwhite.css</strong> and <strong>whiteonblack.css</strong>.<br />
This is <strong>blackonwhite.css</strong>. Click to expand. </p>
<pre class="brush: css; collapse: true; light: false; title: ; toolbar: true; notranslate">
#vt100 .ansiDefR {
  color:            #ffffff;
}

#vt100 .bgAnsiDefR {
  background-color: #123450;
}

#vt100 #scrollable.inverted .ansiDefR {
  color:            #000000;
}

#vt100 #scrollable.inverted .bgAnsiDefR {
  background-color: #ffffff;
}

#vt100 .ansiDefR {
  color:            #ffdfd0;
}

#vt100 .bgAnsiDefR {
  background-color: #010203;
}

#vt100 #scrollable.inverted .ansiDefR {
  color:            #002030;
}

#vt100 #scrollable.inverted .bgAnsiDefR {
  background-color: #1f1fff;
}
</pre>
<p>This is <strong>whiteonblack.css</strong>. Click to expand.</p>
<pre class="brush: css; collapse: true; light: false; title: ; toolbar: true; notranslate">
#vt100 #cursor.bright {
  background-color: white;
  color:            black;
}

#vt100 #cursor.dim {
  background-color: black;
  opacity:          0.2;
  -moz-opacity:     0.2;
  filter:           alpha(opacity=20);
}

#vt100 #scrollable {
  color:            #ffffff;
  background-color: #000000;
}

#vt100 #scrollable.inverted {
  color:            #000000;
  background-color: #ffffff;
}

#vt100 .ansiDef {
  color:            #ffffff;
}

#vt100 .ansiDefR {
  color:            #000000;
}

#vt100 .bgAnsiDef {
  background-color: #000000;
}

#vt100 .bgAnsiDefR {
  background-color: #ffffff;
}

#vt100 #scrollable.inverted .ansiDef {
  color:            #000000;
}

#vt100 #scrollable.inverted .ansiDefR {
  color:            #ffffff;
}

#vt100 #scrollable.inverted .bgAnsiDef {
  background-color: #ffffff;
}

#vt100 #scrollable.inverted .bgAnsiDefR {
  background-color: #000000;
}
</pre>
<p>Copy one of them to be your style. Anytime you change the style, restart shellinabox.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/www/sshtest.iandreev.com
cp blackonwhite.css style.css
cd ..
chown -R www:www sshtest.iandreev.com
</pre>
<p>Finally, start Apache and shellinabox. </p>
<pre class="brush: bash; title: ; notranslate">
service shellinaboxd start
service apache24 start
</pre>
<p>Access your server from a laptop behind your corporate firewall as https://sshtest.domain.com.</p>
<h1>Windows 2016</h1>
<p>You will need a Windows 2016 server with a public IP and port 443 allowed or you can use a Windows server behind your home network as long as port 443 is allowed. In order to bypass the RDP restriction, we&#8217;ll tunnel the RDP traffic over HTTPS using Remote Desktop Gateway.<br />
From the Server Manager, go to Add Roles and Features. Select <strong>Remote Desktop Services</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-03.png" alt="" width="790" height="556" class="aligncenter size-full wp-image-8197" /></a><br />
Click <strong>Next </strong>2-3 times and then select <strong>Remote Desktop Gateway</strong>. Click Next again and accept all the defaults. Windows will install some other components for you.<br />
Once everything is installed, from the Server Manager&#8217;s menu click on <strong>Tools</strong>, <strong>Remote Desktop Services</strong> and then <strong>Remote Desktop Gateway Manager</strong>.<br />
Click on the server name and in the middle pane you&#8217;ll see what you have to do.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-04.png" alt="" width="972" height="456" class="aligncenter size-full wp-image-8198" /></a><br />
Click on the first link, <strong>View or modify certificate properties</strong>. Choose to create a fake certificate or you can import your own. It has to be in p12 format, not PEM.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-05.png" alt="" width="499" height="590" class="aligncenter size-full wp-image-8199" /></a><br />
If you decide to go with a fake certificate, enter the FQDN of the server, e.g sshtest.iandreev.com. You will have to make sure that sshtest.iandreev.com resolves to the public IP of the Windows box or if you have an internal server in your home lab, then the external IP of your cable/DSL modem. Then just click on the button <strong>Create and Import Certificate</strong>, enter the FQDN sshtest.iandreev.com and then click <strong>OK </strong>when prompted. Click <strong>Apply </strong>and <strong>OK </strong>to go back.<br />
At this point, you might want to create a user or a group that you can allow access to the Gateway.<br />
I created a user called RDP. Back in the RD Gateway Manager, select <strong>Policies </strong>under the server name, right-click on it and choose <strong>Create New Authorization Policies</strong>. Choose the option to create both RD CAP and RD RAP policies. Here is what I did in the wizard config.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-06.png" alt="" width="958" height="600" class="aligncenter size-full wp-image-8200" /></a><br />
I choose BUILTIN\Users to be able to use the Gateway. The generic user RDP that I created is by default a member of the users group.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-07.png" alt="" width="952" height="598" class="aligncenter size-full wp-image-8201" /></a><br />
Select the default <strong>Enable device redirection for all client devices</strong>.<br />
Check both checkmarks for <strong>Idle Timeout</strong> and <strong>Session Timeout</strong>. This is optional, but it&#8217;s good to have.<br />
Click Next and then create the <strong>Resource Authorization Policy</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-08.png" alt="" width="957" height="598" class="aligncenter size-full wp-image-8202" /></a><br />
Accept the same group (<strong>BUILTIN\Users</strong>).<br />
Choose the option at the bottom, <strong>Allow users to connect to any network resource (computer)</strong>.<br />
Choose the first option, <strong>Allow connections only to port 3389</strong>.<br />
Click <strong>Next </strong>and <strong>Finish</strong>.<br />
So, how do you use this solution now? Easy&#8230;<br />
All you have to do is go to your corporate laptop and create a new RDP connection. Under the General tab enter the IP address of the Windows box that you want to reach. This is the box that listens on 3389 and that you are not able to reach directly. Mind that the Windows server that we just built is a gateway, so the Windows RD Gateway server should be able to talk to the destination server over 3389 and your corporate laptop will talk to Windows RD Gateway server over 443.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-09.png" alt="" width="542" height="580" class="aligncenter size-full wp-image-8203" /></a><br />
Click on the <strong>Advanced </strong>tab and then the <strong>Settings </strong>button. Select to <strong>Use these RD Gateway server settings</strong> and enter the FQDN (sshtest.iandreev.com) of the RD Gateway server that we just built.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-10.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-10.png" alt="" width="539" height="535" class="aligncenter size-full wp-image-8204" /></a><br />
Once you are done, click <strong>Connect </strong>and you should get prompted to enter the credentials for the RD Gateway (in my case the username and password for the RDP user) and then you&#8217;ll have to enter the username and password for the destination server.<br />
NOTE: Make sure you use .\rdp for the username, not rdp. You can also get an error saying that the identity of the RD Gateway can&#8217;t be verified. This is most likely if you messed up the certificate and it doesn&#8217;t match the hostname. In that case, the RDP client will allow you to view the certificate. Then copy it to a file and import it on the local machine under the Trusted Root Cert Authorities. </p>
<h1>Tunnel over putty</h1>
<p>Let&#8217;s say that your corporate firewall allows only port 443 outbound. In this case, we&#8217;ll build a Linux/BSD server with a public IP and change the SSH listener port from 22 to 443. For this, edit <strong>sshd_config</strong> under <strong>/etc/ssh/sshd_config</strong> or <strong>/usr/local/etc/ssh/sshd_config</strong>. Look for the directive <strong>Port 22</strong> and change it to <strong>Port 443</strong>. Restart the ssh service.<br />
On your client machine behind the corporate firewall, open putty and under Session enter the public IP of your Linux/BSD server and port 443 so it looks like this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-11.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-11.png" alt="" width="453" height="197" class="aligncenter size-full wp-image-8205" /></a><br />
Now, expand the <strong>Connection </strong>on the left side, then <strong>SSH </strong>and select <strong>Tunnels</strong>. For the <strong>source port</strong> enter 3390 and for the <strong>destination </strong>enter the IP of your Windows box where you want to connect.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P102-12.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P102-12.png" alt="" width="448" height="200" class="aligncenter size-full wp-image-8206" /></a><br />
Finally, save this session, open it and login to the Linux server to establish the tunnel. You should be able to run the RDP client (mstsc) and RDP to 127.0.0.1:3390. </p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2018/03/125-ssh-rdp-bypass-your-corporate-firewall/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>CentOS, FreeBSD, Windows: rsyslog server and client</title>
		<link>https://blog.andreev.it/2017/12/118-linux-freebsd-windows-rsyslog-server-client/</link>
					<comments>https://blog.andreev.it/2017/12/118-linux-freebsd-windows-rsyslog-server-client/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 03 Dec 2017 23:56:22 +0000</pubDate>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[rsyslog]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=3480</guid>

					<description><![CDATA[In this post, I&#8217;ll explain how to configure a rsyslog server and client on&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post, I&#8217;ll explain how to configure a <strong>rsyslog </strong>server and client on various operating systems. For the servers, I&#8217;ll chose 2 Red Hat 7 servers and the clients will be AWS Linux, FreeBSD and Windows 2016.<br />
<strong>rsyslog </strong>is an open-source utility for logging, a derivate of the original syslog. As defined by <a href="https://tools.ietf.org/html/rfc3164" rel="noopener noreferrer" target="_blank">RFC 3164</a>, each message includes the facility code and severity level. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-01.png" alt="" width="450" height="690" class="aligncenter size-full wp-image-7794" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-01.png 450w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-01-196x300.png 196w" sizes="(max-width: 450px) 100vw, 450px" /></a><br />
The severity levels are these. (Both screenshots are from <a href="https://en.wikipedia.org/wiki/Syslog" rel="noopener noreferrer" target="_blank">Wikipedia</a>).<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-02.png" alt="" width="958" height="399" class="aligncenter size-full wp-image-7795" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-02.png 958w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-02-300x125.png 300w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-02-768x320.png 768w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-02-585x244.png 585w" sizes="(max-width: 958px) 100vw, 958px" /></a></p>
<h1>RHEL 7 rsyslog servers</h1>
<p>RHEL 7 comes with <strong>rsyslog </strong>installed by default. Make sure it&#8217;s running.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl status rsyslog
</pre>
<p>The configuration file is <strong>/etc/rsyslog.conf</strong>. Make sure that these lines are uncommented. They tell the <strong>rsyslog </strong>daemon to accept TCP and UDP connections.</p>
<pre class="brush: bash; title: ; notranslate">
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
</pre>
<p>If you make changes in <strong>/etc/rsyslog.conf</strong>, make sure you verify the config.</p>
<pre class="brush: bash; title: ; notranslate">
rsyslogd -N 1
</pre>
<p>If you make a change, you&#8217;ll have to restart the <strong>rsyslog </strong>daemon.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart rsyslog
</pre>
<p>To test if <strong>rsyslog </strong>works fine, try a test.</p>
<pre class="brush: bash; title: ; notranslate">
logger -p local0.notice -t from_cmd_line &quot;Test Message&quot;
</pre>
<p>If you check the <strong>/var/log/messages</strong>, a file where by default <strong>rsyslog </strong>writes the output, you&#8217;ll see the message.</p>
<pre class="brush: bash; title: ; notranslate">
tail /var/log/messages
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-03.png" alt="" width="562" height="48" class="aligncenter size-full wp-image-7796" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-03.png 562w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-03-300x26.png 300w" sizes="(max-width: 562px) 100vw, 562px" /></a><br />
OK, so we didn&#8217;t have to make any changes on both RHEL servers. Let&#8217;s move to the clients.<br />
NOTE: If you have firewalld enabled, you&#8217;ll have to open the ports for the clients.</p>
<pre class="brush: bash; title: ; notranslate">
firewall-cmd --permanent --zone=public --add-port=514/tcp
firewall-cmd --permanent --zone=public --add-port=514/udp
firewall-cmd --reload
</pre>
<h1>AWS Linux, RHEL 6, CentOS 6</h1>
<p>AWS Linux is based on RHEL 6 so the instructions will apply for all of them. Check if <strong>rsyslog </strong>is running.</p>
<pre class="brush: bash; title: ; notranslate">
service rsyslog status
</pre>
<p>Edit <strong>/etc/rsyslog.conf</strong> and make sure these lines are commented. We don&#8217;t want a server, we want a client. </p>
<pre class="brush: bash; title: ; notranslate">
# Provides UDP syslog reception
#$ModLoad imudp
#$UDPServerRun 514

# Provides TCP syslog reception
#$ModLoad imtcp
#$InputTCPServerRun 514
</pre>
<p>Add these lines (11 to 14) somewhere at the end.</p>
<pre class="brush: bash; highlight: [11,12,13,14]; title: ; notranslate">
#$WorkDirectory /var/lib/rsyslog # where to place spool files
#$ActionQueueFileName fwdRule1 # unique name prefix for spool files
#$ActionQueueMaxDiskSpace 1g   # 1gb space limit (use as much as possible)
#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown
#$ActionQueueType LinkedList   # run asynchronously
#$ActionResumeRetryCount -1    # infinite retries if host is down
# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional
#*.* @@remote-host:514
# ### end of the forwarding rule ###

*.*     @@10.0.0.170
$ActionExecOnlyWhenPreviousIsSuspended on
&amp; @@10.0.0.225
$ActionExecOnlyWhenPreviousIsSuspended off

# Finally include all config files in /etc/rsyslog.d. This allows overrides
# of the default configuration above.
$IncludeConfig /etc/rsyslog.d/*.conf
</pre>
<p>These four lines means that my primary <strong>rsyslog </strong>server has an IP of <strong>10.0.0.170</strong> and in case it&#8217;s not reachable, use the server <strong>10.0.0.225</strong>. Line 11 tells the <strong>rsyslog </strong>client to log everything to the server. If you want only certain messages logged, than you can change it, e.g. instead of <strong>*.* @@10.0.0.170</strong> you can use something like <strong>*.info @@10.0.0.170</strong> or <strong>*.info;auth.err @@10.0.0.170</strong>. Look at those two tables above. If you run this command on the client.</p>
<pre class="brush: bash; title: ; notranslate">
logger -p local0.notice -t from_aws_linux &quot;Test Message&quot;
</pre>
<p>and do</p>
<pre class="brush: bash; title: ; notranslate">
tail -f /var/log/messages
</pre>
<p>on the server, you&#8217;ll see the message on the server, not on the client.</p>
<h1>FreeBSD</h1>
<p>FreeBSD uses the old <strong>syslog</strong>, not <strong>rsyslog</strong>, but we can still redirect the logs to our RHEL servers. Edit <strong>/etc/syslog.conf</strong> and all the way at the end add this line.</p>
<pre class="brush: bash; title: ; notranslate">
*.* @10.0.0.170
</pre>
<p>As you can see, <strong>syslog </strong>uses one @, not two @@s. Restart the service and send a test message. You&#8217;ll see that the message goes to the RHEL server now.</p>
<pre class="brush: bash; title: ; notranslate">
service syslogd restart
logger -p local0.notice -t from_FreeBSD &quot;Test Message&quot;
</pre>
<h1>Windows</h1>
<p>Go to this <a href="http://www.rsyslog.com/windows-agent/" rel="noopener noreferrer" target="_blank">link </a>and download the rsyslog client. You can see the link for the download and also for the manual.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-04.png" alt="" width="724" height="290" class="aligncenter size-full wp-image-7797" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-04.png 724w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-04-300x120.png 300w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-04-585x234.png 585w" sizes="(max-width: 724px) 100vw, 724px" /></a><br />
The <strong>rsyslog </strong>agent for Windows is very detailed and requires some studying. Use the manual, there are some examples there. I&#8217;ll show you how to forward the <strong>event ID 7036</strong>. This event gets triggered when a service changes its state. So, download the client and open up the GUI. Expand the following and click on <strong>Rsyslog</strong>. Enter the primary and secondary rsyslog server&#8217;s IPs. Click <strong>Save </strong>in the upper left corner and then click <strong>Restart</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-05.png" alt="" width="990" height="646" class="aligncenter size-full wp-image-7798" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-05.png 990w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-05-300x196.png 300w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-05-768x501.png 768w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-05-585x382.png 585w" sizes="(max-width: 990px) 100vw, 990px" /></a><br />
If you check the logs on your rsyslog server, you&#8217;ll see a lot of logging going on. Pretty much everything that Windows does. We just want to filter all these logs to a single event ID.<br />
So, in the <strong>Default Rule Set</strong>, click <strong>Filters</strong>, then right-click <strong>AND</strong>, choose <strong>Add Filter, Event Log Monitor</strong> and then <strong>Event ID</strong>. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-06.png" alt="" width="910" height="556" class="aligncenter size-full wp-image-7799" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-06.png 910w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-06-300x183.png 300w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-06-768x469.png 768w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-06-585x357.png 585w" sizes="(max-width: 910px) 100vw, 910px" /></a><br />
Enter the Event ID <strong>7036</strong>, click <strong>Save </strong>and <strong>Restart</strong>. </p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-07.png" alt="" width="351" height="470" class="aligncenter size-full wp-image-7800" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-07.png 351w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-07-224x300.png 224w" sizes="(max-width: 351px) 100vw, 351px" /></a><br />
Now, go to <strong>Services </strong>(services.msc) and restart <strong>Windows Update </strong>service. You should see this on the rsyslog server.</p>
<p><a href="https://blog.andreev.it/wp-content/uploads/2017/12/P095-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/12/P095-08.png" alt="" width="565" height="75" class="aligncenter size-full wp-image-7801" srcset="https://blog.andreev.it/wp-content/uploads/2017/12/P095-08.png 565w, https://blog.andreev.it/wp-content/uploads/2017/12/P095-08-300x40.png 300w" sizes="(max-width: 565px) 100vw, 565px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2017/12/118-linux-freebsd-windows-rsyslog-server-client/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>FreeBSD: Install nginx &#8211; virtual hosts, PHP, MySQL and WordPress</title>
		<link>https://blog.andreev.it/2017/01/107-freebsd-install-nginx-virtual-hosts-php-mysql-wordpress/</link>
					<comments>https://blog.andreev.it/2017/01/107-freebsd-install-nginx-virtual-hosts-php-mysql-wordpress/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 29 Jan 2017 15:40:02 +0000</pubDate>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[freebsd]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[virtual hosts]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=3030</guid>

					<description><![CDATA[I&#8217;ve decided to play with nginx to see how different is from Apache. The&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I&#8217;ve decided to play with nginx to see how different is from Apache. The best way to experiment is to have an end goal, e.g. a working WordPress site. I will be using FreeBSD 11.0 and for that  I&#8217;ve created a public server in AWS cloud. The hostname for my server is <strong>test.iandreev.com</strong> and I also have 4 different hostnames that point to the same IP (test1, test2, test3 and test4).<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/01/P085-01.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/01/P085-01.png" alt="" width="1068" height="214" class="aligncenter size-full wp-image-7638" srcset="https://blog.andreev.it/wp-content/uploads/2017/01/P085-01.png 1068w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-01-300x60.png 300w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-01-1024x205.png 1024w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-01-768x154.png 768w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-01-585x117.png 585w" sizes="(max-width: 1068px) 100vw, 1068px" /></a></p>
<h1>Installation</h1>
<p>To install nginx, type:</p>
<pre class="brush: bash; title: ; notranslate">
pkg install nginx
</pre>
<p>Make sure it starts at boot by adding <strong>nginx_enable=&#8221;YES&#8221;</strong> in <strong>/etc/rc.conf</strong>.<br />
To see the version, type:</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
nginx -v
nginx version: nginx/1.10.2
</pre>
<p>To see the modules that were installed with the package, type:</p>
<pre class="brush: bash; title: ; notranslate">
nginx -V
</pre>
<p>You can start and stop the service with the standard <strong>service </strong>command. When making changes in the config file, use reload, e.g. <strong>service nginx reload</strong>.<br />
By default, nginx creates the log files under <strong>/var/log/nginx</strong>. There are two files, <strong>access.log</strong> and <strong>error.log</strong>. The config files are under <strong>/usr/local/etc/nginx</strong>. The main config file is <strong>nginx.conf</strong>.<br />
Let&#8217;s start the nginx.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
service nginx start
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
Starting nginx.
</pre>
<p>If everything is OK, you can <strong>telnet localhost 80</strong>. Type something and hit ENTER and you&#8217;ll see a response. </p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
asdf
HTTP/1.1 400 Bad Request
Server: nginx/1.10.2
Date: Sun, 29 Jan 2017 13:56:04 GMT
Content-Type: text/html
Content-Length: 173
Connection: close

&lt;html&gt;
&lt;head&gt;&lt;title&gt;400 Bad Request&lt;/title&gt;&lt;/head&gt;
&lt;body bgcolor=&quot;white&quot;&gt;
&lt;center&gt;&lt;h1&gt;400 Bad Request&lt;/h1&gt;&lt;/center&gt;
&lt;hr&gt;&lt;center&gt;nginx/1.10.2&lt;/center&gt;
&lt;/body&gt;
&lt;/html&gt;
Connection closed by foreign host.
</pre>
<p>Check the nginx process.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
ps -waux | grep nginx
root     778   0.0  0.7 29640 6984  -  Is   13:55    0:00.00 nginx: master process /usr/local/sbin/nginx
www      779   0.0  0.7 29640 7452  -  I    13:55    0:00.00 nginx: worker process (nginx)
</pre>
<p>As you can see the master process runs as root, but then it forks the connections to the www user.</p>
<h1>Single host</h1>
<p>This is the easiest setup. You don&#8217;t have to do anything except the steps above. nginx works right out of the box with the default configuration. Go to http://server_IP_or_hostname and you&#8217;ll see the welcome page.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/01/P085-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/01/P085-02.png" alt="" width="555" height="227" class="aligncenter size-full wp-image-7639" srcset="https://blog.andreev.it/wp-content/uploads/2017/01/P085-02.png 555w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-02-300x123.png 300w" sizes="(max-width: 555px) 100vw, 555px" /></a><br />
But, this scenario has no real use, so we&#8217;ll create two virtual hosts, test1 and test2.</p>
<h1>Virtual hosts</h1>
<p>First, we&#8217;ll create the two directories for the virtual hosts and put some index files there. I use the same root directory as Apache. Make sure that the locations of the virtual hosts are owned by the user <strong>www </strong>and group <strong>www</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/www
mkdir test1.iandreev.com
mkdir test2.iandreev.com
echo &quot;test1&quot; &gt; test1.iandreev.com/index.htm
echo &quot;test2&quot; &gt; test2.iandreev.com/index.htm
chown -R www:www test*
</pre>
<p>Now, we have to edit the main config file and tell nginx where to look for these sites.<br />
Go to <strong>/usr/local/etc/nginx/</strong> and edit <strong>nginx.conf</strong>. Change the values for <strong>worker_processes</strong> from 1 to auto and uncomment <strong>gzip on</strong> directive. See what worker_processes mean <a href="http://nginx.org/en/docs/ngx_core_module.html#worker_processes" target="_blank" rel="noopener noreferrer">here</a>. By uncommenting gzip directive, you are enabling compression on the pages. To test if your web server serves compressed pages, check <a href="http://www.whatsmyip.org/http-compression-test/" target="_blank" rel="noopener noreferrer">this </a>website.<br />
Next, we have to add our two virtual hosts. Scroll all the way down, just before the last accolade &#8220;}&#8221; and add these lines.</p>
<pre class="brush: bash; title: ; notranslate">
    server {
        access_log /var/log/nginx/test1.iandreev.access.log;
        error_log  /var/log/nginx/test1.iandreev.error.log;
        listen 80;
        server_name     test1.iandreev.com;
        location / {
            root /usr/local/www/test1.iandreev.com;
            index index.htm index.html;
        }
    }
    server {
        access_log /var/log/nginx/test2.iandreev.access.log;
        error_log  /var/log/nginx/test2.iandreev.error.log;
        listen 80;
        server_name test2.iandreev.com;
        location / {
            root /usr/local/www/test2.iandreev.com;
            index index.htm index.html;
        }
    }
</pre>
<p>Reload the config with:</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
service nginx reload
Performing sanity check on nginx configuration:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
</pre>
<p>and make sure everything is OK.<br />
If everything is OK, you should be able to browse to your virtual sites.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/01/P085-03.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/01/P085-03.png" alt="" width="298" height="166" class="aligncenter size-full wp-image-7640" /></a><br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/01/P085-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/01/P085-04.png" alt="" width="289" height="226" class="aligncenter size-full wp-image-7641" /></a></p>
<p>If you check one of the error logs, you&#8217;ll see an error that favicon.ico is missing for the site. You can ignore this as it&#8217;s not an error, it&#8217;s just a warning that you don&#8217;t have a favicon for your site.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
tail test2.iandreev.error.log
2017/01/29 14:18:59 &#x5B;error] 838#100084: *4 open() &quot;/usr/local/www/test2.iandreev.com/favicon.ico&quot; failed (2: No such file or directory), client: 240.14.17.24, server: test2.iandreev.com, request: &quot;GET /favicon.ico HTTP/1.1&quot;, host: &quot;test2.iandreev.com&quot;
</pre>
<p>You can get a favicon icon from <a href="http://www.freefavicon.com/freefavicons/objects/" target="_blank" rel="noopener noreferrer">this </a>website or you can generate one from <a href="http://www.favicon-generator.org/" target="_blank" rel="noopener noreferrer">this </a>one.</p>
<h1>nginx and PHP</h1>
<p>Unlike Apache and the php module, nginx is using PHP-FPM as a proxy to requests PHP dynamic code over FCGI protocol. PHP-FPM comes bundled with PHP, so let&#8217;s install php 5.6.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install php56
</pre>
<p>Add this line in <strong>/etc/rc.conf</strong> so PHP-FPM starts on boot.</p>
<pre class="brush: bash; title: ; notranslate">
php_fpm_enable=&quot;YES&quot;
</pre>
<p>Create the <strong>php.ini</strong> file from <strong>php.ini-production</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
</pre>
<p>Now, edit <strong>/usr/local/etc/php-fpm.conf</strong> and make these changes. Replace <strong>listen = 127.0.0.1:9000</strong> with <strong>listen = /var/run/php-fpm.sock</strong>. In addition, uncomment these three lines.</p>
<pre class="brush: bash; title: ; notranslate">
listen.owner = www
listen.group = www
listen.mode = 0660
</pre>
<p>Finally, start the php-fpm service.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
service php-fpm start
Performing sanity check on php-fpm configuration:
&#x5B;28-Jan-2017 23:41:31] NOTICE: configuration file /usr/local/etc/php-fpm.conf test is successful
</pre>
<p>Let&#8217;s create a test website that will serve PHP content.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/www
mkdir test3.iandreev.com
echo &quot;&lt;?php phpinfo(); ?&gt;&quot; &gt; test3.iandreev.com/index.php
chown -R www:www test3.iandreev.com
</pre>
<p>Add a new virtual host in nginx.</p>
<pre class="brush: bash; title: ; notranslate">
server {
        access_log /var/log/nginx/test3.iandreev.access.log;
        error_log  /var/log/nginx/test3.iandreev.error.log;
        listen       80;
        server_name  test3.iandreev.com;
        root /usr/local/www/test3.iandreev.com;
        index index.php index.html index.htm;
        location / {
            try_files $uri $uri/ =404;
        }
        error_page      500 502 503 504  /50x.html;
        location = /50x.html {
            root /usr/local/www/nginx-dist;
        }
        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                include fastcgi_params;
        }
    }
</pre>
<p>and reload the config changes.</p>
<pre class="brush: bash; title: ; notranslate">
service nginx reload
</pre>
<p>Go to your new virtual host, in my case http://test3.iandreev.com and you should see this.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/01/P085-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/01/P085-05.png" alt="" width="1204" height="514" class="aligncenter size-full wp-image-7642" srcset="https://blog.andreev.it/wp-content/uploads/2017/01/P085-05.png 1204w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-05-300x128.png 300w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-05-1024x437.png 1024w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-05-768x328.png 768w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-05-1170x499.png 1170w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-05-585x250.png 585w" sizes="(max-width: 1204px) 100vw, 1204px" /></a></p>
<h1>nginx and WordPress</h1>
<p>Now that we have PHP support we can create a WordPress site. We&#8217;ll use MySQL as a DB backend. Please see my other <a href="https://blog.andreev.it/?p=1309#MySQL" target="_blank" rel="noopener noreferrer">post </a>on how to install MySQL first.<br />
Once you have the MySQL installed, create the database. Replace the values of <strong>wordpress</strong>, <strong>wpuser </strong>and <strong>secret </strong>to suit your needs.</p>
<pre class="brush: sql; title: ; notranslate">
CREATE DATABASE wordpress;
GRANT ALL PRIVILEGES ON wordpress.* TO &quot;wpuser&quot;@&quot;localhost&quot; IDENTIFIED BY &quot;secret&quot;;
FLUSH PRIVILEGES;
QUIT;
</pre>
<p>Install the following php modules, otherwise when you start WordPress you&#8217;ll be presented with a blank page.</p>
<pre class="brush: bash; title: ; notranslate">
pkg install php56-extensions php56-mysql php56-mysqli php56-xml php56-hash php56-gd php56-curl php56-tokenizer php56-zlib php56-zip
</pre>
<p>Download the latest WordPress install. If you don&#8217;t have wget, install it first with <strong>pkg install wget</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/local/www
wget www.wordpress.org/latest.zip --no-check-certificate
unzip latest.zip
mv wordpress test4.iandreev.com
chown -R www:www test4.iandreev.com
rm latest.zip
</pre>
<p>Add the following in nginx.conf to create the virtual host for the WordPress site.</p>
<pre class="brush: bash; title: ; notranslate">
server {
        access_log /var/log/nginx/test4.iandreev.access.log;
        error_log  /var/log/nginx/test4.iandreev.error.log;
        listen       80;
        server_name  test4.iandreev.com;
        root /usr/local/www/test4.iandreev.com;
        index index.php index.html index.htm;
        location / {
            try_files $uri $uri/ =404;
        }
        error_page      500 502 503 504  /50x.html;
        location = /50x.html {
            root /usr/local/www/nginx-dist;
        }
        location ~ \.php$ {
                try_files $uri =404;
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME $request_filename;
                include fastcgi_params;
        }
    }
</pre>
<p>Reload the config and restart php-fpm service.</p>
<pre class="brush: bash; title: ; notranslate">
service nginx reload
service php-fpm restart
</pre>
<p>Go to your website and you&#8217;ll be presented with the WordPress install page.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2017/01/P085-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2017/01/P085-06.png" alt="" width="574" height="823" class="aligncenter size-full wp-image-7643" srcset="https://blog.andreev.it/wp-content/uploads/2017/01/P085-06.png 574w, https://blog.andreev.it/wp-content/uploads/2017/01/P085-06-209x300.png 209w" sizes="(max-width: 574px) 100vw, 574px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2017/01/107-freebsd-install-nginx-virtual-hosts-php-mysql-wordpress/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
