<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Joby Matwick]]></title><description><![CDATA[Electronics and Networking]]></description><link>https://matwick.ca/</link><image><url>https://matwick.ca/favicon.png</url><title>Joby Matwick</title><link>https://matwick.ca/</link></image><generator>Ghost 4.37</generator><lastBuildDate>Mon, 13 Apr 2026 19:57:22 GMT</lastBuildDate><atom:link href="https://matwick.ca/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Self-Hosted SSO with Authelia and NGINX]]></title><description><![CDATA[Secure all of you self-hosted services with one login page using Authelia, an SSO portal to authenticate all your services behind an NGINX reverse proxy.]]></description><link>https://matwick.ca/authelia-nginx-sso/</link><guid isPermaLink="false">5fa5ff211b8dfe05d009df08</guid><category><![CDATA[Homelab]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Sun, 08 Nov 2020 10:36:53 GMT</pubDate><media:content url="https://matwick.ca/content/images/2020/11/cover-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://matwick.ca/content/images/2020/11/cover-1.png" alt="Self-Hosted SSO with Authelia and NGINX"><p>Authelia is an open-source authentication and authorization server. In conjunction with an NGINX proxy, all pf your proxied apps and services can use the the same login credentials and login session - that is sign in once and have access to all you services without signing in again. It also offers 2FA via email, <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator</a>, <a href="https://duo.com/">Duo</a>, and <a href="https://www.yubico.com">Yubikey</a>.</p>
<h2 id="scenario">Scenario</h2>
<p>This guide outlines setting up Authelia in the following scenario:</p>
<ul>
<li>On a webserver running Ubuntu 18.04s.</li>
<li>NGINX is used to proxy a number of apps and services.</li>
<li>Authelia will be run in a docker container.</li>
<li>Authelia will be deployed in the &quot;<a href="https://github.com/authelia/authelia#lite">light</a>&quot; deployment.</li>
</ul>
<h2 id="prerequisites">Prerequisites</h2>
<p>This guide assumes you have done or know how to do the following:</p>
<ul>
<li>You have created a DNS entry for the subdomain <code>auth.example.com</code> pointing to your server.</li>
<li>Your apps and services are proxied to either your root domain or some subdomains.</li>
<li>You are familiar with adding SSL certificates to NGINX (If not, check out <a href="https://letsencrypt.org/">Let&apos;s Encrypt</a>).</li>
</ul>
<h2 id="autheliaconfigurationinstallation">Authelia Configuration &amp; Installation</h2>
<ol>
<li>
<p>The first step is to install the <code>docker</code>, <code>docker-compose</code> and <code>git</code> packages to prepare for the installation of Authelia.</p>
<p>We want to install Docker from the official Docker repository to ensure we get the latest version. The following set of commands prepares the repository.</p>
<pre><code class="language-bash">sudo apt update
sudo apt install apt-transport-https ca-certificates \
    curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
    | sudo apt-key add -
sudo add-apt-repository &quot;deb [arch=amd64] \
    https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable&quot;
sudo apt-get update
</code></pre>
<p>Now to actually install the packages:</p>
<pre><code class="language-bash">sudo apt-get install docker-ce docker-ce-cli docker-compose git
</code></pre>
<p>All that&apos;s left to do is add your user to the <code>docker</code> group so you can manage docker without having to use sudo all the time:</p>
<pre><code class="language-bash">sudo usermod -aG docker ${USER}
su - ${USER}
</code></pre>
</li>
<li>
<p>Now we&apos;ll begin installing Authelia. First we&apos;ll create a directory to contain all of Authelia&apos;s configuration files and any dependencies. In my case it will be in my users home directory.</p>
<pre><code class="language-bash">mkdir ~/authelia
cd ~/authelia
</code></pre>
</li>
<li>
<p>To get started were going to make a <code>docker-compose.yml</code> to define the docker containers we&apos;re creating. Create a file named <code>docker-compose.yml</code> in your editor of choice and paste the following:</p>
<pre><code class="language-yml">version: &apos;3.3&apos;
 
networks:
  net:
    driver: bridge

services:
  authelia:
    image: authelia/authelia
    container_name: authelia
    volumes:
      - ./authelia:/config
    networks:
      - net
    ports:
      - 9091:9091
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/Vancouver

  redis:
    image: redis:alpine
    container_name: redis_authelia
    volumes:
      - ./redis:/data
    networks:
      - net
    expose:
      - 6379
    restart: unless-stopped
    environment:
      - TZ=America/Vancouver
      - PUID=1000
      - PGID=1000
</code></pre>
<p>Now we&apos;ll work through the contents of this file and I&apos;ll point out the changes you&apos;ll need to make depending on your setup.</p>
<p>The first several lines just specify the oldest version of docker engine this file will work with, and the type of network driver docker should use. You probably won&apos;t need to change anything here.</p>
<p>Under <code>services</code> you will find Authelia itself. As well as redis, a database system Authelia uses. As-is in the file each service will have<br>
their respective files in subdirectories of the directory <code>docker-compose.yml</code> is is. If you prefer some other setup, those can be changed.</p>
<p><strong>Change</strong> PUID and GUID on lines 19, 20, 35, and 36 to your users id&apos;s (find your own id&apos;s with <code>id $user</code>).</p>
<p><strong>Change</strong> <code>America\Vancouver</code> on lines 21 and 34 to your local timezone (find a list of timezones known to you system with <code>timedatectl list-timezones</code>).</p>
</li>
<li>
<p>Now we&apos;ll make the first of Authelia&apos;s configuration files.</p>
<pre><code class="language-bash">mkdir ~/authelia/authelia
cd ~/authelia/authelia
</code></pre>
<p>Create and open <code>configuration.yml</code> in your editor of choice and paste the following:</p>
<pre><code class="language-yml">server:
  host: 0.0.0.0
  port: 9091
log:
  level: info
jwt_secret: &lt;your-secret-key&gt;
default_redirection_url: https://apps.example.com
 
authentication_backend:
  file:
    path: /config/users_database.yml
 
access_control:
  default_policy: deny
  rules:
    - domain:
        - &quot;auth.example.com&quot;
      policy: bypass
    - domain:
        - &quot;example.com&quot;
        - &quot;*.example.com&quot;
        - &quot;app.example.com&quot;
      policy: one_factor
 
session:
  name: authelia_session
  secret: &lt;your-secret-key&gt;
  expiration: 12h           # 12 hours
  inactivity: 45m           # 45 minutes
  remember_me_duration: 1M  # 1 month
  domain: example.com
 
  redis:
    host: redis_authelia
    port: 6379
 
regulation:
  max_retries: 3
  find_time: 5m
  ban_time: 15m
 
storage:
  encryption_key: &lt;your-encryption-key&gt;
  local:
    path: /config/db.sqlite3
 
notifier:
  #filesystem:
    #filename: /config/notification.txt
  smtp:
    username: test@gmail.com
    password: &lt;gmail_password&gt;
    host: smtp.gmail.com
    port: 587
    sender: test@gmail.com
