<?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>Ubuntu &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/category/ubuntu/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Mon, 08 Feb 2021 17:04:37 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<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 fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2021/01/P153-02.png" alt="" width="983" height="227" class="aligncenter size-full wp-image-8802" srcset="https://blog.andreev.it/wp-content/uploads/2021/01/P153-02.png 983w, https://blog.andreev.it/wp-content/uploads/2021/01/P153-02-300x69.png 300w, https://blog.andreev.it/wp-content/uploads/2021/01/P153-02-768x177.png 768w, https://blog.andreev.it/wp-content/uploads/2021/01/P153-02-585x135.png 585w" sizes="(max-width: 983px) 100vw, 983px" /></a></p>
<h1>Service handlers</h1>
<p>Service handlers are used only when a change is made on the managed node. For example, we can restart a service only if the config file was changed. If the file is not changed, then there is no need to restart. Here is an example of a service handler. We&#8217;ll restart postfix service only if the main.cf file was changed.</p>
<pre class="brush: yaml; highlight: [11,14]; title: ; notranslate">
# service-handler.yml
---
- hosts: centos
  become: yes
  tasks:
  - name: Configure main.cf
    lineinfile:
      path: /etc/postfix/main.cf
      regexp: ^#mydomain
      line: 'mydomain = example.com'
    notify: restart postfix

  handlers:
  - name: restart postfix
    service: name=postfix state=restarted
</pre>
<p>Make sure that the name for the handler is the same (lines 11 and 14), so Ansible knows what service handlers is referred. </p>
<h1>Variables</h1>
<p>When ansible runs a playbook on a managed node, the first task is to gather info about the managed node. The info is a bunch of settings that we can use in our playbooks. For example, if you execute the following command, you can see the IP address, the CPU model, python version etc.</p>
<pre class="brush: bash; title: ; notranslate">
ansible -m setup &lt;node&gt;
</pre>
<p>We can use these settings and use them as variables if we need them. For example, this playbook displays the hostname and the IP.</p>
<pre class="brush: yaml; title: ; notranslate">
# showip.yml
---
  - hosts: freebsd
    become: yes
    tasks:
      - name: Show the IP address
        debug:
          msg: &quot;The hostname is {{ inventory_hostname}}  and the IP is {{ansible_default_ipv4.address }}&quot;
</pre>
<p>And if you run the playbook, you&#8217;ll see something like this.</p>
<pre class="brush: plain; title: ; notranslate">
TASK &#x5B;Show the IP address] *********************************************************************************************
ok: &#x5B;node1.andreev.local] =&gt; {
    &quot;msg&quot;: &quot;The hostname is node1.andreev.local  and the IP is 192.168.1.211&quot;
}
</pre>
<p>Here is another example of using variables. In this case, we&#8217;ll specify a file and change the ownership and the mode.</p>
<pre class="brush: yaml; title: ; notranslate">
# owner.yml
---
  - hosts: centos
    become: yes
    vars:
      filename: &quot;/var/www/html/index.php&quot;
    tasks:
      - name: Change the owner of the file
        file:
          path: &quot;{{ filename }}&quot;
          owner: apache
          group: apache
          mode: '0755'
</pre>
<p>In case we want to assign an output to a variable, we&#8217;ll have to use the keyword <strong>register</strong>. Here is an example of how to get the output from a command and print it on the screen with the keyword <strong>debug</strong>.</p>
<pre class="brush: yaml; title: ; notranslate">
# variables.yml
---
  - hosts: freebsd

    tasks:
    - name: Get the uptime manually
      command: uptime
      register: var_uptime

    - name: Print the uptime
      debug:
        msg: The uptime is &quot;{{ var_uptime }}&quot;
</pre>
<h1>Roles</h1>
<p>Roles let you automatically load related vars_files, tasks, handlers, and other Ansible artifacts based on a known file structure. Once you group your content in roles, you can easily reuse them and share them with other users. The idea is to separate the tasks, handlers and vars in different files. Let&#8217;s see this playbook for example. It changes a line in main.cf file, restarts postfix and copies a file under the postfix main directory.</p>
<pre class="brush: yaml; title: ; notranslate">
# roles.yml
---
  - hosts: centos
    become: yes

    vars:
      filevd: &quot;/etc/postfix/virtual_domains&quot;
      cfgpostfix: &quot;/etc/postfix/main.cf&quot;


    tasks:
    - name: Configure main.cf
      lineinfile:
        path: &quot;{{ cfgpostfix }}&quot;
        regexp: ^#mydomain
        line: 'mydomain = example.com'
      notify: restart postfix
    - name: Copy virtual_domains
      copy:
        src: ../files/virtual_domains
        dest: &quot;{{ filevd }}&quot;
        mode: 0755

    handlers:
    - name: restart postfix
      service: name=postfix state=restarted