</code></pre>
<p>The first thing to replace in <code>configuration.yml</code> is <code>&lt;your-secret-key&gt;</code> after <code>jwt_secret</code> on line 6, <code>secret</code> on line 27, and <code>&lt;your-encryption-key&gt;</code> on line 43. You should replace these with unique strings. If you want, the command below can be used to generate random seeds. Just make usre to use unique strings for each of the three screts.</p>
<pre><code class="language-bash">head /dev/urandom | tr -dc A-Za-z0-9 | head -c64
</code></pre>
<p>The rest of the options you&apos;ll likely want to change are:</p>
<ul>
<li><strong><code>default_redirection_url</code></strong>: The URL users who navigate directly to the login page will be redirected to after login.</li>
<li><strong><code>access_control</code></strong>: This is the area of the configuration where you set what kind of authentication is required for different subdomains. Rules are defined as a list of domains and the policy they follow.
<ul>
<li>In the configuration template the <code>default_policy</code> is <code>deny</code> and there are two domain rules:
<ul>
<li>The first is a <code>bypass</code> rule allowing anyone to the auth page and the root of the domain. Change these to match your domain.</li>
</ul>
</li>
<li><strong><code>policy</code></strong>: There are four policy options:
<ul>
<li><code>deny</code> - No access is permitted.</li>
<li><code>one_factor</code> - Login with username and password.</li>
<li><code>two_factor</code> - Login with username, password, and 2FA.</li>
<li><code>bypass</code> - No login required.</li>
</ul>
</li>
<li>For more details on the access control list, see the <a href="https://www.authelia.com/docs/configuration/access-control">docs</a>.</li>
</ul>
</li>
<li><strong><code>session</code></strong>: This is where cookie setting are set.
<ul>
<li><strong><code>expiration</code></strong>: How long before the cookie expires.</li>
<li><strong><code>inactivity</code></strong>: Mow much inactivity will cause the cookie to expire.</li>
<li><strong><code>remember_me_duration</code></strong>: How long you will stay signed in for after ticking &quot;remember me&quot;.</li>
</ul>
</li>
<li><strong><code>regulation</code></strong>: If there are <code>max_retries</code> failed login attempts in <code>find_time</code>, you will be banned for <code>ban_time</code>.</li>
<li><strong><code>notifier</code></strong>: This is how 2FA codes will be delivered. The template config is setup for emails to be sent from a Gmail address. You can fill this out with your Gmail information, or some other email services smtp settings. Alternatively, comment out all the email settings and uncomment the filesystem ones. This way 2FA codes will just be saved to the listed file.</li>
</ul>
<p>For more information or additional configuration options, you can refer to the <a href="https://www.authelia.com/docs/configuration/">docs</a> or the <a href="https://github.com/authelia/authelia/blob/master/config.template.yml">sample config</a>.</p>
</li>
<li>
<p>The last bit of configuration is creating the user data base. In the same directory as the <code>configuration.yml</code> file, create a new file called <code>users_database.yml</code> and put the following into it.</p>
<pre><code class="language-bash">users:
  &lt;username&gt;:
    displayname: &quot;Your Name&quot;
    # Generate with docker run authelia/authelia:latest authelia hash-password &lt;your-password&gt;
    password: &quot;&lt;hashed-password&gt;&quot;
    email: &lt;your-email&gt;
    groups:
      - admins
</code></pre>
<p>Replace <code>&lt;username&gt;</code> with your desired username, <code>Your Name</code> with your full name and <code>&lt;your-email&gt;</code> with your email. To get the hashed-password to replace <code>&lt;hashed-password&gt;</code> with, use the following command.</p>
<pre><code class="language-bash">docker run authelia/authelia:latest authelia hash-password &lt;your-password&gt;
</code></pre>
<p>You can add as many users as you like under the <code>users:</code> key. You can also add yourself or any other users to more groups if you want to do access control based on groups.</p>
</li>
<li>
<p>We are now ready to spin up Authelia. <code>cd</code> back to the directory containing <code>docker-compose.yml</code> and run the following command to create and run the containers.</p>
<pre><code class="language-bash">docker-compose up -d
</code></pre>
<p>If everything went smoothly, you should be able to navigate to <code>&lt;webserver-ip&gt;:9091</code> and be presented with Authelia&apos;s login prompt. Try the username and password you setup in step 5!</p>
</li>
</ol>
<h2 id="addingautheliatonginx">Adding Authelia to NGINX</h2>
<p>Now that Authelia is setup and running, it&apos;s time to tie it into NGINX.</p>
<ol start="7">
<li>
<p>The first thing we need to do is create a new site configuration for <code>auth.example.com</code>. For example:</p>
<pre><code class="language-bash">sudo vim /etc/sudo vim /etc/nginx/sites-available/auth.example.com
</code></pre>
<p>Of course, replace <code>example.com</code> with your domain name. Paste the following into the new configuration file:</p>
<pre><code class="language-nginx">server {
    server_name auth.example.com;
    listen 80;
    return 301 https://$server_name$request_uri;
}

server {
    server_name auth.example.com;
    listen 443 ssl http2;

    location / {
        set $upstream_authelia http://127.0.0.1:9091;
        proxy_pass $upstream_authelia;

        client_body_buffer_size 128k;

        #Timeout if the real server is dead
        proxy_next_upstream error timeout invalid_header http_500 http_502     http_503;

        # Advanced Proxy Config
        send_timeout 5m;
        proxy_read_timeout 360;
        proxy_send_timeout 360;
        proxy_connect_timeout 360;

        # Basic Proxy Config
        proxy_set_header Host $host;
        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_set_header X-Forwarded-Host $http_host;
        proxy_set_header X-Forwarded-Uri $request_uri;
        proxy_set_header X-Forwarded-Ssl on;
        proxy_redirect  http://  $scheme://;
        proxy_http_version 1.1;
        proxy_set_header Connection &quot;&quot;;
        proxy_cache_bypass $cookie_session;
        proxy_no_cache $cookie_session;
        proxy_buffers 64 256k;

        # If behind reverse proxy, forwards the correct IP
        set_real_ip_from 10.0.0.0/8;
        set_real_ip_from 172.0.0.0/8;
        set_real_ip_from 192.168.0.0/16;
        set_real_ip_from fc00::/7;
        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
    }
}
</code></pre>
<p>Replace all occurrences of <code>example.com</code> with your domain name. Then to enable this new site, run:</p>
<pre><code class="language-bash">sudo ln -s /etc/nginx/sites-available/auth.example.com /etc/nginx/sites-enabled/auth.example.com
sudo systemctl reload nginx
</code></pre>
<p>Now is a good time to get an SSL certificate for <code>auth.example.com</code>. An example of how to do this with letsencrypt&apos;s certbot:</p>
<pre><code class="language-bash">sudo certbot run -d auth.example.com --nginx
</code></pre>
<p>Now try navigating to <code>auth.example.com</code>. If all went well, you should again see the Authelia login prompt.</p>
</li>
<li>
<p>Now we&apos;ll make a couple configuration snippets to make adding Authelia to our sites easier. Create and open a file <code>/etc/nginx/snippets/authelia.conf</code> and the past the following into it.</p>
<pre><code class="language-nginx"># Virtual endpoint created by nginx to forward auth requests.
location /authelia {
    internal;
    set $upstream_authelia http://127.0.0.1:9091/api/verify;
    proxy_pass_request_body off;
    proxy_pass $upstream_authelia;    
    proxy_set_header Content-Length &quot;&quot;;

    # Timeout if the real server is dead
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

    # [REQUIRED] Needed by Authelia to check authorizations of the resource.
    # Provide either X-Original-URL and X-Forwarded-Proto or
    # X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Uri or both.
    # Those headers will be used by Authelia to deduce the target url of the     user.
    # Basic Proxy Config
    client_body_buffer_size 128k;
    proxy_set_header Host $host;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr; 
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Uri $request_uri;
    proxy_set_header X-Forwarded-Ssl on;
    proxy_redirect  http://  $scheme://;
    proxy_http_version 1.1;
    proxy_set_header Connection &quot;&quot;;
    proxy_cache_bypass $cookie_session;
    proxy_no_cache $cookie_session;
    proxy_buffers 4 32k;

    # Advanced Proxy Config
    send_timeout 5m;
    proxy_read_timeout 240;
    proxy_send_timeout 240;
    proxy_connect_timeout 240;
}
</code></pre>
<p>This snippet will be added to the server block of any site we secure with Authelia. We need one more snippet. Create and open <code>/etc/nginx/snippets/auth.conf</code>, then paste the following in.</p>
<pre><code class="language-nginx"># Basic Authelia Config
# Send a subsequent request to Authelia to verify if the user is authenticated
# and has the right permissions to access the resource.
auth_request /authelia;
# Set the `target_url` variable based on the request. It will be used to build the portal
# URL with the correct redirection parameter.
auth_request_set $target_url $scheme://$http_host$request_uri;
# Set the X-Forwarded-User and X-Forwarded-Groups with the headers
# returned by Authelia for the backends which can consume them.
# This is not safe, as the backend must make sure that they come from the
# proxy. In the future, it&apos;s gonna be safe to just use OAuth.
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $email $upstream_http_remote_email;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Name $name;
proxy_set_header Remote-Email $email;
# If Authelia returns 401, then nginx redirects the user to the login portal.
# If it returns 200, then the request pass through to the backend.
# For other type of errors, nginx will handle them as usual.
error_page 401 =302 https://auth.example.com/?rd=$target_url;
</code></pre>
<p>All you need to do here is replace <code>example.com</code> on the last line with your domain.</p>
</li>
<li>
<p>Now we can edit our existing <code>example.com</code> NGINX site config to add Authelia.</p>
<ul>
<li>You will include the snippet <code>authelia.conf</code> into the main server block.</li>
<li>You will include the snippet <code>auth.conf</code> into any location block you want to protect.</li>
</ul>
<p>For example:</p>
<pre><code class="language-nginx">server {
    server_name app.example.com;
    listen 80;
    return 301 https://$server_name$request_uri;
}

server {
    server_name app.example.com;
    listen 443 ssl http2;
    include snippet/ssl.conf;

    include snippets/authelia.conf; # Authelia auth endpoint

    location / {
        proxy_pass http://proxied:service;
	    proxy_set_header Host $host;
	    proxy_set_header X-Real-IP $remote_addr;
	    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

	    include snippets/auth.conf; # Protect this endpoint
    }
}
</code></pre>
<p>You should just be able to add the snippets in the correct locations to your existing configuration.</p>
<p>Test the configuration and then reload NGINX:</p>
<pre><code class="language-bash">sudo nginx -t
sudo systemctl reload nginx
</code></pre>
<p>Congratulations! If everything your done!</p>
</li>
</ol>
<h2 id="testitout">Test It Out</h2>
<p>Try navigating to any protected endpoint you configured, you should be presented with the login prompt. After entering your credentials, you should be redirected to your destination. If you setup multiple endpoints, going to a second one should not ask for a password because you are still logged in.</p>
<p>If you want to logout, you can navigate to <code>auth.example.com</code> and you will be presented with a logout button. <code>auth.example.com/logout</code> will also accomplish the same.</p>
<h2 id="downthelineupdating">Down the line: Updating</h2>
<p>Because we used <code>docker-compose</code> to bring up this system updating any part of it is very simple. Just run the following commands to pull the latest images and then rebuild and start the containers.</p>
<pre><code class="language-bash">cd ~/authelia
docker-compose pull
docker-compose up --force-recreate --build -d
docker image prune -f
</code></pre>
<hr>
<h2 id="resources">Resources</h2>
<ul>
<li>You can download all the configuration templates <a href="https://files.matwick.ca/authelia_conf">here</a>.</li>
<li>See the official Authelia docs <a href="https://www.authelia.com/docs/">here</a>.</li>
<li>Have a look at the official, complete sample config <a href="https://github.com/authelia/authelia/blob/master/config.template.yml">here</a>.</li>
</ul>
<p><a href="mailto:joby@matwick.ca?subject=Authelia Guide">Email</a> me with any suggestions or feedback!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Internet Connection Sharing on Windows 10 for Raspberry Pi]]></title><description><![CDATA[You can share your Windows laptops Wi-Fi connection with a Raspberry Pi over ethernet using Internet Connection Sharing. These are the steps.]]></description><link>https://matwick.ca/raspi-ics/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcb00</guid><category><![CDATA[Electronics]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Fri, 21 Feb 2020 01:29:04 GMT</pubDate><media:content url="https://matwick.ca/content/images/2020/02/ics-raspi.png" medium="image"/><content:encoded><![CDATA[<img src="https://matwick.ca/content/images/2020/02/ics-raspi.png" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi"><p>If you only have access to a public Wi-Fi network while working with your Raspberry Pi, or the only Wi-Fi network available to you is 5 GHz, you may want to share the internet connection from your Windows laptop or computer with your Pi over ethernet. You can use Window&apos;s Internet Connection Sharing (ICS) feature to help you do this. Below are the steps required to set it up so it reliably works across reboots.</p><!--kg-card-begin: markdown--><h3 id="steps">Steps</h3>
<ol>
<li>Open Windows Control Panel and navigate to <code>Control Panel&gt; Network and Internet &gt; Network and Sharing Center</code>. Click <code>Change Adapter Settings</code> in the left-hand panel and you should be presented with a list of network adapters: <div style="text-align:center"><img src="https://matwick.ca/content/images/2020/02/network-adapters.png" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi"></div>
</li>
<li>Identify the Wi-Fi adapter with the active internet connection that you would like to share, and the Ethernet adapter you would like to share the connection to. In my case, the Wi-Fi adapter is called <code>Wi-Fi</code> and the ethernet adapter is called <code>Ethernet</code>.</li>
<li>Right-click on the <strong>Wi-Fi</strong> adapter, and select <code>Properties</code>, then select the <code>Sharing</code> tab in the top of the window. <div style="text-align:center"><img src="https://matwick.ca/content/images/2020/02/adapter-properties.png" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi"></div>
</li>
<li>Tick the &quot;Allow other users to connect through...&quot; box and then select the ethernet adapter identified in step 2 from the drop-down menu below. Click ok.<br>
You should now see <code>Shared</code> beside the name of the Wi-Fi network you are connected to on the Wi-Fi adapter item.</li>
<li>To make the ICS service startup automatically with Windows, search for <code>Services</code> in the start menu and open the Windows services utility.<div style="text-align:center"><img src="https://matwick.ca/content/images/2020/02/services-list.png" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi"></div>
</li>
<li>Find the service called <code>Internet Connection Services (ICS)</code>, right-click it and select <code>Properties</code>. Select <code>Automatic</code> from the Startup type drop-down menu. Then click OK and exit the services utility. <div style="text-align:center"><img src="https://matwick.ca/content/images/2020/02/ics-service-settings.png" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi"></div>
</li>
<li>To make the ICS service <em>actually work</em> after a reboot we need to create a <a href="https://support.microsoft.com/en-us/help/4055559/ics-doesn-t-work-after-computer-or-service-restart-on-windows-10">registry key</a>. Search for and open the <code>Registry Editor</code> in the start menu. Paste <code>Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedAccess</code> into the adress bar at the top of the window. Right-click anywhere and select <code>New &gt; DWORD (32-bit) Value</code>. Name the new key <code>EnableRebootPersistConnection</code>. Double click the new key and change the Value data field to <code>1</code>. <div style="text-align:center"><img src="https://matwick.ca/content/images/2020/02/registry-key.png" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi"></div></li>
</ol>
<!--kg-card-end: markdown--><p>At this point you should be all set. Plug your Raspberry Pi into the ethernet port of your computer, and power it up. You should see the ethernet activity lights on the Pi blinking away as Windows assigns it a new IP from the 192.168.137.* sub-net. Because Windows will assign your Pi an IP, you wont know what IP to use to ssh into it. You can test the connection as well as resolve the IP by opening a command prompt window in typing <code>ping raspberrypi.mshome.net</code> where <code>rasperrypi</code> is the hostname of the Pi (<code>raspberrypi</code> is the default). </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://matwick.ca/content/images/2020/02/ping-result.png" class="kg-image" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi" loading="lazy"><figcaption>Pi ping result</figcaption></figure><p>If all is well, you will see a response from the resolved IP of the Pi. To ssh into the Pi, you can either enter <code>raspberrypi.mshome.net</code> or the resolved IP into PuTTY, but be aware that the IP will likely change every time you connect the Pi. </p><figure class="kg-card kg-image-card"><img src="https://matwick.ca/content/images/2020/02/ssh-connection.png" class="kg-image" alt="Internet Connection Sharing on Windows 10 for Raspberry Pi" loading="lazy"></figure><!--kg-card-begin: markdown--><h3 id="troubleshooting">Troubleshooting</h3>
<ul>
<li>If you can ping the Pi but can&apos;t connect via ssh, ensure that ssh is enabled. See the <a href="https://www.raspberrypi.org/documentation/remote-access/ssh/README.md#3-enable-ssh-on-a-headless-raspberry-pi-add-file-to-sd-card-on-another-machine">Raspberry Pi documentation</a> for details on this.</li>
<li>If you can connect to the Pi but it cant reach the outside internet, make sure your computer is connected to the internet via Wi-Fi.</li>
<li>If the ICS stops working after a reboot, and you are sure steps 5-7 were done properly, you may be forced to disable and re-enable ICS in the Wi-Fi adapter settings after every reboot. This is a known issue with Windows some people have encountered.</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Button debouncing on AVR microcontrollers]]></title><description><![CDATA[<p>Often when working with microcontrollers, it is necessary to interface with buttons of many kinds. One thing that needs to be considered is no switch or button switches from one state to another perfectly cleanly. Because of this, the microcontroller could see multiple &apos;button presses&apos; when only one</p>]]></description><link>https://matwick.ca/avr-debounce-2/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcb05</guid><category><![CDATA[Embedded]]></category><category><![CDATA[AVR]]></category><category><![CDATA[Electronics]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Sun, 30 Dec 2018 05:19:15 GMT</pubDate><media:content url="https://matwick.ca/content/images/2018/12/scope-view-2.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://matwick.ca/content/images/2018/12/scope-view-2.jpg" alt="Button debouncing on AVR microcontrollers"><p>Often when working with microcontrollers, it is necessary to interface with buttons of many kinds. One thing that needs to be considered is no switch or button switches from one state to another perfectly cleanly. Because of this, the microcontroller could see multiple &apos;button presses&apos; when only one occurred. To handle this, we must do something called debouncing.</p><p>On the image shown below, you can see the output of an active-high button in yellow, and the clean output signal of the micro in blue. Looking to the start of the yellow trace, it initially goes high but for approximately 2ms, its state is unstable. The blue trace shows the output of the micro, going high when it decides that button has stabilized.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://matwick.ca/content/images/2018/12/scope-view-1.jpg" class="kg-image" alt="Button debouncing on AVR microcontrollers" loading="lazy"><figcaption>Scope view showing button bounce in yellow and clean signal in blue.</figcaption></figure><p>My preferred &#xA0;debounce strategy is based on an algorithm I have found through Kenneth Kuhn, debounce.c found <a href="http://www.kennethkuhn.com/electronics/debounce.c">here</a>. His files outlines a strategy in which the state of the button is read on a regular interval. On each read, depending on the state, an &apos;integrator&apos; value is either added to or subtracted from by one. If that value reaches a fixed threshold, then output goes high. It only goes low once the value returns to 0. </p><p>Below is my implementation of this algorithm in a simple function. By calling <code>poll_btn(0)</code> on a timer (I usually put in in a timer interrupt that triggers every millisecond or so), at any point in you code you can check if <code>poll_btn(1)</code> returns a 1.</p><!--kg-card-begin: markdown--><pre><code class="language-c">#define BTNPORT PINB
#define BTNPIN 3