</pre>
<p>We can rewrite this file by separating the tasks, variables, files and handlers. Run this command.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-galaxy role init postfix
</pre>
<p>If you look at the file/directory structure of the newly created directory postfix, it looks like this.</p>
<pre class="brush: plain; highlight: [1]; title: ; notranslate">
tree postfix
postfix
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml
</pre>
<p>Create a file <strong>virtual_domains</strong> under the <strong>files </strong>directory.</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;mydomain.com&quot; &gt; postfix/files/virtual_domains
</pre>
<p>Move the config for vars, handlers and tasks in the separate <strong>main.yml</strong> files. For example, this is how my files look like.<br />
<strong>postfix/vars/main.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
---
# vars file for postfix

  filevd: &quot;/etc/postfix/virtual_domains&quot;
  cfgpostfix: &quot;/etc/postfix/main.cf&quot;
</pre>
<p>As you can see the keyword <strong>vars:</strong> does not exists. Ansible knows that this file is for <strong>vars </strong>so there is no need to enter the <strong>vars </strong>keyboard.<br />
<strong>postfix/tasks/main.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
---
# tasks file for postfix

  - name: Configure main.cf
    lineinfile:
      path: &quot;{{ cfgpostfix }}&quot;
      regexp: ^#mydomain
      line: 'mydomain = example.com'
    notify: restart postfix
  - name: Copy virtual_domains
    copy:
      src: ../files/virtual_domains
      dest: &quot;{{ filevd }}&quot;
      mode: 0755
</pre>
<p><strong>postfix/handlers/main.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
---
# handlers file for postfix

  - name: restart postfix
    service: name=postfix state=restarted
</pre>
<p>Finally, create a file called something.yml that will be your main file. This file has to be outside the postfix directory structure.<br />
In my case it looks like this.<br />
<strong>something.yml</strong></p>
<pre class="brush: yaml; title: ; notranslate">
# something.yml
---
  - hosts: centos
    become: yes
    roles:
      - postfix
</pre>
<p>Now, if you execute this playbook, ansible will automatically execute the rest of the dependant playbooks as well.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook something.yml
</pre>
<h1>Error handling</h1>
<p>Sometimes we want certain changes to be ignored. Sometimes, we know the behavior of certain commands and we know that they might return non-zero code and we want that ignored. For example, consider this part of a playbook.</p>
<pre class="brush: yaml; title: ; notranslate">
- hosts: centos
  tasks: 
  - name: Type something that will fail
    command: thiscommanddoesntexist
    ignore_errors: yes

  - name: Run command remotely
    command: /usr/local/bin/somecommand
    register: cmd_result
    changed_when: cmd_result == 2
</pre>
<p>Ansible would report a task as changed as long as the command (or) script gives zero return code.<br />
In the first part, we know that the task will fail, but we decide to ignore it using the keyword <strong>ignore_errors</strong>. No matter what the command returns, <strong>ignore_errors: yes</strong> will never report to ansible that the command failed.<br />
In the second command we can ignore the error based on the output of the command. For example, if the output is 2, the the error will be ignored. If cmd_result is not equal to 2, the task will be marked as changed.<br />
So whenever this condition is true, the task will be marked as changed. </p>
<h1>Tags</h1>
<p>Tags are used when you have a playbook with several tasks and you need to run only specific parts of it instead of running the entire playbook. You use tags to execute or skip selected tasks. Let&#8217;s say we have this playbook that installs Docker on Centos and has multiple tasks. As you can notice in lines 12, 24, 37 and 45 we have a new line with a keyword <strong>tags</strong> that we use to tag certain tasks. The purpose of this is to include or exclude these tasks from the playbook.</p>
<pre class="brush: yaml; highlight: [12,24,37,45]; title: ; notranslate">
# centos-docker.yml
---
- name: Install docker
  hosts: centos
  become: true

  tasks:
    - name: Install yum utils
      yum:
        name: yum-utils
        state: latest
      tags: install

    - name: Install device-mapper-persistent-data
      yum:
        name: device-mapper-persistent-data
        state: latest
      tags: install

    - name: Install lvm2
      yum:
        name: lvm2
        state: latest
      tags: install

    - name: Add Docker repo
      get_url:
        url: https://download.docker.com/linux/centos/docker-ce.repo
        dest: /etc/yum.repos.d/docer-ce.repo
      become: yes

    - name: Install Docker
      package:
        name: docker-ce
        state: latest
      become: yes
      tags: install

    - name: Start Docker service
      service:
        name: docker
        state: started
        enabled: yes
      become: yes
      tags: start
</pre>
<p>Now, with the command below, we can execute the playbook and only the tasks tagged with <strong>install </strong>will be executed.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook centos-docker.yaml --tags install
</pre>
<p>We can also tell ansible to NOT run those tasks tagged with <strong>install</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook centos-docker.yaml --skip-tags install
</pre>
<p>You can add multiple tags per task, e.g.</p>
<pre class="brush: yaml; title: ; notranslate">
tags:
  - cleanup_app
  - cleanup_web
</pre>
<p>Ansible reserves two tag names for special behavior: <strong>always </strong>and <strong>never</strong>. If you assign the <strong>always </strong>tag to a task or play, Ansible will always run that task or play, unless you specifically skip it (<strong>&#8211;skip-tags always</strong>). If you assign the <strong>never </strong>tag to a task or play, Ansible will skip that task or play unless you specifically request it (<strong>&#8211;tags never</strong>).</p>
<h1>Ansible Vault</h1>
<p>Ansible Vault encrypts variables and files so you can protect sensitive content such as passwords or keys rather than leaving it visible as plaintext in playbooks or roles.<br />
First, you have to create a vaulted file where we&#8217;ll store the passwords. When you run this command it will ask you to create a password and then an empty file will show up.</p>
<pre class="brush: bash; title: ; notranslate">
ansible-vault create secrets.yml
</pre>
<p>Add some passwords there and save the file.</p>
<pre class="brush: bash; title: ; notranslate">
mysql_pwd: &quot;DifficultPassword&quot;
ht_pwd: &quot;PasswordXYZ&quot;
</pre>
<p>If you look at the file now, you&#8217;ll see that it&#8217;s encrypted and you can&#8217;t see the passwords anymore.<br />
If you want to edit the file do <strong>ansible-vault edit secrets.yaml</strong> and enter the vault password.<br />
Create a small playbook that displays the password.</p>
<pre class="brush: yaml; title: ; notranslate">
# centos-vault.yml
---
- hosts: centos
  vars_files:
    - secrets.yml

  tasks:
  - name: Show mysql pwd
    debug:
      msg: &quot;{{ mysql_pwd }}&quot;
</pre>
<p>If you run the playbook now, ansible will throw an error saying ERROR! Attempting to decrypt but no vault secrets found. You have to specify the parameter <strong>&#8211;ask-vault-pass</strong> and enter the vault password when prompted.</p>
<h1>Prompts</h1>
<p>In case you need to pause the playbook execution and ask the user for some input such as confirmation or password, use prompts.<br />
If you want the output to echo, use <strong>private: no</strong>, otherwise what you type won&#8217;t show up on the screen. Here is an example of a playbook that asks you to confirm if a file needs to be copied to the node. If you type <strong>yes</strong> and hit enter, the file will be copied, otherwise it won&#8217;t.</p>
<pre class="brush: yaml; title: ; notranslate">
# centos-prompt.yml
---
- hosts: centos
  become: yes

  vars_prompt:
    name: upload
    private: no
    prompt: &quot;Do you want to upload xyz.txt?&quot;

  tasks:
  - name: Upload xyz.txt
    copy:
      src: xyz.txt
      dest: /var/log
    when: upload == &quot;yes&quot;
</pre>
<h1>Useful options</h1>
<pre class="brush: bash; title: ; notranslate">
ansible-playbook &lt;name&gt; --syntax-check # checks the syntax of the playbook
ansible-playbook &lt;name&gt; --check # does a dry run, reports the will-be changes, but the playbook is not executed
ansible-playbook &lt;name&gt; --step # ask to confirm each-step
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2021/02/ansible-quick-start-guide-for-freebsd-centos-and-ubuntu/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>General: Relay client e-mails using SASL and TLS in postfix</title>
		<link>https://blog.andreev.it/2018/03/124-postfix-relay-client-e-mails-using-sasl-and-tls/</link>
					<comments>https://blog.andreev.it/2018/03/124-postfix-relay-client-e-mails-using-sasl-and-tls/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Sun, 11 Mar 2018 03:20:33 +0000</pubDate>
				<category><![CDATA[CentOS]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[OpenBSD]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[e-mail]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[relay]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=3729</guid>

					<description><![CDATA[I have a bunch of test CentOS/FreeBSD servers and I wanted to get all&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I have a bunch of test CentOS/FreeBSD servers and I wanted to get all the notifications sent to my e-mail instead of logging to each server and check the status of each one of them. Some of my servers are behind my home network where outbound port 25 (SMTP) is blocked by the ISP. So, I decided to use my main postfix server which is already configured to use port 587 for SMTP using TLS. In this post, I&#8217;ll explain how I configured my test servers to relay e-mails.<br />
Use the following links to see how I configured the postfix main server for <a href="https://blog.andreev.it/?p=1975" rel="noopener noreferrer" target="_blank">CentOS </a>and <a href="https://blog.andreev.it/?p=1604" rel="noopener noreferrer" target="_blank">FreeBSD</a>. </p>
<h1>CentOS 7</h1>
<p>There are some prerequisites for CentOS 7. It comes with postfix installed and it has built-in Cyrus SASL already, but we need another Cyrus SASL package for login support. In addition, CentOS doesn&#8217;t come up with the mail command, so we have to install that as well.</p>
<h2>Prerequisites</h2>
<p>Install Cyrus SASL package and the mail client.</p>
<pre class="brush: bash; title: ; notranslate">
yum install cyrus-sasl-plain mailx
</pre>
<h2>postfix main config file</h2>
<p>Edit <strong>/etc/postfix/main.cf</strong> and add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
relayhost = &#x5B;server.domain.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_use_tls = yes
smtp_tls_CAfile = /etc/ssl/certs/server.domain.com.crt
</pre>
<p>The first line is your main postfix server that will receive the e-mail from the client servers, the 4th line is the file where you are going to store the username and password for the user that&#8217;s able to login to the main postfix server and the 6th line is the certificate of the main postfix server. </p>
<h2>SASL Authentication</h2>
<p>Edit <strong>/etc/postfix/sasl_passwd</strong> and add this line.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;server.domain.com]:587 mail@domain.com:YourPassword
</pre>
<p>You have to specify your main postfix server, the username and the password for a valid user that&#8217;s able to login to that server and receive e-mails. Once completed, execute postmap.</p>
<pre class="brush: bash; title: ; notranslate">
postmap /etc/postfix/sasl_passwd
</pre>
<h2>e-mails to relay</h2>
<p>I wanted to send all of my root e-mails to my main server, so what you have to do is edit <strong>/etc/aliases</strong> and scroll all the way down at the bottom. Un-comment the root line and specify where do you want your root emails to be forwarded.</p>
<pre class="brush: bash; title: ; notranslate">
root: mail@domain.com
</pre>
<p>If you have some cron jobs that run under some other username, specify them in this file, e.g. someuser: some-email@email.com.<br />
After you are done, type newaliases.</p>
<pre class="brush: bash; title: ; notranslate">
newaliases
</pre>
<h2>Public certificate</h2>
<p>You will also need the public certificate of your e-mail server. Get the certificate in a PEM format and paste it into a new file <strong>/etc/ssl/certs/server.domain.com.crt</strong>. Or, in my case, I have a wildcard certificate for my domain, so I can get it using this command.</p>
<pre class="brush: bash; title: ; notranslate">
openssl s_client -connect server.domain.com:443 &lt; /dev/null | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' &gt; /etc/ssl/certs/server.domain.com.crt
</pre>
<h2>Final step</h2>
<p>Restart the postfix server on the client server, send a test e-mail and check the result.</p>
<pre class="brush: bash; title: ; notranslate">
systemctl restart postfix
echo &quot;This is a test.&quot; | mail -s &quot;Test e-mail&quot; root
tail /var/log/maillog
</pre>
<h1>FreeBSD 11</h1>
<p>Unlike CentOS, FreeBSD doesn&#8217;t come up with postfix, instead it uses sendmail. So, we have to remove sendmail, install postfix and follow similar config as with CentOS.</p>
<h2>Prerequisites</h2>
<p>We have to install postfix from the ports because it doesn&#8217;t come up with Cyrus SASL. It comes with dovecot SASL, but I am not sure if it works in a client config. On the other hand, FreeBSD comes with mail installed. Install the postfix port, not the package. </p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/ports
</pre>
<p>If you get an error that there is no such file or directory, get the ports tree. If you can cd to that folder, skip the step below to install the ports tree.</p>
<pre class="brush: bash; title: ; notranslate">
portsnap fetch
portsnap extract
</pre>
<p>Install postfix.</p>
<pre class="brush: bash; title: ; notranslate">
cd /usr/ports/mail/postfix
make all install clear
</pre>
<p>When this dialog box pops-up, select <strong>BDB </strong>and <strong>SASL </strong>as highlighted.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2018/03/P101-01.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P101-01.png" alt="" width="537" height="324" class="aligncenter size-full wp-image-8191" /></a><br />
Execute these lines so you replace sendmail with postfix.</p>
<pre class="brush: bash; title: ; notranslate">
sysrc postfix_enable=&quot;YES&quot;
sysrc sendmail_enable=&quot;NONE&quot;
mv /usr/local/etc/mail/mailer.conf /usr/local/etc/mail/mailer.conf.old
install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf
</pre>
<p>Add the following lines to <strong>/etc/defaults/periodic.conf</strong></p>
<pre class="brush: bash; title: ; notranslate">
daily_clean_hoststat_enable=&quot;NO&quot;
daily_status_mail_rejects_enable=&quot;NO&quot;
daily_status_include_submit_mailq=&quot;NO&quot;
daily_submit_queuerun=&quot;NO&quot;
</pre>
<p>Make sure Cyrus SASL is installed.</p>
<pre class="brush: bash; title: ; notranslate">
postconf -a
</pre>
<p>You should see cyrus and dovecot there.</p>
<h2>postfix main config file</h2>
<p>Edit <strong>/usr/local/etc/postfix/main.cf</strong> and add these lines at the end.</p>
<pre class="brush: bash; title: ; notranslate">
relayhost = &#x5B;server.domain.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/usr/local/etc/postfix/sasl_passwd
smtp_use_tls = yes
smtp_tls_CAfile = /usr/local/etc/ssl/server.domain.com.crt
</pre>
<p>The first line is your main postfix server that will receive the e-mail from the client servers, the 4th line is the file where you are going to store the username and password for the user that’s able to login to the main postfix server and the 6th line is the certificate of the main postfix server.</p>
<h2>SASL Authentication</h2>
<p>Edit <strong>/usr/local/etc/postfix/sasl_passwd</strong> and add this line.</p>
<pre class="brush: bash; title: ; notranslate">
&#x5B;server.domain.com]:587 mail@domain.com:YourPassword
</pre>
<p>You have to specify your main postfix server, the username and the password for a valid user that’s able to login to that server and receive e-mails. Once completed, execute postmap.</p>
<pre class="brush: bash; title: ; notranslate">
postmap /usr/local/etc/postfix/sasl_passwd
</pre>
<h2>e-mails to relay</h2>
<p>I wanted to send all of my root e-mails to my main server, so what you have to do is edit <strong>/etc/aliases</strong> and scroll a little bit way down. Un-comment the root line and specify where do you want your root emails to be forwarded.</p>
<pre class="brush: bash; title: ; notranslate">
root: mail@domain.com
</pre>
<p>If you have some cron jobs that run under some other username, specify them in this file, e.g. <strong>someuser: some-email@email.com.</strong><br />
After you are done, type <strong>newaliases</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
newaliases
</pre>
<h2>Public certificate</h2>
<p>You will also need the public certificate of your e-mail server. Get the certificate in a PEM format and paste it into a new file <strong>/usr/local/etc/ssl/server.domain.com.crt</strong>. Or, in my case, I have a wildcard certificate for my domain, so I can get it using this command.</p>
<pre class="brush: bash; title: ; notranslate">
openssl s_client -connect server.domain.com:443 &lt; /dev/null | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' &gt; /usr/local/etc/ssl/server.domain.com.crt
</pre>
<h2>Final step</h2>
<p>Restart the postfix server on the client server, send a test e-mail and check the result.</p>
<pre class="brush: bash; title: ; notranslate">
service postfix restart
echo &quot;This is a test.&quot; | mail -s &quot;Test e-mail&quot; root
tail /var/log/maillog
</pre>
<p>You will notice that the e-mails that come from FreeBSD are always sent by Charlie Root. If you have multiple FreeBSD boxes, the e-mails from various FreeBSD servers will come as Charlie Root which might be a bit confusing. So do a <strong>chpass </strong>and change the line <strong>Full Name</strong>, so instead of <strong>Full Name: Charlie &#038;</strong>, do something like <strong>Full Name: servername Charlie &#038;</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
chpass
</pre>
<p><a href="https://blog.andreev.it/wp-content/uploads/2018/03/P101-02.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2018/03/P101-02.png" alt="" width="565" height="253" class="aligncenter size-full wp-image-8192" /></a><br />
Do <strong><ESC>:wq</strong> if your default editor is vi to save the changes.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2018/03/124-postfix-relay-client-e-mails-using-sasl-and-tls/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PowerShell, shell: Remove comments from source (Windows/Linux/BSD)</title>
		<link>https://blog.andreev.it/2016/12/103-norem-utility-remove-comments-source/</link>
					<comments>https://blog.andreev.it/2016/12/103-norem-utility-remove-comments-source/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Wed, 14 Dec 2016 15:53:14 +0000</pubDate>
				<category><![CDATA[AIX]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[OpenBSD]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[Unix shell]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[remove comments]]></category>
		<category><![CDATA[sh]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=2990</guid>

					<description><![CDATA[norem for Linux/*BSD A small utility written in Bourne shell (compatible with both sh&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><h1>norem for Linux/*BSD</h1>
<p>A small utility written in Bourne shell (compatible with both <strong>sh </strong>and <strong>bash</strong>, which means works without changes on all *BSD/Linux) that strips comments from a source file. E.g. I am too lazy to scroll through <strong>/etc/ssh/sshd_config</strong> file to look for  any valid directives.<br />
Here is <strong>/etc/ssh/sshd_config</strong> on FreeBSD.</p>
<pre class="brush: plain; collapse: true; light: false; title: ; toolbar: true; notranslate">
#       $OpenBSD: sshd_config,v 1.98 2016/02/17 05:29:04 djm Exp $
#       $FreeBSD: releng/10.3/crypto/openssh/sshd_config 296853 2016-03-14 13:05:13Z des $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

# Note that some of FreeBSD's defaults differ from OpenBSD's, and
# FreeBSD has a few additional options.

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

# The default requires explicit activation of protocol 1
#Protocol 2

# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key
# HostKeys for protocol version 2
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_dsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Lifetime and size of ephemeral version 1 server key
#KeyRegenerationInterval 1h
#ServerKeyBits 1024

# Ciphers and keying
#RekeyLimit default none

# Logging
# obsoletes QuietMode and FascistLogging
#SyslogFacility AUTH
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
#PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#RSAAuthentication yes
#PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#RhostsRSAAuthentication no
# similar for protocol version 2
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# RhostsRSAAuthentication and HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# Change to yes to enable built-in password authentication.
#PasswordAuthentication no
#PermitEmptyPasswords no

# Change to no to disable PAM authentication
#ChallengeResponseAuthentication yes

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

# Set this to 'no' to disable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of &quot;PermitRootLogin without-password&quot;.
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
#UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS yes
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum FreeBSD-20160310

# no default banner path
#Banner none

# override default of no subsystems
Subsystem       sftp    /usr/libexec/sftp-server

# Example of overriding settings on a per-user basis
#Match User anoncvs
#       X11Forwarding no
#       AllowTcpForwarding no
#       PermitTTY no
#       ForceCommand cvs server
</pre>
<p>With this utility, I can just do:</p>
<pre class="brush: bash; title: ; notranslate">
norem -f /etc/ssh/sshd_config
</pre>
<p>&#8230; and voila&#8230;You have the meat without the bones.</p>
<pre class="brush: plain; title: ; notranslate">
Subsystem       sftp    /usr/libexec/sftp-server
</pre>
<p>Almost all *nix utilities have &#8220;#&#8221; as a comment, but some languages such as Java and C++ use &#8220;//&#8221; for comments. In this case, we have to run:</p>
<pre class="brush: bash; title: ; notranslate">
norem -f file -c &quot;/&quot;
</pre>
<p>The utility is not smart enough for multi-line comments such as &#8220;/*&#8230;*/&#8221;<br />
Here is the source:</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/sh

usage()
{
    echo &quot;usage: norem &#x5B;-f file ] | &#x5B;-c char] | &#x5B;-e]] | &#x5B;-h]]&quot;
    echo &quot;Prints a file skipping the lines that start with -c&quot;
    echo &quot;By default empty lines are not printed, use -e yes to include them&quot;
    echo &quot;Kliment Andreev - 2016&quot;
}

if &#x5B; &quot;$#&quot; == &quot;0&quot; ]; then
        usage
        exit 1
fi

while &#x5B; $# -gt 0 ]; do
        key=&quot;$1&quot;

        case $key in
                -f|--file)
                        FILENAME=&quot;$2&quot;
                    shift
                        ;;
        -c|--char)
                        CHARACTER=&quot;$2&quot;
                        shift
                ;;
                -e|--empty)
                EMPTY=&quot;$2&quot;
                shift
                ;;
        *)
                usage
                        exit
                ;;
        esac
        shift
done

if &#x5B; -z &quot;${CHARACTER}&quot; ]; then
        CHARACTER=&quot;#&quot;
fi

if &#x5B; -z &quot;${EMPTY}&quot; ]; then
        cat ${FILENAME} | sed &quot;/^\\${CHARACTER}/d&quot; | awk /./
else
        cat ${FILENAME} |sed &quot;/^\\${CHARACTER}/d&quot;
fi
</pre>
<h1>norem for PowerShell</h1>
<p>The same utility for PowerShell. The input parameters are the same.</p>
<pre class="brush: powershell; title: ; notranslate">
Param(
	&#x5B;string]$fileName,
	&#x5B;string]$char=&quot;#&quot;,
	&#x5B;string]$empty
)

function usage {
    Write-Host &quot;usage: norem &#x5B;-f file ] | &#x5B;-c char] | &#x5B;-e]]&quot;
    Write-Host &quot;Prints a file skipping the lines that start with -c&quot;
    Write-Host &quot;By default empty lines are not printed, use -e yes to include them&quot;
    Write-Host &quot;Kliment Andreev - 2016&quot;
}

if ($psboundparameters.Count -eq 0) {
    usage
    exit
}

if ($empty.ToUpper().Contains(&quot;Y&quot;)) {
    Get-Content $fileName | Where { $_ -notmatch &quot;^&quot; + $char }
}
else {
    Get-Content $fileName | Where { $_ -notmatch &quot;^&quot; + $char } | Where {$_.trim() -ne &quot;&quot;}
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2016/12/103-norem-utility-remove-comments-source/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>General: postfix relay for another domain</title>
		<link>https://blog.andreev.it/2012/01/postfix-relay-for-other-domain/</link>
					<comments>https://blog.andreev.it/2012/01/postfix-relay-for-other-domain/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Wed, 18 Jan 2012 19:30:36 +0000</pubDate>
				<category><![CDATA[AIX]]></category>
		<category><![CDATA[CentOS]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[postfix]]></category>
		<category><![CDATA[relay]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=235</guid>

					<description><![CDATA[I have two registered domains both pointing to my FreeBSD external IP. The first&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>I have two registered domains both pointing to my FreeBSD external IP. The first one is chombe.org and I receive these e-mails on my FreeBSD using postfix. The second domain is klimentandreev.com and I use Exchange 2003 to receive e-mails for this domain. Since Exchange is on the internal network, I have to configure postfix to relay all e-mails for klimentandreev.com to the Exchange box.</p>
<p>First, I made sure that I can ping klimentandreev.com from FreeBSD box and that it will resolve to my internal IP. Next, I edited <strong>main.cf</strong> and changed <strong>relay_domains</strong> to be like this.</p>
<pre class="brush: bash; title: ; notranslate">
relay_domains = $mydestionation, /usr/local/etc/postfix/relay-domains 
</pre>
<p>Then, I created that file and added the following lines.</p>
<pre class="brush: bash; title: ; notranslate">
# Relay domains
klimentandreev.com
other-domain-that-i-will-probably-buy.com
</pre>
<p>After that, I reloaded postfix with <strong>/usr/local/etc/rc.d/postfix reload</strong> and I verified that postfix is relaying OK. I didn’t have to configure anything on the Exchange box.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2012/01/postfix-relay-for-other-domain/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Ubuntu: OpenVPN 2.0.9 client on Ubuntu 9.04</title>
		<link>https://blog.andreev.it/2011/12/openvpn-2-0-9-client-on-ubuntu-9-04/</link>
					<comments>https://blog.andreev.it/2011/12/openvpn-2-0-9-client-on-ubuntu-9-04/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Wed, 28 Dec 2011 19:25:02 +0000</pubDate>
				<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[OpenVPN]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=222</guid>

					<description><![CDATA[This is a method to install OpenVPN client on Ubuntu 9.04. First, download OpenVPN&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>This is a method to install OpenVPN client on Ubuntu 9.04. First, download OpenVPN client from <a href="http://openvpn.net/release/openvpn-2.0.9.tar.gz">http://openvpn.net/release/openvpn-2.0.9.tar.gz</a>. Unpack it, but do not install it yet. Then, download lzo-2.03 compression library from <a href="http://www.oberhumer.com/opensource/lzo/download/lzo-2.03.tar.gz">http://www.oberhumer.com/opensource/lzo/download/lzo-2.03.tar.gz</a>.</p>
<p>Before installing it, do:</p>
<pre class="brush: bash; title: ; notranslate">apt-get install libcurl4-openssl-dev </pre>
<p>Then unpack lzo-2.03, cd to that folder and do:</p>
<pre class="brush: bash; title: ; notranslate">./configure
sudo make
sudo make check
sudo make test
sudo make install </pre>
<p>Once you are done with lzo install, cd to openvpn folder and do the following.</p>
<pre class="brush: bash; title: ; notranslate">./configure
sudo make
sudo make install </pre>
<p>Now, put your config file under <strong>/etc/client.ovpn</strong> and your keys under your Documents folder. Make sure that you update client.ovpn so it reflects the new path. You can start the client using:</p>
<pre class="brush: bash; title: ; notranslate">/usr/local/sbin/openvpn --config /etc/client.ovpn</pre>
<p>Next, you can create a shortcut or “Launcher”. Make a small script <strong>/usr/local/bin/openvpn.sh</strong> and put the following lines.</p>
<pre class="brush: bash; title: ; notranslate">#!/bin/bash
sudo /usr/local/sbin/openvpn --config /etc/client.ovpn
</pre>
<p>Change the permissions with <strong>chmod +x</strong> or <strong>chmod 744</strong> if you want to have exclusive execute rights and then do:</p>
<pre class="brush: bash; title: ; notranslate">sudo updatedb </pre>
<p>Right-click anywhere on the desktop, choose <strong>“Create Launcher”</strong>, choose <strong>“Application in Terminal” </strong>and browse for the .sh script that you just made.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2011/12/openvpn-2-0-9-client-on-ubuntu-9-04/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>OpenBSD, Ubuntu: PXE network installation, DHCP and tftp server</title>
		<link>https://blog.andreev.it/2011/12/pxe-network-installation-of-ubuntu-linux-using-openbsd-as-dhcp-and-tftp-server/</link>
					<comments>https://blog.andreev.it/2011/12/pxe-network-installation-of-ubuntu-linux-using-openbsd-as-dhcp-and-tftp-server/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Fri, 02 Dec 2011 18:48:15 +0000</pubDate>
				<category><![CDATA[OpenBSD]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[DHCP]]></category>
		<category><![CDATA[PXE]]></category>
		<category><![CDATA[tftp]]></category>
		<guid isPermaLink="false">http://blog.iandreev.com/?p=128</guid>

					<description><![CDATA[Recently I got a laptop that came without CD or floppy. This laptop supports&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>Recently I got a laptop that came without CD or floppy. This laptop supports PXE boot so the only choice was to install Ubuntu over the network. In order to do that, I needed a DHCP server that supports PXE boot, tftp server and of course the boot file that will start the installation over the network. You can see my <a href="https://blog.andreev.it/?p=124" target="_blank" rel="noopener noreferrer">previous article</a> on how to setup a DHCP server on OpenBSD. Installation of the tftp server is very easy on OpenBSD. You have to edit <strong>/etc/inetd.conf</strong> and uncomment the first entry for tftp.</p>
<pre class="brush: bash; title: ; notranslate">
ident           stream  tcp     nowait  _identd /usr/libexec/identd     identd -el
ident           stream  tcp6    nowait  _identd /usr/libexec/identd     identd -el
tftp            dgram   udp     wait    root    /usr/libexec/tftpd      tftpd -s /tftpboot
#tftp           dgram   udp6    wait    root    /usr/libexec/tftpd      tftpd -s /tftpboot
</pre>
<p>Now, you need to refresh inetd process and create the home/root folder for the tftp.</p>
<pre class="brush: bash; title: ; notranslate">
kill -HUP `cat /var/run/inetd.pid`
mkdir /tftpboot  
</pre>
<p>Make sure that tftp is working. Type <strong>q</strong> to exit.</p>
<pre class="brush: bash; title: ; notranslate">
tftp localhost
tftp&gt; q
</pre>
<p>Next, you have to download the Ubuntu network installation file and place it in <strong>/tftpboot</strong>. Put this file in <strong>/tftpboot</strong> and unpack it with:</p>
<pre class="brush: bash; title: ; notranslate">
tar xzvf netboot.tar.gz
</pre>
<p>You have to change the MAC address in <strong>/etc/dhcpd.conf</strong> to match the MAC address on the computer where you want to install Ubuntu. Restart the computer, choose network boot and install.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2011/12/pxe-network-installation-of-ubuntu-linux-using-openbsd-as-dhcp-and-tftp-server/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