#define DEBOUNCECYCLES 5

uint8_t poll_btn(uint8_t number) {
	static uint8_t integrator;
	static uint8_t output;

	switch(number) {
		case 0 :
			// Poll and integrate fire and set buttons
			if ((BTNPORT &amp; (1&lt;&lt;BTNPIN))) {
				if (integrator &gt; 0) {
					integrator--;
				}
			} else if (integrator &lt; DEBOUNCECYCLES) {
				integrator++;
			}
			return(0);

		case 1 :
			// If integrator is at threshhold, return 1
			// If integrator is at 0, return 0
			if (integrator == 0) {
				output = 0;
			}
			else if (integrator &gt;= DEBOUNCECYCLES) {
				integrator = DEBOUNCECYCLES;
				output = 1;
			}
			return(output);
	}
	return(0);
}
</code></pre>
<!--kg-card-end: markdown--><p>The function could be easily expanded to more inputs by adding their polling and integrating code to case 0 and making a new case to check them.</p><!--kg-card-begin: markdown--><hr>
<p><a href="mailto:joby@matwick.ca?subject=AVR debouce comments&amp;body=Lemme know!">Email</a> me with any suggestions or questions!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using tinyAVR 1-Series AVRs with pyupdi]]></title><description><![CDATA[<p>Recently while browsing Digikey, I came across a new-to-me AVR microcontroller, the <a href="https://www.digikey.ca/products/en/integrated-circuits-ics/embedded-microcontrollers/685?k=attiny1616&amp;k=&amp;pkeyword=attiny1616&amp;sv=1&amp;pv7=2&amp;pv252=774&amp;sf=0&amp;quantity=&amp;ColumnSort=0&amp;page=1&amp;pageSize=25">ATtiny1616</a> (<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny3216_ATtiny1616-data-sheet-40001997B.pdf">Datasheet here</a>). It has impressive specs and an extremely reasonable price (less than $1.50CAD in single quantities). But, there are a few caveats to contend with. It is only available in SMD packages which can make</p>]]></description><link>https://matwick.ca/pyupdi-2/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcb04</guid><category><![CDATA[Embedded]]></category><category><![CDATA[Electronics]]></category><category><![CDATA[AVR]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Wed, 19 Dec 2018 08:21:23 GMT</pubDate><media:content url="https://matwick.ca/content/images/2018/12/rsz_1rsz_1img_20181218_224605.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://matwick.ca/content/images/2018/12/rsz_1rsz_1img_20181218_224605.jpg" alt="Using tinyAVR 1-Series AVRs with pyupdi"><p>Recently while browsing Digikey, I came across a new-to-me AVR microcontroller, the <a href="https://www.digikey.ca/products/en/integrated-circuits-ics/embedded-microcontrollers/685?k=attiny1616&amp;k=&amp;pkeyword=attiny1616&amp;sv=1&amp;pv7=2&amp;pv252=774&amp;sf=0&amp;quantity=&amp;ColumnSort=0&amp;page=1&amp;pageSize=25">ATtiny1616</a> (<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny3216_ATtiny1616-data-sheet-40001997B.pdf">Datasheet here</a>). It has impressive specs and an extremely reasonable price (less than $1.50CAD in single quantities). But, there are a few caveats to contend with. It is only available in SMD packages which can make prototyping a little bit tricky, and bigger than that, it doesn&apos;t use the classic AVRISP programmer.</p><p>This micro came out after the Atmel-Microchip merger and is part of the new tinyAVR 1-Series. This means that it has a few key differences to AVR&apos;s that you may be familiar with. The most significant to the actual process of developing with it is your AVRISP programmer is unable to program it. It uses a new programming interface called UPDI which stands for Unified Program and Debug Interface. The lowest-cost official programmer for it seems to be the Atmel-ICE which costs over $150. Fortunatley there is a cheaper, easier solution that you probably have the parts for - pyupdi.</p><p><a href="https://github.com/mraardvark/pyupdi">pyupdi</a> is a is a driver written in python that lets you turn a simple usb to serial adapter into a UPDI programmer using a single resistor. To set it up, all you need to do is connect the RX pin of the adapter to the UPDI pin on the micro and the TX pin to that through a 4.7k resistor. Then just use the program on your computer.</p><p>The other thing you may have to deal with if you choose to use these new microcontrollers are the SMD packages. Fortunately, SOIC packages are relativley easy to hand-solder and breakout boards can be had for cheap on <a href="https://www.digikey.ca/product-detail/en/adafruit-industries-llc/1206/1528-1066-ND/5022795">Digikey</a> or anywhere else.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://matwick.ca/content/images/2018/12/breakout-1.jpg" class="kg-image" alt="Using tinyAVR 1-Series AVRs with pyupdi" loading="lazy"><figcaption>The ATTINY1616 soldered on a breakout board with a decoupling cap directly attached.</figcaption></figure><p>As a simple hello-world project to get used to the new device, I chose to use some seven segment displays I recently got. I wanted to try multiplexing and this was the perfect opportunity. I built up the following circuit and then got to programming.</p><figure class="kg-card kg-image-card"><img src="https://matwick.ca/content/images/2018/12/Capture.PNG" class="kg-image" alt="Using tinyAVR 1-Series AVRs with pyupdi" loading="lazy"></figure><p>The seven segment displays are common-cathode to each of the commons is connected to an I/O pin on the micro. Then each of the segment pins are connected to each display ans well as seven more I/Os. Ideally, each segment pin would get a resistor instead of resistors on the common cathode but i just wanted to keep the wring clean so I opted for this setup. Because of this, the brightness depends on how many segments are turned on.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://matwick.ca/content/images/2018/12/img_20181218_224633.jpg" class="kg-image" alt="Using tinyAVR 1-Series AVRs with pyupdi" loading="lazy"><figcaption>Completed circuit</figcaption></figure><p>The code is relatively simple, just increasing the number displayed. It can be found below:</p><!--kg-card-begin: markdown--><pre><code class="language-c">#define  F_CPU 3300000
#include &lt;avr/io.h&gt;
#include &lt;util/delay.h&gt;

int main(void)
{
	PORTB.DIR = 0xFF;
	PORTA.DIR = 0xFF;
	PORTA.OUT = 0x00;

	char SegA[] = {0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00};
	char SegB[] = {0xC0, 0xF9, 0xE4, 0xF0, 0xD9, 0xD2, 0xC2, 0xF8, 0xC0, 0xD8, 0xC8, 0xC3, 0xC6, 0xE1, 0xC6, 0xCE};

	int count = 0;

	int DispA = 0;
	int DispB = 0;
	int DispC = 0;
	int DispD = 0;

    while (1) {
		count ++;

		PORTA.OUT = (PORTA.OUT &amp; ~0b10000000) | (SegA[DispA] &amp; 0b10000000);
		PORTB.OUT = (PORTB.OUT &amp; ~0b00111111) | (SegB[DispA] &amp; 0b00111111);
		PORTA.OUT |= (1 &lt;&lt; 1);
		_delay_us(30);
		PORTA.OUT &amp;= ~(1 &lt;&lt; 1);

		PORTA.OUT = (PORTA.OUT &amp; ~0b10000000) | (SegA[DispB] &amp; 0b10000000);
		PORTB.OUT = (PORTB.OUT &amp; ~0b00111111) | (SegB[DispB] &amp; 0b00111111);
		PORTA.OUT |= (1 &lt;&lt; 2);
		_delay_us(30);
		PORTA.OUT &amp;= ~(1 &lt;&lt; 2);

		PORTA.OUT = (PORTA.OUT &amp; ~0b10000000) | (SegA[DispC] &amp; 0b10000000);
		PORTB.OUT = (PORTB.OUT &amp; ~0b00111111) | (SegB[DispC] &amp; 0b00111111);
		PORTA.OUT |= (1 &lt;&lt; 3);
		_delay_us(30);
		PORTA.OUT &amp;= ~(1 &lt;&lt; 3);

		PORTA.OUT = (PORTA.OUT &amp; ~0b10000000) | (SegA[DispD] &amp; 0b10000000);
		PORTB.OUT = (PORTB.OUT &amp; ~0b00111111) | (SegB[DispD] &amp; 0b00111111);
		PORTA.OUT |= (1 &lt;&lt; 4);
		_delay_us(30);
		PORTA.OUT &amp;= ~(1 &lt;&lt; 4);


		if (count &gt;= 25) {
			count = 0;
			DispD++;
			if (DispD &gt; 9) {
				DispC++;
				DispD = 0;
				if (DispC &gt; 9) {
					DispB++;
					DispC = 0;
					DispD = 0;
					if (DispB &gt; 9) {
						DispA++;
						DispB = 0;
						DispC = 0;
						DispD = 0;
						if (DispA &gt; 9) {
							DispA = 0;
							DispB = 0;
							DispC = 0;
							DispD = 0;
						}
					}
				}
			}
		}
	}
}
</code></pre>
<!--kg-card-end: markdown--><p></p><p>If you are using Atmel studio, you can set the custom programming command to this, changing the path and COM port to however your system is set up. <code>path\to\python.exe path\to\pyupdi.py -d tiny1616 -c COM# -f $(OutputDirectory)$(OutputFileName).hex</code> This way pressing Start Without Debugging will build and upload your program. More details <a href="https://github.com/mraardvark/pyupdi/issues/10">here</a>.</p><p>To program from the command line, use the command <code>python path\to\pyupdi.py -d tiny1616 -c COMX -f yourfile.hex -v</code>. If everything is hooked up correctly, you should be all set!</p><h2 id="troubleshooting">Troubleshooting</h2><p>If you are having some issues, try going through the following:</p><ul><li>Ensure the ground of the adapter is connected to the ground of your circuit.</li><li>Make sure you have all python dependencies installed (pip install intelhex pylint pyserial).</li><li>The voltage of your serial adapter should be the same as your circuit.</li><li>Nothing else can be using the COM port.</li><li>Python 3 <em>should</em> work but some people have had issues. Try 2.7.</li><li>Make sure you don&apos;t disable the UPDI pin with fuses. You&apos;ll need a high-voltage programmer (Big $$$) to recover your chip.</li><li>If you are on Linux, your COM port will likely be /dev/tty&lt;something&gt;. Make sure your user is the group for tty access (usually <code>uucp</code>), and test out your serial connection before trying pyupdi. If all is well both with your software and hardware (4.7K resistor), any characters you send should be echoed right back.</li></ul><h2 id="helpful-links">Helpful Links</h2><ul><li>mraardvark&apos;s pyupdi [<a href="https://github.com/mraardvark/pyupdi">github</a>]</li><li>ATtiny1616 datasheet [<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny3216_ATtiny1616-data-sheet-40001997B.pdf">microchip</a>]</li><li>USB Serial adapter I used [<a href="https://amzn.to/2F8pjMf">amazon</a>]</li></ul><!--kg-card-begin: markdown--><hr>
<p><a href="mailto:joby@matwick.ca?subject=tinyAVR Comments&amp;body=Lemme know!">Email</a> me with any suggestions or questions!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Koel Music Server Ubuntu 16.04 Install Guide]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Koel is a selfhosted music streaming service written in PHP and javascript with <a href="https://vuejs.org/">vue</a> and <a href="https://laravel.com/">laravel</a>. This guide will go through the process of installing Koel on <a href="https://www.ubuntu.com/download/server">Ubuntu server</a> 16.04 running under an <a href="https://www.nginx.com">NGINX</a> webserver with a <a href="https://mariadb.org/">MariaDB</a> sql database. Before we start, make sure you have a user</p>]]></description><link>https://matwick.ca/koel-music-server-ubuntu-16-04-install-guide/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcafe</guid><category><![CDATA[Homelab]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Thu, 29 Mar 2018 22:39:01 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Koel is a selfhosted music streaming service written in PHP and javascript with <a href="https://vuejs.org/">vue</a> and <a href="https://laravel.com/">laravel</a>. This guide will go through the process of installing Koel on <a href="https://www.ubuntu.com/download/server">Ubuntu server</a> 16.04 running under an <a href="https://www.nginx.com">NGINX</a> webserver with a <a href="https://mariadb.org/">MariaDB</a> sql database. Before we start, make sure you have a user with root or sudo privileges.</p>
<blockquote>
<p style="padding-left: 30px;">Koel <span style="text-decoration: underline;">must</span> be installed at its own domain or sub domain. It will not work properly in a directory/URI.</p>
<p style="padding-left: 30px;">Your music files must be located on the server allong with the application and NGINX.</p>
</blockquote>
<h1>Installation</h1>
Before installing Koel, we must install NGINX, PHP, MariaDB, and all the other dependencies.
<h2>NGINX</h2>
NGINX will be the main web server. Install it with the following commands:
<pre><code class="language-bash">sudo apt-get update
sudo apt-get install nginx
</code></pre>
<p>after that, you can verify that the install was successful by navigating to your servers IP or domain in a web browser. You should see the following:</p>
<p><img src="https://matwick.ca/content/images/2018/03/nginx-welcome-page-1.png" alt="nginx welcome page" loading="lazy"></p>
<p>Great, that&apos;s all we need to do for now with NGINX. If you&apos;d like to set up Koel under a sub domain or secure it with SSL, you can head over to my <a href="https://matwick.ca/nginx-the-ultimate-web-server-for-self-hosting/" target="_blank" rel="noopener">NGINX guide</a>.</p>
<h2>MariaDB</h2>
The SQL database is MariaDB, a MySQL compatible SQL. To install the server and client, run the following commands:
<pre><code class="language-bash">sudo apt-get install mariadb-client mariadb-server
sudo mysql_secure_installation
</code></pre>
<p>The second command will bring up the following prompts. Follow the directions below.</p>
<pre><code class="language-bash">Enter current password for root (enter for none):  # Hit enter
Set root password? [Y/n]                           # Y
New password:                                      # New Root database pass
Re-enter new password:                             # Repeat
Remove anonymous users? [Y/n]                      # Y
Disallow root login remotely? [Y/n]                # Y
Reload privilege tables now? [Y/n]                 # Y
</code></pre>
<p>Now we have to log in the server to create a database for Koel as well as a new user. Login by typing the following command then entering the password you set before.</p>
<pre><code class="language-bash">mysql -u root -p
Enter passowrd:                             # Enter your root database password
</code></pre>
<p>Once you are at the MariaDB command prompt, enter the following commands to create a database, user and set permissions:</p>
<pre><code class="language-sql">CREATE DATABASE koel DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
CREATE USER &apos;koel&apos;@&apos;localhost&apos; IDENTIFIED BY &apos;koelpass&apos;;
GRANT ALL PRIVILEGES ON koel.* TO &apos;koel&apos;@&apos;localhost&apos; WITH GRANT OPTION;
exit;
</code></pre>
<p>Now you have a database <strong>koel</strong> and a user <strong>koel</strong> with the password <strong>koelpass</strong>.</p>
<h2>Dependecies</h2>
Finally we can install the rest of the dependencies. Run the following commands:
<pre><code class="language-bash">cd ~
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
sudo echo &quot;deb https://dl.yarnpkg.com/debian/ stable main&quot; | sudo tee /etc/apt/sources.list.d/yarn.list
sudo curl -sL https://deb.nodesource.com/setup_6.x | bash - &amp;amp;&amp;amp; sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y php7.0 php7.0-mysql php7.0-zip php7.0-xml php7.0-tidy php7.0-mbstring php7.0-fpm php7.0-common zip unzip git g++
curl -sS https://getcomposer.org/installer -o composer-setup.php
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer &amp;amp;&amp;amp; composer -V
</code></pre>
<p>You should see Composer version x.x.x in the console if it was successful.</p>
<h2>Koel</h2>
Now we are finally ready to install Koel. Run the following commands to download Koel to your home directory:
<pre><code class="language-bash">cd ~
git clone https://github.com/phanan/koel.git music
cd music
composer install
yarn
</code></pre>
<h1>Configuration</h1>
<h2>NGINX</h2>
Make NGINX work with PHP by editing the site config with the following command:
<pre><code class="language-bash">sudo nano /etc/nginx/sites-enabled/default
</code></pre>
<p>Now replace the contents of that file with the following. Note that if you want SSL, subdomains or any other special config, the server block that you will need will be different. See my NGINX guide for more details.</p>
<pre><code class="language-nginx">server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.php index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}
</code></pre>
<p>Save and exit and then reload nginx by typing:</p>
<pre><code class="language-bash">sudo service nginx reload
</code></pre>
<h2>Koel</h2>
Now we have to setup Koel to use our database info as well as tell it what the first users account info should be. Edit the .env file and fill in the variables noted below:
```bash
cd ~/music
nano .env
```
<pre><code class="language-yaml">DB_CONNECTION=mysql
DB_HOST=localhost
DB_DATABASE=koel
DB_USERNAME=koel
DB_PASSWORD=koelpass
ADMIN_EMAIL=your-email
ADMIN_NAME=your-name
ADMIN_PASSWORD=your-pass
</code></pre>
<p>Now you can save and close the file. Run the next commands to initialize the application, move it into the web root and set the permissions:</p>
<pre><code class="language-bash">sudo rm * /var/www/html &amp;amp;&amp;amp; sudo cp -R * /var/www/html 
sudo chown -R www-data:www-data /var/www/html*
cd /var/www/html
sudo php artisan koel:init
</code></pre>
<p>And now you should be good to go! Head over to http://&lt;your-ip/domain&gt; in your browser and sign in with the credentials you setup earlier. Click settings and put in your music directory the scan. Give it a moment and then you&apos;ll be able to enjoy your music off your server.</p>
<p><a href="mailto:joby@matwick.ca?subject=Grafana Tutorial Suggestion&amp;body=I have a suggestion to improve the Koel tutorial:">Email</a> me with any suggestions to improve the tutorial!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[NGINX: The Ultimate Web Server for Self Hosting]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><a href="https://matwick.ca/nginx-vs-apache-a-homelabbers-opinion/">NGINX vs Apache</a>, while they both have their pros and cons, one stands out clearly for self hosting - NGINX. There are a few key reasons for this including the following:</p>
<ul>
<li><strong>Lightweight</strong> - When self hosting, you have limited resources. NGINX uses fewer resources.</li>
<li><strong>Reverse Proxy</strong> - Many of your</li></ul>]]></description><link>https://matwick.ca/nginx-the-ultimate-web-server-for-self-hosting/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcafd</guid><category><![CDATA[Homelab]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Thu, 29 Mar 2018 22:37:30 GMT</pubDate><media:content url="https://matwick.ca/content/images/2018/09/NGINX-Guide.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://matwick.ca/content/images/2018/09/NGINX-Guide.png" alt="NGINX: The Ultimate Web Server for Self Hosting"><p><a href="https://matwick.ca/nginx-vs-apache-a-homelabbers-opinion/">NGINX vs Apache</a>, while they both have their pros and cons, one stands out clearly for self hosting - NGINX. There are a few key reasons for this including the following:</p>
<ul>
<li><strong>Lightweight</strong> - When self hosting, you have limited resources. NGINX uses fewer resources.</li>
<li><strong>Reverse Proxy</strong> - Many of your services are going to run on weird ports without encryption. NGINX allows you to access them from convenient URLs using HTTPS encryption.</li>
<li><strong>Easy Configuration</strong> - You don&apos;t need to be an expert to understand NGINX config files.</li>
<li><strong>It just works.</strong></li>
</ul>
<p>This guide will go over <a href="#Installation">installing </a>NGINX, <a href="#Basic_Configuration">basic configuration</a>, <a href="#Enabling_PHP">enabling PHP</a>, <a href="#Server_Blocks_Virtual_Hosts">setting up server blocks</a>, <a href="#Let8217s_Encrypt_SSL_Certificates">getting and using free SSL</a>, <a href="#Reverse_Proxy">setting up reverse proxy</a>, and <a href="#Alias">using the alias function</a>.</p>
<!--more-->
<h2 id="installation">Installation</h2>
<p>Installation is easy, just use your distributions package manager to install the NGINX package:</p>
<h3 id="ubuntudebian">Ubuntu/Debian:</h3>
<pre><code class="language-bash">apt-get install nginx
</code></pre>
<p>You can find instructions for other distributions <a href="https://www.nginx.com/resources/admin-guide/installing-nginx-open-source/">here</a>.</p>
<p>Once installed, just head over to your server IP or domain in a web browser and you should see the following page:</p>
<p><img src="https://matwick.ca/content/images/2018/03/nginx-welcome-page.png" alt="NGINX: The Ultimate Web Server for Self Hosting" loading="lazy"></p>
<p>If so then you&apos;re good to start configuring!</p>
<h2 id="basicconfiguration">Basic Configuration</h2>
<p>The default config file or &apos;server block&apos; is located at <code>/etc/nginx/sites-available/default</code>. If you stripped out all the comments, then it would look like this:</p>
<pre><code class="language-nginx">server {
listen 80 default_server;
listen [::]:80 default_server;

root /var/www/html;
index index.html index.htm index.nginx-debian.html;

server_name _;

location / {
try_files $uri $uri/ =404;
}
}
</code></pre>
<p>At first it may seem as though there is a lot going on. Here&apos;s a rundown of everything:</p>
<ul>
<li>The <code>listen</code> lines tell the server what port to run on. 80 is the standard for HTTP, 443 for HTTPS. The <code>default_server</code> string means all requests will go here is there is no other block for them. It can only be in <strong>1</strong> server block.</li>
<li><code>Root</code> tells the server where on the server the files you want to serve are.</li>
<li><code>index</code> tells the server what file should be served when you just go to the IP or URL.</li>
<li><code>server name</code> tells the server what domain to listen for. <code>_</code> is any.</li>
<li>The <code>location</code> block just says that if the request can&apos;t be served, return a 404.</li>
</ul>
<p>Before we begin making changes, we want to make a backup of the default block. This is so if something gets really messed up, we can restore it easily. We&apos;ll also install PHP now so we can enable it in the config.</p>
<pre><code class="language-bash">cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.old
</code></pre>
<h2 id="enablingphp">Enabling PHP</h2>
<p>PHP is an extremely common server side scripting language. Unlike Apache, NGINX does not integrate PHP natively. Instead, whenever it needs to serve some PHP, it makes a call to an external PHP server process. While this tends to make the configuration slightly more complex, it cuts down on overhead and improves performance.</p>
<p>First you need to install the <code>php-fpm</code> package:</p>
<pre><code class="language-bash">apt-get install php-fpm
</code></pre>
<p>Now one quick security improvement we can make is edit the <code>php.ini</code> file. It is usually located at <code>/etc/php/7.0/fpm/php.ini</code>. You want to find the commented out line called <code>cgi.fix_pathinfo</code>, make sure it is uncommented and set to <code>0</code>. Great! Now we can tell NGINX to use PHP-FPM to process PHP files.</p>
<p>Open up the default server block in your text editor of choice and add this location block to the bottom of the <code>server { }</code> block. While your at it, update the <code>index</code> command by adding <code>index.php</code>.</p>
<pre><code class="language-nginx">location ~ .php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}
</code></pre>
<p>Now make a new file called <code>info.php</code> in your web root and add <code>&amp;lt;? phpinfo(); ?&amp;gt;</code> to it. Now if you head over to <code>http://yourdomain/info.php</code>, you should see somthing similar to the following:</p>
<p><img src="https://matwick.ca/content/images/2018/03/ubuntu_nginx_php_info.png" alt="NGINX: The Ultimate Web Server for Self Hosting" loading="lazy"></p>
<p>Cool, Now your all set with PHP!</p>
<h2 id="serverblocksvirtualhosts">Server Blocks (Virtual Hosts)</h2>
<p>You&apos;ll likely want to run multiple domains or subdomains serving different services through the same server. If you need your own domain, I can personally recommend <a href="https://affiliate.namecheap.com/?affId=118721">NameCheap</a>. With NGINX, this is easy. First, we need to copy the default server block for our new domain. Name the copy whatever your domain is to keep things organized, make a new web root, and then open the new config to edit:</p>
<pre><code class="language-bash">cd /etc/nginx/sites-available
cp /etc/nginx/sites-available/default /etc/nginx/sites-available/my.domain.com
mkdir -R /var/www/mydomain/html
</code></pre>
<p>Now for what to change.</p>
<ol>
<li>Remove <code>default_server</code> from the first 2 <code>listen</code> lines.</li>
<li>Change the <code>root</code> to the new directory you made.</li>
<li>Replace the <code>_</code> by <code>server_name</code> to your domain. For example, <code>my.domain.com</code>.</li>
</ol>
<p>That&apos;s it; now to enable the server block we need to link it to the enabled directory, test it and then reload the web server:</p>
<pre><code class="language-bash">ln -s my.domain.com ../sites-enabled/my.domain.com
nginx -t
service nginx reload
</code></pre>
<p>Now head over to the domain you should get a 404. If you do that great, that means that instead of going through the default config and showing the NGINX welcome, it looking in the web root you set and found nothing. Now you can add whatever content you want to the new folder you made; just make sure it&apos;s owner and group is the user that is running web server process (eg. <code>www-data</code>).</p>
<p>You can repeat this process for however many domains you want to use. Just remember to remove <code>default_server</code> and change the root to something new.</p>
<h2 id="letsencryptsslcertificates">Let&apos;s Encrypt SSL Certificates</h2>
<p>SSL encryption is an important part of any public web services. They encrypt all data sent to and from the server to prevent man-in-the-middle attacks. And, now that you can get free, signed SSL certs through Lets Encrypt, there&apos;s no reason not to.</p>
<h4 id="settingup">Setting Up</h4>
<p>First, we need to get the <code>letsencrypt</code> and <code>openssl</code> package. On Ubuntu, <code>sudo apt-get install letsencrypt openssl</code> does the job. Then we need to make a small change to all server blocks we want to secure. Add the following line to each server block:</p>
<pre><code class="language-nginx">location ~ /.well-known {
allow all;
}
</code></pre>
<p>Then just reload with <code>service nginx reload</code>. Now generate a strong DH group with the following command: <code>sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048</code>. This might take a few minutes so sit tight. Great, now were set to make get some certs.</p>
<h4 id="gettingcertificates">Getting Certificates</h4>
<p>To get your certificates, your going to run the next command but you&apos;ll have to change a few things. Set <code>--webroot-path=</code> to whatever your root is, set <code>-d</code> to your domain.</p>
<pre><code class="language-bash">sudo letsencrypt certonly --webroot --webroot-path=/var/www/html -d example.com
</code></pre>
<p>If successful, it should print out where your certificates were placed. Niw we can go install the certs.</p>
<h4 id="installingcertificates">Installing Certificates</h4>
<p>Now we need to make a few snippets to add to our server block. Change all <code>example.com</code> your domain.</p>
<pre><code class="language-nginx">#/etc/nginx/snippets/ssl-example.com.conf

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
</code></pre>
<pre><code class="language-nginx">#/etc/nginx/snippets/ssl-params.com.conf

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers &quot;EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH&quot;;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_dhparam /etc/ssl/certs/dhparam.pem;
</code></pre>
<p>Great now that we&apos;ve got the snippets, we can apply them to the server block. Make your server block look like the following with your own info and snippets:</p>
<pre><code class="language-nginx">server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 https://$server_name$request_uri;
}

server {
# SSL configuration

listen 443 ssl http2;
listen [::]:443 ssl http2;
include snippets/ssl-example.com.conf;
include snippets/ssl-params.conf;

root /var/www/example/html;

index index.html index.php index.htm index.nginx-debian.html;

server_name example.com;

location / {
try_files $uri $uri/ /index.php?$args;
}

location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}

location ~ /\.ht {
deny all;
}

location ~ /.well-known {
allow all;
}

}
</code></pre>
<p>Now reload NGINX. Now if you head over to your domain it shout redirect to the HTTPS version and you should see a green lock! Perfect!</p>
<h2 id="reverseproxy">Reverse Proxy</h2>
<p>When self hosting, its very common to end up with lots of services running on a number of ports. You can make it much easier to access and share all the these services using a reverse proxy. As an example I&apos;ll proxy <a href="https://sonarr.tv/">Sonarr</a>, a popular self hosted media app from the default of <code>ip:8989</code> to <code>example.com/sonarr</code>. Since I already have a server block setup with SSL for <code>example.com</code>, this will be super simple.</p>
<p>It&apos;s just a matter of opening up the server block and adding a location block. Then change the directory of the location block to whatever you want it to be. Lastly replace the IP and port to that of your Sonarr install.</p>
<pre><code class="language-nginx">location /sonarr {
proxy_pass http://192.168.1.12:8989;
proxy_set_header Host $host; #DO NOT CHANGE
proxy_set_header X-Real-IP $remote_addr; #DO NOT CHANGE
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #DO NOT CHANGE
}
</code></pre>
<p>Then you just need to go to Sonarrs settings and set the base url as <code>sonarr</code> and reload bot Sonarr and NGINX. Now if you head over to <code>example.com/sonarr</code> you&apos;ll see your sonarr, just without that pesky port.</p>
<h2 id="alias">Alias</h2>
<p>If you want to run an app like WordPress, at a URI like <code>example.com/blog</code> but you want all files related to it to be in a different directory, you&apos;d use the <code>alias</code> function. One quirk is you need to add your PHP for PHP to work. Check this out:</p>
<pre><code class="language-NGINX">location /alternative {
alias /var/www/alternative_html/;
location ~ /\.php$ {
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
</code></pre>
<p>You can change <code>alternative</code> and <code>alternative_html</code> to whatever you like then you should be all set.</p>
<hr>
<p>Now that you&apos;ve got a secure, robust and lightweight web server, you can <a href="http://blog.matwick.ca/guides/installing-koel-ubuntu-16-04/">install Koel</a> - a self hosted music server. Or not. It&apos;s really up to you :)</p>
<pre><code>Last Updated: 07/11/17
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[DIY ThinkPad Charger]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I recently bought a used Lenonvo T440s. I got it for a good deal but there with a few issues:</p>
<ul>
<li>No charger included</li>
<li>Missing trackpoint nub</li>
<li>Missing an arrow key</li>
</ul>
<p>First thing I did after ordering the laptop was order a new Thinkpad charger. No problem; but while browsing Ebay</p>]]></description><link>https://matwick.ca/diy-thinpad-charger-2/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcb02</guid><category><![CDATA[Electronics]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Thu, 29 Mar 2018 22:34:26 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I recently bought a used Lenonvo T440s. I got it for a good deal but there with a few issues:</p>
<ul>
<li>No charger included</li>
<li>Missing trackpoint nub</li>
<li>Missing an arrow key</li>
</ul>
<p>First thing I did after ordering the laptop was order a new Thinkpad charger. No problem; but while browsing Ebay looking for a new key cap and trackpoint nub, I found generic laptop charger to Lenovo slim charging adaptors. Knowing I have a few spare old chargers, and that I would want a second for my new laptop, I ordered a few from China. After they arrived however, I knew they weren&apos;t going to work so great.</p>
<p><img src="https://matwick.ca/content/images/2018/09/IMG_20170712_195207.jpg" alt="Adaptor and old charger" loading="lazy"> <em>Adaptor and old charger</em></p>
<h3 id="diggingintotheadaptor">Digging Into the Adaptor</h3>
<p>The Toshiba charger I had was very loose in the adaptor and the connection was flaky at best. Then, knowing I had two adaptors, I figured it couldn&apos;t hurt to dig into one and see if I could wire it up directly. So I went at he adaptor with a sharp knife and cut away all the over-moulded rubber.</p>
<p><img src="https://matwick.ca/content/images/2018/09/IMG_20170712_195239.jpg" alt="Adaptor free of all wores and rubber" loading="lazy"><em>Adaptor free of all wires and rubber</em></p>
<p>While digging I found and promptly broke a resistor built in. After some google-fu, I found myself on the <a href="http://www.thinkwiki.org/wiki/Power_Connector#Signal_Pin_2">ThinkWiki</a> with a chart of the resistor values for different wattages. The resistor goes between the center signal pin and outside shield (Ground).</p>
<table>
<thead>
<tr>
<th style="text-align:center">Wattage</th>
<th style="text-align:center">Resistance</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">45W</td>
<td style="text-align:center">120R</td>
</tr>
<tr>
<td style="text-align:center">65W</td>
<td style="text-align:center">280R</td>
</tr>
<tr>
<td style="text-align:center">90W</td>
<td style="text-align:center">550R</td>
</tr>
<tr>
<td style="text-align:center">135W</td>
<td style="text-align:center">1K</td>
</tr>
<tr>
<td style="text-align:center">170W</td>
<td style="text-align:center">1.9K</td>
</tr>
</tbody>
</table>
<p>I multiplied the rated voltage and amperage of the Toshiba adaptor <code>19v * 4.75A = 90.25W</code> - A 550R resistor will be perfect. After digging through my parts bin, the closest I could find was two 1K resistors in series for 500R. I figured that would be plenty close.</p>
<h3 id="puttingitalltogether">Putting It All Together</h3>
<p>I took the freshly stripped adaptor and soldered a short wire to the ground pin. Then I put the two resistors between the center signal pin and the new wire I soldered. Lastly I stripped the Toshiba adaptor and soldered the positive wire to the middle pin and the negative to the top of the resistor.</p>
<p><img src="https://matwick.ca/content/images/2018/09/IMG_20170712_201048.jpg" alt="All soldered up" loading="lazy"><em>All soldered up</em></p>
<p>To protect the joints and prevent anything from moving, I mixed up some two part epoxy and coated all the exposed joints. After ot was all set, I had a perfectly usable charger to toss in my bag.</p>
<h3 id="notes">Notes</h3>
<ul>
<li>Wile the Thinkpad charger is rated at 20 volts, 19 volt chargers work fine.</li>
<li>Evidently, the tolerance of the resistor isn&apos;t too critical. 50 ohms off wasn&apos;t an issue.</li>
<li>If you are more careful removing the rubber, the existing resistor can be used.</li>
<li>The adaptors can be found on Ebay by searching for <code>female dc to Lenovo slim</code> mine were about $2.50CAD for 2.</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[NGINX vs Apache: A Homelabbers Opinion]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>NGINX vs Apache, often debated and rightly so. Both these popular web servers have their many strong point as well as weaknesses. It&apos;s up to you to decide what you think is the best for your application. When trying to decide, you have to remember there is no</p>]]></description><link>https://matwick.ca/nginx-vs-apache-a-homelabbers-opinion-2/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcb01</guid><category><![CDATA[Homelab]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Thu, 29 Mar 2018 22:31:04 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>NGINX vs Apache, often debated and rightly so. Both these popular web servers have their many strong point as well as weaknesses. It&apos;s up to you to decide what you think is the best for your application. When trying to decide, you have to remember there is no <em>ideal</em> solution, only the best for you. This post will go over my opinions on the subject from a Home lab/Self hosted viewpoint.</p>
<p>Now with all that aside, in my opinion, <strong>NGINX is the best</strong> for home servers. Here are a few of the key reasons:</p>
<ul>
<li><strong>Performance</strong>: NGINX was originally created to address some problems with Apache, including it&apos;s size and performance. It is likely better for your home server because it has a lower overhead resource usage.</li>
<li><strong>Reverse Proxy</strong>: When selfhosting, you often find yourself with a number of services running on different ports and virtual machines. NGINXs reverse proxy lets you access them at a convenient URL.</li>
<li><strong>Ease of Configuration</strong>: NGINXs configuration files or &quot;server blocks&quot; as their called, are extremely easy to understand and are all located in one place.</li>
<li><strong>Speed</strong>: <a href="https://theorganicagency.com/blog/apache-vs-nginx-performance-comparison/">Tests</a> have proven NGINX to be over <strong>4 times faster</strong> than Apache, under the same circumstances!</li>
</ul>
<h1 id="performance">Performance</h1>
<p>First and foremost in the NGINX vs Apache debate is performance. To understand why NGINX comes out on top, we first need to understand how the two work. Apache is a one-thread-per-process style program, whereas NGINX is an event-driven, asynchronous model. The main difference here is when traffic increases, Apache starts to struggle while NGINX handles it all no problem. NGINX also has a considerably smaller code base decreasing the number of attack vectors and generally improving performance.</p>
<h1 id="reverseproxy">Reverse Proxy</h1>
<p>NGINXs reverse proxy is one of its biggest pros, especially for self hosting. It allows you to access services run on other ports, machines or virtual machines through your NGINX server. instead of accessing a service at <code>my.ip:8989</code>, it can be just <code>my.domain/myservice</code>. You can also encrypt the traffic with SSL. See the diagram below for more info on how it all works:</p>
<p><img src="https://matwick.ca/content/images/2018/03/Reverse-proxy2.jpg" alt="Nginx reverse proxy" loading="lazy"></p>
<h1 id="configuration">Configuration</h1>
<p>Apache is configured at the directory level with the use of <code>.htacess</code> files in the given directory. This is convenient for shared host where you don&apos;t have access to the base virtual server config file - not a common issue when you run your server. The downside to the <code>.htaccess</code> files is they are more server requests to deal with. NGINX has everything in the base server block file - no need to hunt around for a bunch of files in a bunch of directories.</p>
<h1 id="speed">Speed</h1>
<p>The graph below really says it all when it comes to speed and performance. With 1 request, both are very similar but as the requests increase, NGINX clearly comes out ahead:</p>
<p><img src="https://matwick.ca/content/images/2018/03/TGZJ8_IWGWsn-0M6Txi9rrt7m5shn_Y5wwi475r8ewMatyVQyULg43lQvAvSN1V24P_9Eu_aezpyRMuWRbmf_XPXtjkN6QrsB9zbM7eLs4ESzrtR6_3ft-LgjA.png" alt="Webserver performance" loading="lazy"></p>
<hr>
<p>Hopefully this short guide has helped you choose NGINX vs Apache for your home lab. If you want a guide for all the basic NGINX config, <a href="https://blog.matwick.ca/guides/nginx-complete-guide/">look no further</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Atmel Studio for Linux]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Unfortunately, if you&apos;ve done some searching, you may have found out that Atmel&apos;s IDE, Atmel Studio is windows only. There is no official Atmel Studio linux. The best alternative I have found is the Eclipse IDE with the AVR plugin.</p>
<blockquote>
<p>Note: While this guide is written</p></blockquote>]]></description><link>https://matwick.ca/atmel-studio-for-linux/</link><guid isPermaLink="false">5f9cb1ecdcd7381a895dcafc</guid><category><![CDATA[Embedded]]></category><category><![CDATA[Electronics]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Joby Matwick]]></dc:creator><pubDate>Thu, 29 Mar 2018 22:10:03 GMT</pubDate><media:content url="https://matwick.ca/content/images/2018/03/atmelStudoLinux.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://matwick.ca/content/images/2018/03/atmelStudoLinux.jpg" alt="Atmel Studio for Linux"><p>Unfortunately, if you&apos;ve done some searching, you may have found out that Atmel&apos;s IDE, Atmel Studio is windows only. There is no official Atmel Studio linux. The best alternative I have found is the Eclipse IDE with the AVR plugin.</p>
<blockquote>
<p>Note: While this guide is written for Linux, you can use it on windows or Mac OSX of you don&apos;t like Atmel studio or want to try something new.</p>
</blockquote>
<h1 id="installation">Installation</h1>
<h2 id="dependencies">Dependencies</h2>
<p>Before we install eclipse and the AVR plugin, we need a few packages. Install <code>avrdude</code>, <code>avr-gcc</code>, <code>avr-libc</code>, <code>avr-binutils</code>, and <code>avr-gdb</code>.</p>
<h2 id="eclipse">Eclipse</h2>
<p>First you wnat to install the excellent <a href="https://eclipse.org/">Eclipse C/C++ IDE</a>. Depending on what operating system you are on the process will be different. For most linux distorbutions, you need to install the <code>eclipse-cpp</code> package.</p>
<p>Once installed, you want to open it up and create a new workspace for your AVR projects. Now open the Eclipse Marketplace <code>Help &gt; Eclipse Marketplace</code>. Search for and install the <code>AVR Eclipse Plugin</code>.</p>
<h1 id="usage">Usage</h1>
<h2 id="creatinganewproject">Creating a new project</h2>
<p>To make a new project, select <code>File &gt; New &gt; C Project&apos;, choose a name and then pick </code>AVR Cross Target Application` from the dialog box and press next. Press next again and then select your projects chip and frequency. These can be changed later in the project properties. Then press finish.</p>
<h2 id="writingyourcode">Writing your code</h2>
<p>To begin creating source code for your program, close the <code>Welcome</code> tab and in the left <code>Project Explorer</code> panel, right click and select <code>New &gt; File</code>; Name it <code>main.c</code>. Now you can code away.</p>
<h2 id="buildingyourproject">Building your project</h2>
<p>To build your project, first right click you project in the explorer and pick <code>Build Configurations &gt; Set Active &gt; 2 Release</code>make sure all files are saved and press <code>Project &gt; Build all</code> or just <code>Ctrl-B</code>. You should see the build progress in the console at the bottom of the screen. For Directions on setting up a programmer with eclipse and programming your micro controller, got <a href="http://avr-eclipse.sourceforge.net/user%20manual/gettingstarted/gs_avrdude_requirements.html">here</a>.</p>
<hr>
<p>There you go, You should be all set up with an equivalent Atmel Studio Linux! Now you can code away to your hearts content on the operating system of your choosing!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>