<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>open weight</title><link>https://terokarvinen.com/tags/open-weight/</link><description>open weight</description><language>en-us</language><lastBuildDate>Wed, 08 Jul 2026 17:10:54 +0300</lastBuildDate><image><url>https://terokarvinen.com/img/favicon.png</url><title>open weight</title><link>https://terokarvinen.com/tags/open-weight/</link></image><atom:link href="https://terokarvinen.com/tags/open-weight/index.xml" rel="self" type="application/rss+xml"/><item><title>Kokoro TTS - Voice Comparison</title><link>https://terokarvinen.com/kokoro-foss-tts-voice-comparison/</link><pubDate>Wed, 08 Jul 2026 17:10:54 +0300</pubDate><guid>https://terokarvinen.com/kokoro-foss-tts-voice-comparison/</guid><description>
&lt;p>Free, open weight models can generate speech. On your local machine.&lt;/p>
&lt;p>Listen to &lt;a href="https://terokarvinen.com/kokoro-voice-comparison/">voice samples of all Kokoro TTS voices&lt;/a> on the web.&lt;/p>
&lt;p>Optionally, install Kokoro with Podman.&lt;/p>
&lt;h2 id="listen-and-compare-voices-in-your-browser">Listen and Compare Voices in Your Browser&lt;/h2>
&lt;p>Search and filter by gender and language. The demo text is currently only in English.&lt;/p>
&lt;p>Kokoro is a free text-to-speech engine, architected by Li, Han, Raghavan, Mischler and Mesgarani; and trained by @rzvnzn. I just created the samples and the page to filter them. Their default flagship voice is af_heart (English, female), but there are many other interesting voices.&lt;/p>
&lt;p>&lt;a href="https://terokarvinen.com/kokoro-voice-comparison/">Listen Kokoro samples now&lt;/a>.&lt;/p>
&lt;p>&lt;a href="https://terokarvinen.com/kokoro-voice-comparison/">&lt;img src="kokoro-tts-foss-voice-comparison-samples-english-female.png" class="pad">&lt;/a>&lt;/p>
&lt;h2 id="run-kokoro-with-podman">Run Kokoro with Podman&lt;/h2>
&lt;p>These commands assume you already have Podman installed. Podman runs containers like Docker. It's safer than Docker, as it does not require root (or the infamous root-equivalent docker group).&lt;/p>
&lt;p>Let's download and run Brauns ready-made Kokoro container:&lt;/p>
&lt;pre>&lt;code>$ podman run -p 8880:8880 ghcr.io/remsky/kokoro-fastapi-cpu
&lt;/code>&lt;/pre>
&lt;p>Web user interface: &lt;a href="http://localhost:8880/web/">http://localhost:8880/web/&lt;/a>&lt;/p>
&lt;img src="fast-kokoro-web.jpg" class="pad">
&lt;p>API, usable with Python requests http://localhost:8880/v1&lt;/p>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;p>Hacker News 2026: &lt;a href="https://news.ycombinator.com/item?id=48821576">Local, CPU-Friendly, High-Quality TTS (Text-to-Speech) with Kokoro&lt;/a>&lt;/p>
&lt;p>Li, Han, Raghavan, Mischler and Mesgarani, @rzvnzn 2026: &lt;a href="https://huggingface.co/hexgrad/Kokoro-82M">hexgrad/Kokoro-82M on HuggingFace&lt;/a>&lt;/p>
&lt;p>Braun 2026: &lt;a href="https://github.com/remsky/Kokoro-FastAPI">remsky / Kokoro-FastAPI on Github&lt;/a>&lt;/p></description></item><item><title>cdu - Jump up to project directory</title><link>https://terokarvinen.com/cdu-change-dir-up-to-project-dir/</link><pubDate>Mon, 06 Jul 2026 11:58:45 +0300</pubDate><guid>https://terokarvinen.com/cdu-change-dir-up-to-project-dir/</guid><description>
&lt;p>You're five levels deep in your git repo. You would like to get to the top level. 'cdu'.&lt;/p>
&lt;p>An up only directory jumper for zsh and bash. Nicely complements other directory jumpers, like zoxide, autojump or fasd.&lt;/p>
&lt;h2 id="usage-example">Usage example&lt;/h2>
&lt;pre>&lt;code>$ pwd
/home/tero/code/revincom/doc/design/subsystems/nav/fallbacks/sun
$ cdu
/home/tero/code/revincom
Found .git
&lt;/code>&lt;/pre>
&lt;p>If you have really deep repos, such as monorepos, cdu can help you even more.&lt;/p>
&lt;p>Deep in a Django project, cdu jumps to manage.py level first. The next cdu will take you to repo root.&lt;/p>
&lt;h2 id="a-new-cdu-change-dir-up">A new 'cdu', change dir up&lt;/h2>
&lt;p>I have used a longer bash version for years. This is a rewrite to support both zsh and bash. It's also shorter. Prettier and more features, but less tested than the old one.&lt;/p>
&lt;p>Save the source code to a dir where it runs (e.g. /usr/local/bin/changedirup). Make runnable (chmod ugo+rx /usr/local/bin/changedirup). Add to your .bashrc and .zshrc: 'alias cdu=&amp;quot;source changedirup&amp;quot;'. Log out and back.&lt;/p>
&lt;p>And now you can jump up with 'cdu'.&lt;/p>
&lt;h2 id="source-code-gpl">Source code, GPL&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#099">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#099">&lt;/span>&lt;span style="color:#09f;font-style:italic"># changedirup - cd up to project top dir, &amp;#39;alias cdu=&amp;#34;source changedirup&amp;#34;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># To persist it, add the alias to .zshrc or .bashrc&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Single usage also works with &amp;#39;source cdu&amp;#39; or &amp;#39;. cdu&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># Can be run again to go to even higher project dir. &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># cdu works with zsh and bash. Shebang #! is just for syntax highlight.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># SPDX-License-Identifier: GPL-3.0-or-later&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#09f;font-style:italic"># SPDX-FileCopyrightText: Copyright 2020-2026 Tero Karvinen https://TeroKarvinen.com&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#033">CDU_PWD_WAS&lt;/span>&lt;span style="color:#555">=&lt;/span>&lt;span style="color:#c30">&amp;#34;&lt;/span>&lt;span style="color:#069;font-weight:bold">$(&lt;/span>&lt;span style="color:#366">pwd&lt;/span>&lt;span style="color:#069;font-weight:bold">)&lt;/span>&lt;span style="color:#c30">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#366">cd&lt;/span> ..
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">while&lt;/span> true; &lt;span style="color:#069;font-weight:bold">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">for&lt;/span> f in .git Makefile .profile .bashrc README.md requirements.txt go.mod manage.py hosts.ini .project project.godot Dockerfile Cargo.toml index.theme config.toml default.gpr DICOMDIR ansible.cfg site.yml Vagrantfile package.json pyproject.toml zowe.yaml pom.xml build.gradle Gemfile composer.json docker-compose.yml compose.yaml .cobaltstrike.beacon_keys flake.nix .zshrc .ssh .sliver .sliver-client .msf4 havoc_default.yaotl .projectile .svn .hg .fossil .jj .editorconfig _darcs .bzr Cargo.lock .bash_profile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">[&lt;/span> -e &lt;span style="color:#c30">&amp;#34;&lt;/span>&lt;span style="color:#033">$f&lt;/span>&lt;span style="color:#c30">&amp;#34;&lt;/span> &lt;span style="color:#555">]&lt;/span>; &lt;span style="color:#069;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">echo&lt;/span> &lt;span style="color:#c30">&amp;#34;Found &lt;/span>&lt;span style="color:#033">$f&lt;/span>&lt;span style="color:#c30">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">pwd&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">break&lt;/span> &lt;span style="color:#f60">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">done&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">if&lt;/span> &lt;span style="color:#555">[&lt;/span> &lt;span style="color:#c30">&amp;#34;&lt;/span>&lt;span style="color:#069;font-weight:bold">$(&lt;/span>&lt;span style="color:#366">pwd&lt;/span>&lt;span style="color:#069;font-weight:bold">)&lt;/span>&lt;span style="color:#c30">&amp;#34;&lt;/span> &lt;span style="color:#555">=&lt;/span> &lt;span style="color:#c30">&amp;#34;/&amp;#34;&lt;/span> &lt;span style="color:#555">]&lt;/span>; &lt;span style="color:#069;font-weight:bold">then&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">cd&lt;/span> &lt;span style="color:#c30">&amp;#34;&lt;/span>&lt;span style="color:#033">$CDU_PWD_WAS&lt;/span>&lt;span style="color:#c30">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">echo&lt;/span> &lt;span style="color:#c30">&amp;#34;No project files found above. Working directory unchanged.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">pwd&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#069;font-weight:bold">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#366">cd&lt;/span> .. &lt;span style="color:#555">||&lt;/span> &lt;span style="color:#366">break&lt;/span> &lt;span style="color:#09f;font-style:italic"># prevent infinite loop in the rare case cd fails for permissions&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#069;font-weight:bold">done&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>ppp Personal Project Portfolio</title><link>https://terokarvinen.com/ppp-personal-project-portfolio/</link><pubDate>Thu, 02 Jul 2026 11:52:15 +0300</pubDate><guid>https://terokarvinen.com/ppp-personal-project-portfolio/</guid><description>
&lt;p>Arrange your ideas into a skill tree.&lt;/p>
&lt;ul>
&lt;li>Pick little wins on your way to big goals&lt;/li>
&lt;li>Ship something at every step&lt;/li>
&lt;li>Turn ambition into output&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="https://terokarvinen.com/ppp/">Open ppp in your browser&lt;/a>. Free, no login.&lt;/p>
&lt;h2 id="talk-nerd-to-me">Talk nerd to me&lt;/h2>
&lt;p>Single 50 kB HTML file with no dependencies. Use online or 100% offline. Your data stays yours: JSON export and import. Fully usable with keyboard-only - or mouse-only with keyboard just for typing names. A vibe-coded GUI editor for a directed acyclic graph with project-specific attributes: costs, deliverables, soft benefits. Public beta.&lt;/p>
&lt;p>Gain a bird's-eye view with ppp. I hope you have more ideas than time to do them. Use ppp to decide which path to pick next. Once you're committed, use &lt;a href="https://terokarvinen.com/2021/calendar-txt/">calendar.txt&lt;/a> and todo.txt for day-to-day and hour-to-hour.&lt;/p>
&lt;h2 id="try-ppp">Try ppp&lt;/h2>
&lt;p>&lt;a href="https://terokarvinen.com/ppp/">Try ppp&lt;/a>. Free web access, no login required. Optionally save the 50 kB HTML file for 100% offline use. Looking forward to your &lt;a href="#comments">comments&lt;/a>.&lt;/p>
&lt;p>&lt;a href="https://terokarvinen.com/ppp/">
&lt;img src="https://terokarvinen.com/ppp-personal-project-portfolio/ppp%20Personal%20Portfolio%20Manager%20-%20A%20skill%20tree%20for%20life_hu1fdde610736e2f1bce27e11014b13464_169827_1000x1000_fit_box_3.png" width="1000" height="477" alt=" " class="imgOne pad">
&lt;/a>&lt;/p></description></item><item><title>Apache installed with Ansible - quick notes</title><link>https://terokarvinen.com/apache-ansible/</link><pubDate>Thu, 09 Apr 2026 16:10:04 +0300</pubDate><guid>https://terokarvinen.com/apache-ansible/</guid><description>
&lt;img src="https://terokarvinen.com/apache-ansible/apache-httpd-logo_hu0274bb063ced1072a70ec8e201c9b197_74947_400x400_fit_box_3.png" width="206" height="400" alt=" " class="imgOne right">
&lt;p>Install Apache 2 web server automatically. Serves a web site on the front page of http://localhost. Pages can be edited as a normal user - without root or sudo.&lt;/p>
&lt;p>Simplified Ansible role. An example of &lt;em>package-file-server&lt;/em> pattern. Just notes, no tutorial.&lt;/p>
&lt;p>Using these short notes require a working Ansible configuration - &lt;a href="https://terokarvinen.com/hello-ansible/">Hello Ansible&lt;/a>.&lt;/p>
&lt;h2 id="package-file-service-pattern">Package-file-service pattern&lt;/h2>
&lt;p>Daemons, like Apache2 web server, are somewhat similar. They are configured with package-file-service pattern. Install the daemon, change configuration by editing files, start it.&lt;/p>
&lt;ul>
&lt;li>package - sudo apt-get install apache2&lt;/li>
&lt;li>files - sudoedit /etc/apache2/...&lt;/li>
&lt;li>service - sudo systemctl restart apache2&lt;/li>
&lt;/ul>
&lt;p>Changes to configuration files only take effect after you kick the daemon. Thus, &lt;em>file&lt;/em> in tasks/main.yml &lt;em>notify&lt;/em> the &lt;em>handler&lt;/em> &amp;quot;restart apache2&amp;quot;.&lt;/p>
&lt;h2 id="tree-of-rolesapache2">tree of roles/apache2/&lt;/h2>
&lt;pre>&lt;code>roles/apache2/ # All files related to &amp;quot;apache2&amp;quot; role
├── files/ # Master copies of files
│   └── example.com.conf
├── handlers/ # restarting services
│   └── main.yml
└── tasks/ # most ansible code
└── main.yml
&lt;/code>&lt;/pre>
&lt;h2 id="tasksmainyml">tasks/main.yml&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>- &lt;span style="color:#309;font-weight:bold">apt&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apache2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">state&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>present&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#309;font-weight:bold">copy&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">dest&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;/etc/apache2/sites-available/example.com.conf&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">src&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;example.com.conf&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">owner&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;root&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;root&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">mode&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;0644&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">notify&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>restart apache2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#309;font-weight:bold">file&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">src&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/etc/apache2/sites-available/example.com.conf&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">dest&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>/etc/apache2/sites-enabled/example.com.conf&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">owner&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>root&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>root&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">state&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>link&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">notify&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>restart apache2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="handlersmainyml">handlers/main.yml&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>- &lt;span style="color:#309;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>restart apache2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">systemd&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>apache2&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">state&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>restarted&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="filesexamplecomconf">files/example.com.conf&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-fallback" data-lang="fallback">&lt;span style="display:flex;">&lt;span># Managed file, changes will be overwritten
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;VirtualHost *:80&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ServerName example.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> DocumentRoot /home/tero/publicsite/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;Directory /home/tero/publicsite/&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> require all granted
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/Directory&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/VirtualHost&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="adminstrivia">Adminstrivia&lt;/h2>
&lt;p>Apache httpd logo is a trademark of The Apache Software Foundation.&lt;/p></description></item><item><title>Passwordless Sudo with Ansible</title><link>https://terokarvinen.com/passwordless-sudo-with-ansible/</link><pubDate>Thu, 02 Apr 2026 16:44:50 +0300</pubDate><guid>https://terokarvinen.com/passwordless-sudo-with-ansible/</guid><description>
&lt;p>Sudo without password, automatically. Short example role for ansible.&lt;/p>
&lt;p>The role&lt;/p>
&lt;ul>
&lt;li>creates a new user in &amp;quot;sudoless&amp;quot; group&lt;/li>
&lt;li>adds a sudoers.d/ NOPASSWD rule for the group&lt;/li>
&lt;/ul>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;p>Applying this example file requires you to have &lt;a href="https://terokarvinen.com/hello-ansible/">Ansible working&lt;/a>.&lt;/p>
&lt;p>Tero's rule #1 for IaC: &lt;em>Manual before auto.&lt;/em>&lt;/p>
&lt;p>So it's a good idea to try creating &lt;a href="https://terokarvinen.com/passwordless-sudo/">passwordless sudo manually&lt;/a> first.&lt;/p>
&lt;p>&lt;em>Draft: This article has commands written from memory. It has not gone trough quality assuarance and testing yet.&lt;/em>&lt;/p>
&lt;h2 id="tree">Tree&lt;/h2>
&lt;pre>&lt;code>$ tree -F
./
├── ansible.cfg
├── hosts.ini
├── roles/
│   ├── antero/
│   │   └── tasks/
│   │   └── main.yml
│   └── world/
│   └── tasks/
│   └── main.yml
└── site.yml
&lt;/code>&lt;/pre>
&lt;h2 id="role---antero">Role - antero&lt;/h2>
&lt;p>cat roles/antero/tasks/main.yml&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>- &lt;span style="color:#309;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;sudoless&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">state&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>present&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#309;font-weight:bold">user&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">name&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;antero&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">state&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>present&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">groups&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>[&lt;span style="color:#c30">&amp;#34;sudoless&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;sudo&amp;#34;&lt;/span>,&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;adm&amp;#34;&lt;/span>]&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#309;font-weight:bold">authorized_key&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">user&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;antero&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">key&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;ssh-ed25519 U2VlIHlvdSBhdCBUZXJvS2FydmluZW4uY29tIQ== tero@example.com&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb">&lt;/span>- &lt;span style="color:#309;font-weight:bold">copy&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">dest&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;/etc/sudoers.d/sudoless&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">content&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;%sudoless ALL = (ALL) NOPASSWD: ALL\n&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">owner&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;root&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">group&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;root&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">mode&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#c30">&amp;#34;0644&amp;#34;&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="first-run---chicken-or-egg">First run - chicken or egg?&lt;/h2>
&lt;p>For the first run, you don't yet have sudo without password.&lt;/p>
&lt;p>Let's make ansible try for sudo rights. Add &amp;quot;become: true&amp;quot; in the correct block in site.yml:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>- &lt;span style="color:#309;font-weight:bold">hosts&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>all&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">become&lt;/span>:&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#069;font-weight:bold">true&lt;/span>&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>&lt;span style="color:#309;font-weight:bold">roles&lt;/span>:&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- world&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#bbb"> &lt;/span>- antero&lt;span style="color:#bbb">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>$ ansible-playbook site.yml
&lt;/code>&lt;/pre>
&lt;p>Now it should complain that sudo needs password. Ansible asks this with -K aka --ask-become-password.&lt;/p>
&lt;pre>&lt;code>$ ansible-playbook site.yml --ask-become-password
&lt;/code>&lt;/pre>
&lt;h2 id="tips">Tips&lt;/h2>
&lt;p>When you got it to work manually, you have your example. Copy it to automation!&lt;/p>
&lt;ul>
&lt;li>Copy paste paths.&lt;/li>
&lt;li>Copy files or file contents.&lt;/li>
&lt;li>Use 'stat' to check for modes (permissions). Do not guess octal permissions, you have to understand them to avoid privesc worries.&lt;/li>
&lt;/ul>
&lt;p>Some IaC programs only reliably understand octal modes (numbers), and only as strings. I would also recommend explicit leading zero meaning no special permissions (no setgid...). So &amp;quot;0644&amp;quot;, in quotes. Maybe it has improved over the years? Who knows.&lt;/p></description></item><item><title>Sudo without password</title><link>https://terokarvinen.com/passwordless-sudo/</link><pubDate>Thu, 02 Apr 2026 16:04:03 +0300</pubDate><guid>https://terokarvinen.com/passwordless-sudo/</guid><description>
&lt;p>Ansible needs root on the slave. One way is to allow 'sudo' without password.&lt;/p>
&lt;p>Summary for gurus (the rest of us can read the article):&lt;/p>
&lt;pre>&lt;code>$ cat /etc/sudoers.d/sudoless
%sudoless ALL = (ALL) NOPASSWD: ALL
&lt;/code>&lt;/pre>
&lt;p>&lt;em>Draft: This article has commands written from memory. It has not gone trough quality assuarance and testing yet.&lt;/em>&lt;/p>
&lt;img src="https://terokarvinen.com/passwordless-sudo/sudo-logo_hu90c7c77f1bb985b8b0dfccb8c62285a4_186853_400x400_fit_box_3.png" width="358" height="400" alt=" " class="imgOne right">
&lt;p>This short tutorial assumes you know the &lt;a href="https://terokarvinen.com/2020/command-line-basics-revisited/">basics of Linux command line&lt;/a> and have &lt;a href="https://terokarvinen.com/ssh-public-key-login-without-password/">installed openssh-server&lt;/a>.&lt;/p>
&lt;h2 id="create-the-new-user">Create the new user&lt;/h2>
&lt;p>Let's create a user and add it to &amp;quot;sudoless&amp;quot; group that we'll set up later. We'll call him antero, a neologism from &amp;quot;Ansible&amp;quot; and &amp;quot;Tero&amp;quot;, yours truly.&lt;/p>
&lt;p>Always use only good passwords. Never use bad passwords, even for a moment. Practice doing it right, don't practice doing it wrong.&lt;/p>
&lt;pre>&lt;code>$ sudo adduser antero
$ sudo groupadd sudoless
$ sudo adduser antero sudoless
&lt;/code>&lt;/pre>
&lt;h2 id="broken-sudo-insurance">Broken sudo insurance&lt;/h2>
&lt;p>Open a new window, ssh to target machine as needed. Then open a root shell using sudo.&lt;/p>
&lt;p>If we break sudo, this might be a way to fix it. Otherwise, broken sudo prevents us from using sudo to fix the broken files.&lt;/p>
&lt;pre>&lt;code>$ sudo -i # just while fiddling with sudoers
&lt;/code>&lt;/pre>
&lt;p>We don't wont to work in the root shell (where the prompt is a hash &amp;quot;#&amp;quot;).&lt;/p>
&lt;p>So leave the root shell window behind and go back to the normal window.&lt;/p>
&lt;h2 id="new-sudoers-rule">New sudoers rule&lt;/h2>
&lt;p>Let's create a sudoers rule that allows members of &amp;quot;sudoless&amp;quot; group use 'sudo' without password.&lt;/p>
&lt;p>Visudo runs our default $EDITOR. But has some checks for obvious errors.&lt;/p>
&lt;p>As usual, we'll use .d/ dirs if available. And luckily, sudoers has /etc/sudoers.d/.&lt;/p>
&lt;pre>&lt;code>$ sudo visudo /etc/sudoers.d/sudoless
&lt;/code>&lt;/pre>
&lt;p>Add our oneliner there&lt;/p>
&lt;pre>&lt;code>%sudoless ALL = (ALL) NOPASSWD: ALL
&lt;/code>&lt;/pre>
&lt;p>What does the sudoers line mean?&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Token&lt;/th>
&lt;th>Meaning&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>%sudoless&lt;/td>
&lt;td>Percent &amp;quot;%&amp;quot; means group&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ALL&lt;/td>
&lt;td>All computers&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>=&lt;/td>
&lt;td>Literal equals &amp;quot;=&amp;quot;, a separator&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>(ALL)&lt;/td>
&lt;td>Runas: may become any user, including root&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>NOPASSWD&lt;/td>
&lt;td>Tag: don't prompt for password&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>:&lt;/td>
&lt;td>Literal colon &amp;quot;:&amp;quot;, a separator&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ALL&lt;/td>
&lt;td>All commands permitted&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>So it's something like:&lt;/p>
&lt;pre>&lt;code>%group COMPUTERS: (RUNAS) TAG: COMMANDS.
&lt;/code>&lt;/pre>
&lt;h2 id="test">Test&lt;/h2>
&lt;p>&lt;em>not tested == not done&lt;/em>&lt;/p>
&lt;p>New groups are effective only after logout-login. So if you're logged in as &amp;quot;antero&amp;quot;, log out and back.&lt;/p>
&lt;p>If you have recently given 'sudo' commands as &amp;quot;antero&amp;quot;, sudo will remember your credentials for a while. Use 'sudo -k' to forget them.&lt;/p>
&lt;pre>&lt;code>$ ssh antero@localhost
$ sudo -k
$ sudo echo &amp;quot;See you at TeroKarvinen.com&amp;quot;
See you at TeroKarvinen.com
&lt;/code>&lt;/pre>
&lt;p>No password asked? Great! You now have passwordless sudo. You could use it with Ansible.&lt;/p>
&lt;h2 id="adminstrivia">Adminstrivia&lt;/h2>
&lt;p>Sudo logo my Mark Stillman 2019, received under CC-BY-4.0.&lt;/p></description></item><item><title>DORA &amp; Threat Lead Penetration Testing with Marko</title><link>https://terokarvinen.com/buuri-2026-dora-and-threat-lead-penetration-testing/</link><pubDate>Tue, 31 Mar 2026 14:54:33 +0300</pubDate><guid>https://terokarvinen.com/buuri-2026-dora-and-threat-lead-penetration-testing/</guid><description>
&lt;p>Banks are now required to do red teaming exercises. Marko Buuri (Bank of Finland) showed us how TIBER-FI helps to create threat intel based red teaming exercises.&lt;/p>
&lt;p>Marko's visit was part of my &lt;a href="https://terokarvinen.com/tunkeutumistestaus/">Penetration Testing&lt;/a> course. You can &lt;a href="https://terokarvinen.com/newsletter/">join my list&lt;/a> to get invitations to similar events.&lt;/p>
&lt;h2 id="synopsis">Synopsis&lt;/h2>
&lt;img src="https://terokarvinen.com/buuri-2026-dora-and-threat-lead-penetration-testing/mark-buuri-talks-tiber-in-teros-pentest-course_hu09239795106670e281e38133c0de53b3_296907_400x400_fit_box.png" width="400" height="217" alt=" " class="imgOne right padSides">
&lt;p>Cybersecurity red team testing has evolved from underground art to regulated operations in the European financial sector. This lecture explores the requirement for advanced threat-led penetration testing in EU's DORA regulation, and practical guidance on how those projects are organized and delivered according to the TIBER-EU guidance across Europe.&lt;/p>
&lt;h2 id="slides">Slides&lt;/h2>
&lt;p>Buuri 2026: &lt;a href="buuri-2026-dora-and-threat-lead-penetration-testing--teros-pentest-course.pdf">DORA and TLPT testing - Lecture for Haaga-Helia on 31 March 2026&lt;/a> (pdf, 2 MB)&lt;/p>
&lt;h2 id="links">Links&lt;/h2>
&lt;p>&lt;a href="https://eur-lex.europa.eu/eli/reg/2022/2554/oj/eng">DORA (Regulation ... on digital operational resilience for the financial sector)&lt;/a>&lt;/p>
&lt;ul>
&lt;li>Article 26 defines threat-lead penetration testing. &amp;quot;Advanced testing of ICT tools, systems and processes based on TLPT&amp;quot;&lt;/li>
&lt;li>Article 27 defines the requirements for the testers. &amp;quot;Requirements for testers for the carrying out of TLPT&amp;quot;&lt;/li>
&lt;/ul>
&lt;p>Bank of Finland (Suomen Pankki): &lt;a href="https://www.suomenpankki.fi/tiberfi">TIBER-FI and TIBER-EU guidance&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.suomenpankki.fi/globalassets/bof/en/money-and-payments/the-bank-of-finland-as-catalyst-payments-council/tiber-fi/tiber-fi-2.0-procedures-and-guidelines.pdf">TIBER-FI procedures and guidelines&lt;/a> (pdf, 1 MB)&lt;/li>
&lt;/ul>
&lt;p>Buuri 2026: &lt;a href="https://youtu.be/z6KIEEknKjM?si=7n8cNWynzMrEwdWZ">D26 - Releasing Your Inner TIBER in Regulated Adversary Simulations&lt;/a>. Video, 45 min. Disobey 2026.&lt;/p>
&lt;h2 id="slides-taster">Slides taster&lt;/h2>
&lt;p>You can &lt;a href="buuri-2026-dora-and-threat-lead-penetration-testing--teros-pentest-course.pdf">download the whole deck&lt;/a>.&lt;/p>
&lt;p>&lt;img src="slide-07-buuri-2026-dora-and-threat-lead-penetration-testing--teros-pentest-course.png" alt="">&lt;/p>
&lt;p>&lt;img src="slide-22-buuri-2026-dora-and-threat-lead-penetration-testing--teros-pentest-course.png" alt="">&lt;/p>
&lt;p>&lt;img src="slide-32-buuri-2026-dora-and-threat-lead-penetration-testing--teros-pentest-course.png" alt="">&lt;/p>
&lt;h2 id="bio">Bio&lt;/h2>
&lt;p>Marko Buuri is cyber security adviser in the Bank of Finland (Suomen Pankki). He has over 20 years of in-house and consulting cyber experience. Since 2020 he's been involved in implementing and operating TIBER-FI red team testing framework for the financial sector in Finland.&lt;/p></description></item><item><title>SSH public key - Login without password</title><link>https://terokarvinen.com/ssh-public-key-login-without-password/</link><pubDate>Thu, 26 Mar 2026 14:50:58 +0200</pubDate><guid>https://terokarvinen.com/ssh-public-key-login-without-password/</guid><description>
&lt;p>SSH is the leading solution for securily logging into servers.&lt;/p>
&lt;p>Many products use SSH in the background: git, rsync, ansible...&lt;/p>
&lt;p>Public key authentication is quite convenient. You don't need to type your password for every 'git push' or 'ansible-playbook'. Use correctly, it can also make your server more secure.&lt;/p>
&lt;p>This example is written for Debian 13-trixie.&lt;/p>
&lt;p>&lt;em>Draft: This article has commands written from memory. It has not gone trough quality assuarance and testing yet.&lt;/em>&lt;/p>
&lt;h2 id="install-ssh">Install SSH&lt;/h2>
&lt;p>Install the OpenSSH-server package&lt;/p>
&lt;pre>&lt;code>$ sudo apt-get update
$ sudo apt-get -y install ssh
&lt;/code>&lt;/pre>
&lt;p>Make SSH daemon start on boot (enable) and also start it now (--now)&lt;/p>
&lt;pre>&lt;code>$ sudo systemctl enable --now ssh
&lt;/code>&lt;/pre>
&lt;h3 id="test-ssh">Test SSH&lt;/h3>
&lt;p>Normally, you would say user@host, such as &lt;a href="mailto:tero@example.com">tero@example.com&lt;/a>. Here, we can leave out username, as it's the same on both machines.&lt;/p>
&lt;pre>&lt;code>$ ssh localhost
&lt;/code>&lt;/pre>
&lt;p>With 'w', you can see yourself logged in twice: once on the desktop, once trough ssh.&lt;/p>
&lt;pre>&lt;code>remote$ exit
&lt;/code>&lt;/pre>
&lt;h3 id="automatic-login-with-ssh-public-key">Automatic login with SSH public key&lt;/h3>
&lt;p>Generate a keypair&lt;/p>
&lt;pre>&lt;code>$ ssh-keygen # enter enter enter to accept the defaults
&lt;/code>&lt;/pre>
&lt;p>If you already have a keypair, don't overwrite it. The public key ($HOME/.ssh/id_*.pub) is literally public, you can use the same public key in all hosts. The public key ends with &amp;quot;.pub&amp;quot;.&lt;/p>
&lt;p>If you need the public key for VPS (virtual private server) provider, you can see and copy-paste your keys with 'head $HOME/.ssh/id*.pub'.&lt;/p>
&lt;p>Copy it to hosts where you can already log in.&lt;/p>
&lt;pre>&lt;code>$ ssh-copy-id localhost
&lt;/code>&lt;/pre>
&lt;p>Once you've entered your password for the last time, ssh-copy-id adds your public key into .ssh/authorized_keys on the remote machine. Now your key is authorized for logins.&lt;/p>
&lt;p>Your public key is used automatically&lt;/p>
&lt;pre>&lt;code>$ ssh localhost
&lt;/code>&lt;/pre>
&lt;p>Did you log in without giving your password?&lt;/p>
&lt;p>Well done, you've now automated login with SSH public keys.&lt;/p>
&lt;h2 id="troubleshooting">Troubleshooting&lt;/h2>
&lt;p>Here are some helpfull troubleshooting commands.&lt;/p>
&lt;p>Client side:&lt;/p>
&lt;pre>&lt;code>$ ssh -v localhost
&lt;/code>&lt;/pre>
&lt;p>Server side:&lt;/p>
&lt;pre>&lt;code>$ sudo journalctl --follow
$ sudo systemctl status ssh
&lt;/code>&lt;/pre></description></item><item><title>Hello Ansible</title><link>https://terokarvinen.com/hello-ansible/</link><pubDate>Thu, 26 Mar 2026 14:39:42 +0200</pubDate><guid>https://terokarvinen.com/hello-ansible/</guid><description>
&lt;p>Write infrastructure-as-code, control multiple machines easily.&lt;/p>
&lt;p>In this Ansible tutorial, we create a single file in /tmp/.&lt;/p>
&lt;p>In this whole tutorial, we'll create only &lt;a href="#endresult">4 folders and 4 short files&lt;/a>. But I'll show you how to build it step by step, so you can understand and adapt the process.&lt;/p>
&lt;p>&lt;em>Draft: This article has commands written from memory. It has not gone trough quality assuarance and testing yet.&lt;/em>&lt;/p>
&lt;h2 id="background">Background&lt;/h2>
&lt;p>Ansible is a configuration management tool. You write your infrastructure as code (IaC). You describe the end state, and ansible only makes changes if they are needed.&lt;/p>
&lt;p>Ansible works trough SSH. Thus, the slave computers only need SSH daemon and Python installed.&lt;/p>
&lt;p>This tutorial is tested with Debian 13-Trixie. You can probably adapt it to other Linuxes, like Kali or Ubuntu. We'll use ssh daemon on the same host for testing, so the master and the slave are the same computer here.&lt;/p>
&lt;h2 id="test-ssh-account-without-ansible">Test SSH account (without Ansible)&lt;/h2>
&lt;p>Ansible works trough SSH. Let's first test that we can use SSH without Ansbile.&lt;/p>
&lt;p>It's advertised as &amp;quot;agentless&amp;quot;, and indeed there is no slave daemon for ansible. It still needs SSH daemon and Python on slave machine. Ansible (the command) is only needed on master side. Master computer is also known as &amp;quot;controller&amp;quot; in Ansible lingo.&lt;/p>
&lt;p>It's a good idea to set up passwordless SSH authentication for the account used with ansible. Check out Karvinen 2026: &lt;a href="https://terokarvinen.com/ssh-public-key-login-without-password/">SSH public key - Login without password&lt;/a>.&lt;/p>
&lt;pre>&lt;code>$ ssh localhost
remote$ exit
&lt;/code>&lt;/pre>
&lt;h2 id="install-ansible">Install Ansible&lt;/h2>
&lt;p>Ansible is convenintly in Debian repositories.&lt;/p>
&lt;pre>&lt;code>$ sudo apt-get update
$ sudo apt-get install ansible micro bash-completion tree
&lt;/code>&lt;/pre>
&lt;p>Only ansible is really needed. Extras make it easier to work:
- micro (text editor)
- bash-completion (tab fills current word)
- tree (show a tree of files and folders)&lt;/p>
&lt;h2 id="test-ssh-with-ansible">Test SSH with Ansible&lt;/h2>
&lt;p>Let's make a folder for our Ansible configuration.&lt;/p>
&lt;pre>&lt;code>$ cd
$ mkdir ansible/
$ cd ansible/
&lt;/code>&lt;/pre>
&lt;p>Let's write a list of hosts we'll be controlling. Create &amp;quot;hosts.ini&amp;quot;, and add &amp;quot;localhost&amp;quot; there.&lt;/p>
&lt;pre>&lt;code>$ micro hosts.ini
$ cat hosts.ini
localhost
&lt;/code>&lt;/pre>
&lt;p>Later, we can add more hosts. One line per host. The hosts can be grouped, so we can have hosts in &amp;quot;web&amp;quot; category and five in &amp;quot;db&amp;quot;.&lt;/p>
&lt;p>Now we can make Ansible run a command on all hosts.&lt;/p>
&lt;pre>&lt;code>$ ansible all -a 'uptime' -i hosts.ini
...
localhost | CHANGED | rc=0 &amp;gt;&amp;gt;
15:24:39 up 14 days, 20:36, 2 users, load average: 0.55, 0.44, 0.47
&lt;/code>&lt;/pre>
&lt;p>We're just testing ansible here. If we just wanted to run command on remote machine, we could have 'ssh localhost &amp;quot;uptime&amp;quot;'.&lt;/p>
&lt;p>Did you see the uptime? Great, Ansible can now use SSH to one host.&lt;/p>
&lt;p>&amp;lt;a name=&amp;quot;pythonversion&amp;quot;&lt;/p>
&lt;h2 id="convenience-stop-whining-about-python-version">Convenience: Stop whining about Python version&lt;/h2>
&lt;p>Why does Ansible have to whine about Python version? Oh, it could change - who could have guessed...&lt;/p>
&lt;pre>&lt;code>$ ansible all -a 'uptime' -i hosts.ini
[WARNING]: Host 'localhost' is using the discovered Python interpreter at '/usr/bin/python3.13', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/2.19/reference_appendices/interpreter_discovery.html for more information.
localhost | CHANGED | rc=0 &amp;gt;&amp;gt;
15:29:24 up 14 days, 20:41, 2 users, load average: 0.27, 0.29, 0.39
&lt;/code>&lt;/pre>
&lt;p>Let's tell it to use the obvious Python command. We can add variables to host groups in inventory. This one we'll add to all.&lt;/p>
&lt;pre>&lt;code>$ micro hosts.ini
$ cat hosts.ini
localhost
[all:vars]
ansible_python_interpreter=/usr/bin/python3
&lt;/code>&lt;/pre>
&lt;p>So our only host &amp;quot;localhost&amp;quot; at the top, and variables for all hosts at the bottom.&lt;/p>
&lt;p>Let's try again:&lt;/p>
&lt;pre>&lt;code>ansible$ ansible all -a 'uptime' -i hosts.ini
localhost | CHANGED | rc=0 &amp;gt;&amp;gt;
15:31:18 up 14 days, 20:43, 2 users, load average: 0.18, 0.27, 0.37
&lt;/code>&lt;/pre>
&lt;p>We can see that the Python version warning is gone.&lt;/p>
&lt;a name="autoinventory">
&lt;h2 id="convenience-just-use-my-hostsini">Convenience: Just use my hosts.ini&lt;/h2>
&lt;p>Don't want to write &amp;quot;-i hosts.ini&amp;quot; for each 'ansible' and 'ansible-playbook' command?&lt;/p>
&lt;p>You can add hosts.ini to ansible.cfg, so you don't need to add it to each command line.&lt;/p>
&lt;pre>&lt;code>$ micro ansible.cfg
$ cat ansible.cfg
[defaults]
inventory = hosts.ini
&lt;/code>&lt;/pre>
&lt;p>Now we don't need to add &amp;quot;-i hosts.ini&amp;quot; to every 'ansible' and 'ansbile-playbook' commands.&lt;/p>
&lt;pre>&lt;code>$ ansible all -a &amp;quot;uptime&amp;quot;
localhost | CHANGED | rc=0 &amp;gt;&amp;gt;
15:22:18 up 14 days, 20:34, 2 users, load average: 0.35, 0.37, 0.46
&lt;/code>&lt;/pre>
&lt;h2 id="siteyml---what-computers-get-which-roles">Site.yml - what computers get which roles&lt;/h2>
&lt;p>Site.yml lists wich groups of computers get which configuration (roles).&lt;/p>
&lt;p>We want all computers to get the role &amp;quot;hello&amp;quot;. We have not written the role yet.&lt;/p>
&lt;pre>&lt;code>$ micro site.yml
$ cat site.yml
- hosts: all
roles:
- hello
&lt;/code>&lt;/pre>
&lt;p>Let's run our new playbook, site.yml&lt;/p>
&lt;pre>&lt;code>$ ansible-playbook site.yml
[ERROR]: the role 'hello' was not found in /home/tero/code/terokarvinen-com/ansible/roles/:...
Origin: /home/tero/code/terokarvinen-com/ansible/site.yml:3:7
1 - hosts: all
2 roles:
3 - hello
^ column 7
&lt;/code>&lt;/pre>
&lt;p>Great, an error message! Most error messages bring us two letters: good news and bad news.&lt;/p>
&lt;ul>
&lt;li>Good news: ansible-playbook has read our file, site.yml. It's even quoting some text from it.&lt;/li>
&lt;li>Bad news: the role &amp;quot;hello&amp;quot; does not exist. Well, we have not written it yet.&lt;/li>
&lt;/ul>
&lt;h2 id="first-role---create-a-file">First role - create a file&lt;/h2>
&lt;p>Role is one configured thing, for example nginx, apache2, postgresql...&lt;/p>
&lt;p>But first, we'll create a &amp;quot;hello&amp;quot; role. It will create a file in /tmp/, on the slave computer. It's so simple it doesn't even need sudo.&lt;/p>
&lt;p>Roles are in roles/ folder. There could be roles/nginx/, roles/postgresql/... But here, we'll have roles/hello/.&lt;/p>
&lt;p>Each role folder will have standard subfolders. We'll just have tasks/. Often, we'll also see handlers/ for kicking daemons. The entry point, the code that get's run automatically, is in main.yml.&lt;/p>
&lt;pre>&lt;code>$ mkdir -p roles/hello/tasks/
$ micro roles/hello/tasks/main.yml
$ cat roles/hello/tasks/main.yml
- copy:
dest: /tmp/hello-ansible
content: &amp;quot;See you at TeroKarvinen.com!\n&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>Let's run our playbook. Site.yml calls roles/hello/, tasks/main.yml is run automatically:&lt;/p>
&lt;pre>&lt;code>$ ansible-playbook site.yml
PLAY [all]
TASK [Gathering Facts]
ok: [localhost]
TASK [hello : copy]
changed: [localhost]
PLAY RECAP
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
&lt;/code>&lt;/pre>
&lt;p>Hey, it has &amp;quot;changed=1&amp;quot;. So it claims to have changed the file on the slave.&lt;/p>
&lt;p>Let's verify using a different tool.&lt;/p>
&lt;pre>&lt;code>$ ssh localhost 'cat /tmp/hello-ansible'
See you at TeroKarvinen.com!
&lt;/code>&lt;/pre>
&lt;p>Did you see the file on slave? Great, your first &amp;quot;Hello, Ansible world&amp;quot; has run.&lt;/p>
&lt;h2 id="convenience-show-me-what-you-do">Convenience: Show me what you do&lt;/h2>
&lt;p>Default is pretty terse:&lt;/p>
&lt;pre>&lt;code>TASK [hello : copy]
changed: [localhost]
&lt;/code>&lt;/pre>
&lt;p>A popular solution would be giving each task a name that repeats the code: &amp;quot;Copy our hello world text to the file /tmp/hello&amp;quot;. To me, this would be similar to this C code: &amp;quot;i++; // increment the value of i by one&amp;quot;. It would make sense to name a block of tasks in ansible, but this is not supported yet.&lt;/p>
&lt;p>Luckily, we can make ansible print what it does. Add display_args_to_stdout:&lt;/p>
&lt;pre>&lt;code>$ micro ansible.cfg
$ cat ansible.cfg
[defaults]
inventory = hosts.ini
display_args_to_stdout = true
&lt;/code>&lt;/pre>
&lt;p>Now, let's run our playbook again:&lt;/p>
&lt;pre>&lt;code>$ ansible-playbook site.yml
...
TASK [hello : copy dest=/tmp/hello-ansible, content=See you at TeroKarvinen.com!
]
ok: [localhost]
&lt;/code>&lt;/pre>
&lt;p>Now we can see what it does:&lt;/p>
&lt;pre>&lt;code>- old: &amp;quot;hello : copy&amp;quot;
- new: &amp;quot;hello : copy dest=/tmp/hello-ansible, content=See you at TeroKarvinen.com!&amp;quot;
&lt;/code>&lt;/pre>
&lt;a name="endresult">
&lt;h2 id="end-result">End result&lt;/h2>
&lt;p>This is what we have in the end&lt;/p>
&lt;pre>&lt;code>$ tree -F
./
├── ansible.cfg # generic configuration
├── hosts.ini # list of slave computers
├── roles/
│   └── hello/
│   └── tasks/
│   └── main.yml # code for &amp;quot;hello&amp;quot; role&amp;quot;
└── site.yml # which roles run on which slave
4 directories, 4 files
$ head -1000 ansible.cfg hosts.ini site.yml roles/hello/tasks/main.yml
==&amp;gt; ansible.cfg &amp;lt;== # generic configuration
[defaults]
inventory = hosts.ini
display_args_to_stdout = true
==&amp;gt; hosts.ini &amp;lt;== # list of slave computers
localhost
[all:vars]
ansible_python_interpreter=/usr/bin/python3
==&amp;gt; site.yml &amp;lt;== # which roles run on which slave
- hosts: all
roles:
- hello
==&amp;gt; roles/hello/tasks/main.yml &amp;lt;== # code for &amp;quot;hello&amp;quot; role
- copy:
dest: /tmp/hello-ansible
content: &amp;quot;See you at TeroKarvinen.com!\n&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>And to run it all, we just run the playbook:&lt;/p>
&lt;pre>&lt;code>$ ansible-playbook site.yml
...
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
&lt;/code>&lt;/pre>
&lt;h2 id="troubleshooting-ansible">Troubleshooting Ansible&lt;/h2>
&lt;p>No trouble? No troubleshooting needed. Go enjoy your ansible!&lt;/p>
&lt;h3 id="no-inventory">No inventory&lt;/h3>
&lt;pre>&lt;code>$ ansible all -a &amp;quot;uptime&amp;quot;
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
$
&lt;/code>&lt;/pre>
&lt;p>See: &lt;a href="#autoinventory">Convenience: Just use my hosts.ini&lt;/a>&lt;/p>
&lt;p>Ansible does not detect hosts &lt;em>inventory&lt;/em> hosts.ini automatically. Use a command line flag for that:&lt;/p>
&lt;pre>&lt;code>$ ansible all -a &amp;quot;uptime&amp;quot; -i hosts.ini
...
localhost | CHANGED | rc=0 &amp;gt;&amp;gt;
15:17:49 up 14 days, 20:29, 2 users, load average: 0.25, 0.41, 0.51
&lt;/code>&lt;/pre>
&lt;p>You can add hosts.ini to ansible.cfg, so you don't need to add it to each command line.&lt;/p>
&lt;pre>&lt;code>$ micro ansible.cfg
$ cat ansible.cfg
[defaults]
inventory = hosts.ini
&lt;/code>&lt;/pre>
&lt;p>Now we don't need to add &amp;quot;-i hosts.ini&amp;quot; to every 'ansible' and 'ansbile-playbook' commands.&lt;/p>
&lt;pre>&lt;code>$ ansible all -a &amp;quot;uptime&amp;quot;
...
localhost | CHANGED | rc=0 &amp;gt;&amp;gt;
15:22:18 up 14 days, 20:34, 2 users, load average: 0.35, 0.37, 0.46
&lt;/code>&lt;/pre>
&lt;h3 id="discovered-python-interpreter">Discovered Python interpreter&lt;/h3>
&lt;pre>&lt;code>$ ansible all -a 'uptime' -i hosts.ini
[WARNING]: Host 'localhost' is using the discovered Python interpreter at '/usr/bin/python3.13', but future installation of another Python interpreter could cause a different interpreter to be discovered. See https://docs.ansible.com/ansible-core/2.19/reference_appendices/interpreter_discovery.html for more information.
&lt;/code>&lt;/pre>
&lt;p>See Convenience: &lt;a href="#pythonversion">Stop whining about Python version&lt;/a>.&lt;/p>
&lt;h3 id="indent-is-two-spaces-tabs-are-usually-invalid-in-yaml">Indent is two spaces: Tabs are usually invalid in YAML&lt;/h3>
&lt;p>[ERROR]: YAML parsing failed: Tabs are usually invalid in YAML.&lt;/p>
&lt;p>Yes, my brain hurts, too. Why can't YAML use tabs like normal people?&lt;/p>
&lt;p>You must indent with spaces. Each indent is two spaces. The error message will show where the mistake is:&lt;/p>
&lt;pre>&lt;code>[ERROR]: YAML parsing failed: Tabs are usually invalid in YAML.
Origin: ...ansible/site.yml:3:1
1 - hosts: all
2 roles:
3 - hello
^ column 1
&lt;/code>&lt;/pre>
&lt;h3 id="indent-ignores-the-dash-conflicting-action-statements">Indent ignores the dash: conflicting action statements&lt;/h3>
&lt;p>[ERROR]: conflicting action statements: copy, dest
Origin: ...ansible/roles/hello/tasks/main.yml:1:3&lt;/p>
&lt;p>1 - copy:
^ column 3&lt;/p>
&lt;pre>&lt;code>$ cat roles/hello/tasks/main.yml
- copy:
dest: /tmp/hello-ansible # WRONG - too little indent
content: &amp;quot;Blah&amp;quot; # WRONG - too little indent
&lt;/code>&lt;/pre>
&lt;p>We want to have &amp;quot;copy&amp;quot;, which has two children, &amp;quot;dest&amp;quot; and &amp;quot;content&amp;quot;.&lt;/p>
&lt;p>Correct:&lt;/p>
&lt;pre>&lt;code>- copy: # no indent, dash is first char on line
dest: /tmp/hello-ansible # four spaces on the left, two spaces from &amp;quot;c&amp;quot; in copy
content: &amp;quot;See you at TeroKarvinen.com!\n&amp;quot; # four spaces on the left, two from &amp;quot;c&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>&amp;quot;But it looks like four&amp;quot; - I know, I know. It's two from the start of the word above, ignoring the dash.&lt;/p>
&lt;h3 id="sudo-needed">Sudo needed&lt;/h3>
&lt;p>After a wait: &amp;quot;Task failed: Module failed: Failed to lock apt for exclusive operation: Failed to lock directory&amp;quot; and other error messages.&lt;/p>
&lt;p>Ansible needs sudo on the slave to do administration. It does not complain when creating files on /tmp/, because anyone can create files there. But as soon as you start doing any normal sysop things, you will need sudo.&lt;/p>
&lt;p>Add &amp;quot;become: true&amp;quot;. That means becoming the sudo user on slave machine.&lt;/p>
&lt;pre>&lt;code>$ cat site.yml
- hosts: all
become: true
roles:
- apt
- sshd
# ...
&lt;/code>&lt;/pre>
&lt;p>Now it will probably complain it does not know your sudo password.&lt;/p>
&lt;pre>&lt;code>$ ansible-playbook site.yml --ask-become-pass
&lt;/code>&lt;/pre>
&lt;p>Now it asks your sudo password before running the commands.&lt;/p>
&lt;p>If you get tired of typing your sudo password, there are many ways around it, with different levels of security. For example, you can create an ansible specific user with passwordless sudo. Or use ansible vault. Or pass. Or even read sudo password from file, which sounds less than secure.&lt;/p></description></item><item><title>Palvelinten Hallinta</title><link>https://terokarvinen.com/palvelinten-hallinta/</link><pubDate>Thu, 26 Mar 2026 09:52:19 +0200</pubDate><guid>https://terokarvinen.com/palvelinten-hallinta/</guid><description>
&lt;p>Control &lt;del>10&lt;/del>, &lt;del>100&lt;/del>, &lt;del>1000&lt;/del> many computers.&lt;/p>
&lt;p>Or control 2071 computers, like Jussi did on a earlier course. Or handle 7 different operating systems and OS versions with a single master, like Matias.&lt;/p>
&lt;p>Best instance got 5.0 / 5 feedback - all respondents gave the best grade 5.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Course, both instances&lt;/th>
&lt;th>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Course name and code&lt;/td>
&lt;td>Palvelinten hallinta &lt;a href="https://opinto-opas.haaga-helia.fi/course_unit/ICI001AS3A">ICI001AS3A&lt;/a>-&lt;strong>3011&lt;/strong> and &lt;em>-3013&lt;/em>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Timing&lt;/td>
&lt;td>2026 period 4, &lt;strong>late spring&lt;/strong>, w13-w20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Credits&lt;/td>
&lt;td>5 cr&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Language&lt;/td>
&lt;td>&lt;strong>Finnish&lt;/strong> (+reading material in English)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Feedback&lt;/td>
&lt;td>Reached 5.0 / 5 * &lt;strong>&lt;a href="#comments">Excellent feedback&lt;/a>&lt;/strong> &lt;img src="https://terokarvinen.com/img/five-stars-15.png" alt="Five star experience">&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Classes&lt;/td>
&lt;td>-3011 online ke 17:40-20:30. -3013 pa5001 to 11:00-13:45. Both have mandatory participation.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Max students&lt;/td>
&lt;td>50 online, 40 Pasila. (Come to the first class if you're queuing for place)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Remote&lt;/td>
&lt;td>One course instance -3011 is fully remote. Other -3013 is face-to-face in Pasila pa5001.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>First class&lt;/td>
&lt;td>Online-3011 2026-03-25 w13 Wed 17:40 Zoom. Pasila-3013 2026-03-26 w13 Thu 11:00 pa5001, bring laptop.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Services&lt;/td>
&lt;td>Moodle: Palvelinten hallinta &lt;a href="https://hhmoodle.haaga-helia.fi/course/view.php?id=45174">-3011 online Wednesday evening&lt;/a>; &lt;a href="https://hhmoodle.haaga-helia.fi/course/view.php?id=45176">-3013 Thursday&lt;/a>, Zoom, Laksu. Optional: &lt;a href="https://terokarvinen.com/newsletter/">Tero's list&lt;/a>.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>I've done some research on configuration management systems. I have written my doctoral dissertation on applying malware command and control techniques to benign configuration management systems. I've given an invited speech in IEEE ICIM Chengdu and a plenary speech in IEEE ICIM Oxford; I’ve also been teaching these modern methods to companies. Previous feedback for this course has been from very good 4.3 to excellent &lt;del>4.9&lt;/del> 5.0 out of 5.&lt;/p>
&lt;p>As the course is in Finnish, the rest of this page will be in Finnish.&lt;/p>
&lt;h2 id="opintojakson-suoritettuaan-opiskelija">Opintojakson suoritettuaan opiskelija&lt;/h2>
&lt;ul>
&lt;li>Osaa hallita palvelimia kuvailemalla tavoitetilan (idempotenssi)&lt;/li>
&lt;li>Osaa tehdä asetukset pelkkänä tekstinä ja versioitavasti (infrastruktuuri koodina)&lt;/li>
&lt;li>Pystyy tekemään tavalliset ylläpitotoimet valitulla työkalulla (yksi totuus)&lt;/li>
&lt;/ul>
&lt;h2 id="esitiedot">Esitiedot&lt;/h2>
&lt;p>Esitiedot, kertaa nämä.&lt;/p>
&lt;p>Opettele komennot ja hakemistot ulkoa. Harjoittele niitä kokeilemalla moneen kertaan Linuxissa.&lt;/p>
&lt;ul>
&lt;li>Linuxin komennot, apt &lt;a href="http://terokarvinen.com/2020/command-line-basics-revisited/">Command Line Basics Revisited&lt;/a>&lt;/li>
&lt;li>Tiedostojärjestelmän rakenne (etc, var…). Alkeet löytyvät samasta &lt;a href="http://terokarvinen.com/2020/command-line-basics-revisited/">Command Line Basics Revisited&lt;/a>&lt;/li>
&lt;li>Demonien hallinta (esim Apache) &lt;a href="http://terokarvinen.com/2008/05/02/install-apache-web-server-on-ubuntu-4/index.html">Install Apache Web Server on Ubuntu&lt;/a> (paitsi demonin potkaisu nykyisin 'sudo systemctl restart apache2')&lt;/li>
&lt;li>Linuxin asentaminen virtuaalikoneeseen&lt;/li>
&lt;/ul>
&lt;a name="alustava-aikataulu">
&lt;h2 id="aikataulu">Aikataulu&lt;/h2>
&lt;p>Kurssi kestää 8 viikkoa. Edellyttää aktiivista osallistumista etäopetukseen videokonfferensissa lukkariin merkittynä aikana. Läksyt palautetaan 24 h ennen seuraavan oppitunnin alkua ja ristiinarvioidaan kahden luokkakaverin työt. Tämä alustava aikataulu elää kurssin aikana.&lt;/p>
&lt;p>Tunnit tiistaisin online 08:00 - 10:45 videokonfferenssina.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Päivä&lt;/th>
&lt;th>Aihe&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Perusteet&lt;/strong>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w13&lt;/td>
&lt;td>1. &lt;strong>Hei maailma&lt;/strong>. Järjestäytyminen: osallistujat, kurssin käytänteet. Keskitetyn hallinnan periaateet, infra koodina. Raportit, git web-käyttö, MarkDown kertaus. Hei maailma!&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w14&lt;/td>
&lt;td>2. &lt;strong>Infraa koodina&lt;/strong>. Konfiguraation kirjoittaminen koodiksi.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w15&lt;/td>
&lt;td>3. &lt;strong>Pkg-file-service&lt;/strong> eli demonien hallinta. Käsin tehdyn konfiguraation automatisointi.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w16&lt;/td>
&lt;td>4. &lt;strong>Esimerkkipalvelin&lt;/strong>. Käytännön esimerkki palvelimen konfiguroinnista.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w17&lt;/td>
&lt;td>5. &lt;strong>Versionhallinta&lt;/strong>. Git: init, clone, add, commit, pull, push, log. GitHub ja muut avustavat palvelut. &lt;strong>Omien modulien aloitus.&lt;/strong>, 2 hengen ryhmät.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Soveltaminen&lt;/strong>&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w18&lt;/td>
&lt;td>6. &lt;strong>Soveltaminen&lt;/strong>. Käytännön tekniikoita ja esimerkkejä. Ongelmanratkaisua. / Torstain ryhmällä omien modulien esittely alkaa.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w19&lt;/td>
&lt;td>7. &lt;strong>Omien modulien esittely&lt;/strong> I.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>w20&lt;/td>
&lt;td>8. &lt;strong>Omien modulien esittely&lt;/strong> II. (2026-05-14 w20 Thu on Helatorstai, torstain ryhmällä ei tuntia. Keskiviikon ryhmän online-opetus normaalisti.)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="oheismateriaalia-lukemista-ja-asennuspaketteja">Oheismateriaalia, lukemista ja asennuspaketteja&lt;/h2>
&lt;p>Debian stable 13-trixie levykuva &lt;a href="https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/debian-live-13.4.0-amd64-xfce.iso">debian-live-13.4.0-amd64-xfce.iso&lt;/a> (3.6 GB) Kun uusia versioita tulee, linkki vanhenee. Uusi löytyy &lt;a href="https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/">samasta kansiosta&lt;/a>.&lt;/p>
&lt;p>Karvinen 2021: &lt;a href="https://terokarvinen.com/2021/install-debian-on-virtualbox/">Install Debian on Virtualbox&lt;/a>&lt;/p>
&lt;p>Karvinen 2023: &lt;a href="https://terokarvinen.com/2023/create-a-web-page-using-github/">Create a Web Page Using Github&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://www.virtualbox.org/">VirtualBox.org&lt;/a>&lt;/p>
&lt;p>Karvinen 2020: &lt;a href="https://terokarvinen.com/2020/command-line-basics-revisited/">Command Line Basics Revisited&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://docs.ansible.com/projects/ansible/latest/">Ansible Community Documentation&lt;/a>&lt;/p>
&lt;p>Salo ym 2026: &lt;a href="https://github.com/tommi-vsalo/BlueTeamLab">BlueTeamLab&lt;/a>. Käynnissä olevassa projektissa rakennetaan SOC-harjoitusympäristöä. Linux, Windows, AD. OpenTofu, Ansible. VirtualBoxia ohjataan OpenTofulla.&lt;/p>
&lt;h2 id="arviointi">Arviointi&lt;/h2>
&lt;p>Osien ohjeelliset painoarvot ovat: kotitehtävät 70% ja oma moduli 30%. Arvosana perustuu kokonaisarvioon suorituksista. Kaikki kotitehtävät pitää tehdä ajallaan. Etäopetukseen pitää osallistua aktiivisesti.&lt;/p>
&lt;h2 id="anna-palautetta">Anna palautetta&lt;/h2>
&lt;p>Palaute on todella tärkeä tapa kehittää kurssia – kiitos kommenteista jo etukäteen. Palaute kahteen kanavaan&lt;/p>
&lt;h3 id="1-vapaamuotoinen-palaute-kommenttina-taman-kurssisivun-peraan">1) Vapaamuotoinen palaute kommenttina tämän kurssisivun perään&lt;/h3>
&lt;p>&lt;a href="#comments">Vapaamuotoinen palaute kommenttina tämän kurssisivun perään&lt;/a>&lt;/p>
&lt;p>Vapaamuotoiseen palautteeseen saa kirjoittaa mitä vain, eikä kysymyksiä tarvitse toistaa. Mutta tässä vinkiksi:&lt;/p>
&lt;ul>
&lt;li>Opitko jotakin – eli osaatko nyt sellaista, mitä et osannut ennen kurssia?&lt;/li>
&lt;li>Teitkö jotain ensimmäistä kertaa? Käytit modernia hallintatyökalua (Ansible tms), kirjoitit idempotentin tilan, kirjoitit infraa koodina...&lt;/li>
&lt;li>Oliko opittu hyödyllistä? Luuletko, että voit hyödyntää infraa koodina töissä tai kotona?&lt;/li>
&lt;li>Mitä mieltä olit läksyistä? Luku/video/podcast -materiaalista? Hands-on tehtävistä?&lt;/li>
&lt;li>Mitä pidät miniprojektin valmistelusta ja (tulevista) esityksistä? Itse esittämisestä? Luokkakavereiden esitysten seuraamisesta?&lt;/li>
&lt;li>Miten voisin parantaa kurssia?&lt;/li>
&lt;li>Viihdyitkö kurssilla?&lt;/li>
&lt;li>Suosittelisitko kurssia? Kenelle kurssi sopisi? Koulutoverille tai kollegalle?&lt;/li>
&lt;/ul>
&lt;h3 id="2-numeerinen-palaute-haaga-helian-palautejarjestelmaan-mynetissa">2) Numeerinen palaute Haaga-Helian palautejärjestelmään MyNetissa&lt;/h3>
&lt;p>Numeerinen palaute &lt;a href="https://mynet.haaga-helia.fi">Haaga-Helian palautejärjestelmään MyNetissa&lt;/a>&lt;/p>
&lt;p>Numeerisen palautteen avulla mm. verrataan Haaga-Helian kursseja toisiinsa. On tärkeää saada jokaiselta palaute, jotta tulos on tilastollisesti merkitsevä.&lt;/p>
&lt;p>Numeeriset: Asteikko 1-välttävä (huonoin) ... 5-kiitettävä (paras)&lt;/p>
&lt;ul>
&lt;li>Oma aktiivisuutesi opiskelussa 1-5&lt;/li>
&lt;li>Osaamistavoitteiden saavuttaminen 1-5&lt;/li>
&lt;li>Työskentelytavat tukivat oppimista 1-5&lt;/li>
&lt;li>Opiskeluympäristö tuki oppimista 1-5&lt;/li>
&lt;li>Hyödyllisyys työelämään 1-5&lt;/li>
&lt;/ul>
&lt;p>Avoimet kysymykset (näihin voi myös kopioida samat vastaukset jotka kirjoitit aiemmin)&lt;/p>
&lt;ul>
&lt;li>Mitkä asiat edistivät oppimistasi?&lt;/li>
&lt;li>Miten kehittäisit toteutusta / toteutuskokonaisuutta, jotta osaamistavoitteet saavutettaisiin paremmin?&lt;/li>
&lt;/ul>
&lt;p>Kokonaisarviosi toteutuksesta / toteutuskokonaisuudesta 1-5&lt;/p>
&lt;p>Suosittelisitko 1 - 10 (1 en varmasti, 10 aion varmasti suositella tai olen jo suositellut)&lt;/p>
&lt;p>Kiitos palautteesta ja jännittävästä kurssista! Seuraavilla kursseilla nähdään.&lt;/p>
&lt;h2 id="vanhoja-toteutuksia">Vanhoja toteutuksia&lt;/h2>
&lt;p>&lt;a href="https://terokarvinen.com/2025/palvelinten-hallinta--ici001as3a-3008--2025">Palvelinten hallinta ICI001AS3A-3008 - 2025p2 loppusyksy&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://terokarvinen.com/2024/palvelinten-hallinta-2024p2/">Palvelinten hallinta ICI001AS3A-3010 - 2024 periodi 2, loppusyksy&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://terokarvinen.com/search/?q=palvelinten+hallinta">Vanhoja toteutuksia vuoteen 2018 asti&lt;/a>&lt;/p>
&lt;h2 id="laksyt">Läksyt&lt;/h2>
&lt;p>Palautus 24 h ennen seuraavaa lukujärjestykseen merkittyä aikaa. Weppisivulle (HTML), ja palauta linkki Laksuun. Halutessasi voit laittaa linkin myös kommentiksi tämän sivun perään, niin sivusi saa lisää kävijöitä ja nousee PageRankissa.&lt;/p>
&lt;p>Nämä läksyt ovat alustavia. Läksyt ovat virallisia vasta, kun ne on annettu tunnilla. Tämä on edistynyt kurssi, joten pystymme tekemään muutoksia kurssin kuluessa ja sovittamaan läksyt aiheen mukaan. Jos et uskalla tai muuten halua julkaista, voit laittaa weppisivun salasanan taakse (sama salasana koko kurssille ja jokaiselle tehtävälle, ei kirjautumista eri tunnuksilla eri henkilöille) ja jakaa salasanan kurssilaisten kanssa - mutta suosittelen julkaisua. Kotisivutilaa saa esim wordpress.com, github.com, gitlab.com ja monista muista paikoista.&lt;/p>
&lt;p>Suosittu ja helppo tapa on &lt;a href="https://terokarvinen.com/2023/create-a-web-page-using-github/">laittaa raportit Githubiin&lt;/a>.&lt;/p>
&lt;p>Kaikki käytetyt lähteet tulee merkitä raporttiin: kurssin tehtäväsivu, kurssikavereiden raportit, man-sivut, kirjat. Mikäli tekoälyltä kysyy neuvoa, se on merkittävä lähteeksi. Tekoälyt hallusinoivat, tiedot on suositeltavaa tarkistaa. Tiivistelmiä tai esseitä ei saa generoida tekoälyllä eikä muilla vastaavilla tekniikoilla, vaan ne on kirjoitettava itse.&lt;/p>
&lt;p>Kaikkien ajan säästämiseksi poistan kurssilta ne, jotka eivät palauta tehtäviä ajallaan.&lt;/p>
&lt;p>Tekoälyn käyttö: Tällä kurssilla on samat AI säännöt kuin YAMK:n kurssillani: &amp;quot;AI and large language models (LLM): You can ask AI or LLM a question and use the answer as facts for your own answer, written in your own words. AI must be marked as a reference, with details such as prompt (and for advanced users system prompts, temperature, jailbreaks...). LLMs tend to hallucinate, so you should check answers from more reliable sources. It's not allowed to generate text with AI or similar technologies. For example, it's not allowed to generate essay answers or summaries with AI, LLM or similar technologies.&amp;quot;&lt;/p>
&lt;h3 id="h1-hei-ansiblen-maailma">h1 Hei Ansiblen maailma&lt;/h3>
&lt;p>&lt;em>Hei maailma! Yleensä kaikki ohjelmat alkavat siitä. Hei maailma testaa, että ympäristö toimii.&lt;/em>&lt;/p>
&lt;p>&lt;em>Tässä kotitehtävässä harjoitellaan itse tunnilla kurkattuja ja osin kokeiltuja juttuja, jotta tehtävistä ei tule liian vaikeita. Jos olet aiemmin tehnyt nämä, voit simuloida puhtaan tilanteen - näin tehdään myöhemmin myös IaC-koodeja testatessa. Voit esimerkiksi pysäyttää ja poistaa ssh-demonin, poistaa authorized_keys... Katso vinkit alla.&lt;/em>&lt;/p>
&lt;ul>
&lt;li>x) Lue ja tiivistä. (Tässä x-alakohdassa ei tarvitse tehdä testejä tietokoneella, vain lukeminen tai kuunteleminen ja tiivistelmä riittää. Tiivistämiseen riittää muutama ranskalainen viiva. Ei siis vaadita pitkää eikä essee-muotoista tiivistelmää. Lisää kuhunkin jokin oma kysymys tai huomio.)
&lt;ul>
&lt;li>Karvinen 2026: &lt;a href="https://terokarvinen.com/ssh-public-key-login-without-password/">SSH public key - Login without password&lt;/a>&lt;/li>
&lt;li>Karvinen 2026: &lt;a href="https://terokarvinen.com/hello-ansible/">Hello Ansible&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>a) Sshecrets. Asenna SSH-demoni ja testaa se kirjautumalla SSH:lla.&lt;/li>
&lt;li>b) Pubkey. Automatisoi ssh-kirjautuminen julkisella avaimella.&lt;/li>
&lt;li>c) Hei Ansible. Tee hei maailma ansiblella ja kokeile sitä SSH:n yli.&lt;/li>
&lt;li>d) Vapaaehtoinen bonus, vaikea: kokeile Ansiblella jokin näista asetuksista: paketin asennus, asetustiedosto /etc/ alle, käynnistä jokin demoni, tee uusi käyttäjä. Tarvitset todennäköisesti sudoa, become: true.&lt;/li>
&lt;/ul>
&lt;p>Kuten aina, palauta linkki Laksuun, ristiinarvioi vähintään 2.&lt;/p>
&lt;p>&lt;strong>Vinkit&lt;/strong>&lt;/p>
&lt;p>(Komennot alla ulkomuistista)&lt;/p>
&lt;p>SSH-demonin poistaminen asennuskokeilua varten. Tämän voi tehdä localhost:lla. Älä tee etänä palvelimelle, tai yhteytesi katkeaa.&lt;/p>
&lt;pre>&lt;code>$ sudo systemctl stop ssh
$ sudo apt-get purge openssh-server
&lt;/code>&lt;/pre>
&lt;p>Julkisen avaimen poistaminen&lt;/p>
&lt;pre>&lt;code>remote$ mv -v $HOME/.ssh/authorized_keys $HOME/DISABLED_authorized_keys
&lt;/code>&lt;/pre>
&lt;p>Ansiblen asetukset voit vaan tehdä uuteen kansioon ja ajaa sieltä.&lt;/p>
&lt;p>Testaamatta == tekemättä. Kun asennat tai säädät jotain, osoita testillä, että se toimii.&lt;/p>
&lt;p>Eikö toimi? Raportoi erityisen tarkasti, jotta voimme pähkiä sitä tunnilla yhdessä. Myös tarkat virheilmoitukset talteen.&lt;/p>
&lt;h3 id="h2-voileipa">h2 Voileipä&lt;/h3>
&lt;img src="https://terokarvinen.com/palvelinten-hallinta/sudo-logo_hu90c7c77f1bb985b8b0dfccb8c62285a4_186853_200x200_fit_box_3.png" width="179" height="200" alt=" " class="imgOne right">
&lt;ul>
&lt;li>x) Lue ja tiivistä. (Tässä x-alakohdassa ei tarvitse tehdä testejä tietokoneella, vain lukeminen tai kuunteleminen ja tiivistelmä riittää. Tiivistämiseen riittää muutama ranskalainen viiva. Ei siis vaadita pitkää eikä essee-muotoista tiivistelmää. Lisää kuhunkin jokin oma kysymys tai huomio.)
&lt;ul>
&lt;li>Karvinen 2026: &lt;a href="https://terokarvinen.com/passwordless-sudo/">Sudo without password&lt;/a>&lt;/li>
&lt;li>Munroe 2006: &lt;a href="https://xkcd.com/149/">xkcd 149: Sandwitch&lt;/a>&lt;/li>
&lt;li>Karvinen 2026: &lt;a href="https://terokarvinen.com/passwordless-sudo-with-ansible/">Passwordless Sudo with Ansible &lt;/a>&lt;/li>
&lt;li>Ansiblen sisäänrakennettu dokumentaatio ansible-doc -kommennolla.
&lt;ul>
&lt;li>Kustakin vain
&lt;ul>
&lt;li>Johdantokappale (Usein MODULE alla, päättyy OPTIONS alkuun)&lt;/li>
&lt;li>Nimetyt optiot selityksineen&lt;/li>
&lt;li>Esimerkeistä (EXAMPLES) jokin helppo ja keskeinen esimerkki&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>'ansible-doc copy': content, dest, src; owner, group, mode;&lt;/li>
&lt;li>'ansible-doc apt': name, state, update_cache.&lt;/li>
&lt;li>'ansible-doc file': path, recurse, src, state. owner, group, mode;&lt;/li>
&lt;li>'ansible-doc user': name; create_home, comment, groups, shell, state, system.&lt;/li>
&lt;li>'ansible-doc authorized_key': user, key.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>a) Sudoless. Tee ansiblea varten tunnus, jolla voi käyttää sudoa ilman salasanaa. Sekä ssh-kirjautuminen että sudon käyttö tulee olla ansbilea varten automatisoitu.&lt;/li>
&lt;li>b) Antero. Tee salasanaton, automaattisesti ssh:lla kirjautuva tunnus Ansiblella.&lt;/li>
&lt;li>c) Package. Asenna kaksi pakettia ansiblella.&lt;/li>
&lt;li>d) File. Kirjoita orjalle useamman rivin mittainen tiedosto Ansiblella. Määrittele sen omistaja, omistava ryhmä ja oikeudet. Käytä oikeuksille oktaalinumeroa, esim. &amp;quot;0600&amp;quot;. Kerro, mitä oikeudet ovat symbolisessa muodossa, esim. &amp;quot;-rwxr--r--&amp;quot;. Selitä, mitä kukin käyttäjä saa tehdä tuolle tiedostolle.&lt;/li>
&lt;li>e) Jotain muuta. Näytä esimerkki ansiblen käskystä, jota ei ole vielä käsitelty kurssilla tai kotitehtävissä. Voit ottaa jonkun muun modulin kuin apt, file, copy, user tai authorized_key. Tai voit käyttää ominaisuutta, jota ei vielä ole demonstroitu. Jos tiivistystehtävässä x on mainittu ominaisuuksia, joita ei tunneilla tai läksyissä kokeiltu, nekin kelpaavat.&lt;/li>
&lt;/ul>
&lt;p>Vinkit&lt;/p>
&lt;ul>
&lt;li>Rakenna tila paloittain. Tottakai se toimii kopioimalla malli ja muuttamalla muutama muuttuja. Mutta hetken päästä näitä pitäisi rakentaa myös ilman mallia.&lt;/li>
&lt;li>'ansible-doc user', 'ansible-doc --list'&lt;/li>
&lt;li>Etkö jaksa odottaa?
&lt;ul>
&lt;li>'ansible-doc --list &amp;gt; doc-list.txt'&lt;/li>
&lt;li>helppolukuisempana 'ansible-doc --list|grep -oP '^\S+'&amp;gt;doc-list.txt'&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Paketin asennus: apt&lt;/li>
&lt;li>File:
&lt;ul>
&lt;li>copy: src: foo.txt -&amp;gt; roles/superd/files/foo.txt&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="h3-demoni">h3 Demoni&lt;/h3>
&lt;img src="https://terokarvinen.com/palvelinten-hallinta/apache-httpd-logo_hu0274bb063ced1072a70ec8e201c9b197_74947_300x300_fit_box_3.png" width="154" height="300" alt=" " class="imgOne padSides right">
&lt;p>&lt;em>Package, file, service&lt;/em>&lt;/p>
&lt;ul>
&lt;li>x) Lue ja tiivistä. (Tässä x-alakohdassa ei tarvitse tehdä testejä tietokoneella, vain lukeminen tai kuunteleminen ja tiivistelmä riittää. Tiivistämiseen riittää muutama ranskalainen viiva. Ei siis vaadita pitkää eikä essee-muotoista tiivistelmää. Lisää kuhunkin jokin oma kysymys tai huomio.)
&lt;ul>
&lt;li>Karvinen 2026: &lt;a href="https://terokarvinen.com/apache-ansible/">Apache installed with Ansible - quick notes&lt;/a>&lt;/li>
&lt;li>Ansible Community Documentation: &lt;a href="https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_handlers.html">Handlers: running operations on change&lt;/a>
&lt;ul>
&lt;li>Handlers: running operations on change (johdantokappale pääotsikon alta)&lt;/li>
&lt;li>Notifying handlers&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>'ansible-doc service':
&lt;ul>
&lt;li>johdantokappale (MODULE alta)&lt;/li>
&lt;li>enabled&lt;/li>
&lt;li>name&lt;/li>
&lt;li>state&lt;/li>
&lt;li>EXAMPLES&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>a) Apassi. Asenna Apache 2 käsin. Weppisivun tulee näkyä palvelimen etusivulla. Sivun tulee olla tavallisen käyttäjän muokattavissa, ilman root- tai sudo-oikeuksia.&lt;/li>
&lt;li>b) Moottorix. Asenna Nginx käsin. Weppisivun tulee näkyä palvelimen etusivulla. Sivun tulee olla tavallisen käyttäjän muokattavissa, ilman root- tai sudo-oikeuksia. (Muista sammuttaa Apache ensin.)&lt;/li>
&lt;li>c) Automoottorix. Automatisoi Nginx asennus Ansiblella. Ylläpitäjän osuus Ansiblella riittää, itse HTML-weppisivut voi tehdä käsin.&lt;/li>
&lt;li>d) Vapaaehtoinen bonus: Osiris-T. Osiris-T asentaa Wazuhin ja tarvittavat virtuaalikoneet. Voit lähettää vihamielistä verkkoliikennettä (tcpreplay), siepata sen (suricata) ja saat tulokset suoraan dashboardille (wazuh). Enemmän alpha kuin se kreikkalainen kirjain. Mutta Oskari, Nico ja Arttu ilahtuvat, jos kokeilet. Häkämies, Saario, Mukkula 2026: &lt;a href="https://github.com/oskarihakamies/IDS-project">Osiris-T&lt;/a>. Häkämies etal 2026: &lt;a href="https://github.com/oskarihakamies/IDS-project/blob/main/How-To-Install.md">How to Install&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>&lt;em>Vinkit&lt;/em>&lt;/p>
&lt;ul>
&lt;li>Ensin käsin, sitten automaattisesti&lt;/li>
&lt;li>Pienen testattava kokonaisuus kerrallaan&lt;/li>
&lt;li>Lue lokeja. Weppipalvelimen virheilmoitukset ovat lokeissa, käyttäjälle näkyvä weppisivu ei kerro juuri mitään.&lt;/li>
&lt;li>Kaksi demonia ei voi kuunnella samaa porttia. Sulje siis nginx ennen apachen asennusta ja päinvastoin.&lt;/li>
&lt;li>'ansible-doc apt': name, state, update_cache. EXAMPLES.&lt;/li>
&lt;li>'ansible-doc copy': dest, src; owner, group, mode. EXAMPLES.&lt;/li>
&lt;li>'ansible-doc file': src, dest, state. owner, group. EXAMPLES.&lt;/li>
&lt;li>nginx asennus on samantapainen kuin Apachen
&lt;ul>
&lt;li>sites-available/default - tiedoston lopussa on esimerkki yksinkertaisesta konfiguraatiosta&lt;/li>
&lt;li>'sudo nginx -t' on samantapainen kuin 'sudo apache2ctl configtest'&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Kotisivut käyttäjänä
&lt;ul>
&lt;li>Weppipalvelin pyörinee käyttäjänä www-data, ryhmä www-data. Jos tiedoston omistaa tero:tero, niin www-data on others eli viimeiset kolme kirjainta.&lt;/li>
&lt;li>Jotta se näkee sivut, kansioihin pitää olla x-oikeus ja tiedostoihin r.&lt;/li>
&lt;li>/home/tero/publicsite/index.html
&lt;ul>
&lt;li>chmod ugo+x /home/tero/&lt;/li>
&lt;li>chmod ugo+x /home/tero/publicsite/&lt;/li>
&lt;li>chmod ugo+r /home/tero/publicsite/index.html&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Tarkista oikeudet 'ls -t' ja 'stat'&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="h4-pizza-fantasia">h4 Pizza Fantasia&lt;/h3>
&lt;ul>
&lt;li>x) Lue ja tiivistä. (Tässä x-alakohdassa ei tarvitse tehdä testejä tietokoneella, vain lukeminen tai kuunteleminen ja tiivistelmä riittää. Tiivistämiseen riittää muutama ranskalainen viiva. Ei siis vaadita pitkää eikä essee-muotoista tiivistelmää. Lisää kuhunkin jokin oma kysymys tai huomio.)
&lt;ul>
&lt;li>Karvinen 2023: &lt;a href="https://westminsterresearch.westminster.ac.uk/item/w7vvz/configuration-management-of-distributed-systems-over-unreliable-and-hostile-networks">Configuration Management of Distributed Systems over Unreliable and Hostile Networks&lt;/a> (&lt;a href="https://westminsterresearch.westminster.ac.uk/download/4cc417566aa9af60fe3826d690719e390abdb7a3c8672f3d51b1eb4ca75e7624/1427236/karvinen-2023-configuration-management-of-distributed-systems.pdf">pdf&lt;/a>, ̣mirrors: &lt;a href="Karvinen-2023-Configuration-Management-of-Distributed-Systems-over-Unreliable-and-Hostile-Networks.pdf">local&lt;/a>, &lt;a href="https://scholar.archive.org/work/3vyjt2wj2ndp5egy72xkudeeey/access/wayback/https%3A%2F%2Fwestminsterresearch.westminster.ac.uk%2Fdownload%2F4cc417566aa9af60fe3826d690719e390abdb7a3c8672f3d51b1eb4ca75e7624%2F1427236%2Fkarvinen-2023-configuration-management-of-distributed-systems.pdf">archive.org&lt;/a>), vain nämä kohdat:
&lt;ul>
&lt;li>4.12.1 Size and Complexity of Some DSLs (112. Ominaisuuksien määrä.)&lt;/li>
&lt;li>4.12.2 Use of DSL Functions in Case Configuration (112-115. Mitä oikeasti käytetään.)&lt;/li>
&lt;li>4.12.3.1 Dependencies Between Main Functions (115-117. Tärkeimmät rakennuspalikat.)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>a) Räpylä. Asenna itse valitsemasi demoni käsin. Jokin muu kuin tunnilla tai kotitehtävissä aiemmin asennettu, eli ei apache, ngninx eikä openssh-server. Kuten aina, testaa lopputulos.&lt;/li>
&lt;li>b) Automaatti. Automatisoi valitsemasi demonin asennus Ansiblella.&lt;/li>
&lt;li>c) Asetus. Muuta asetustiedostoa herralla (master, &amp;quot;control node&amp;quot;) ja aja ansible uudestaan. Osoita, että asetukset tulivat käyttöön.&lt;/li>
&lt;li>d) Paikka remonttiin. Riko jotain asetuksia. Voit esimerkiksi poistaa demonin 'sudo apt-get purge foobar' (purge poistaa myös asetustiedostoja), poistaa asennuksen yhteydessä tulevan kansion (sudo rm -r /etc/foobar/ # vaarallista) tms. Ja sitten ajaa ansible-roolisi uudestaan ja todeta, että se korjaa tilanteen.&lt;/li>
&lt;li>e) Idempotentti. Osoita, että tilasi on idempotentti.&lt;/li>
&lt;/ul>
&lt;p>Vinkit&lt;/p>
&lt;ul>
&lt;li>CM: configuration management&lt;/li>
&lt;li>DSL: domain specific language. Yhteen käyttötarkoitukseen tehty kieli. Esim Ansiblen oma kieli, jolla määrittelemme konfiguraatiota.&lt;/li>
&lt;li>Kannattaa valita demoni, joka löytyy suoraan Debian 13 varastoista apt-get:lla.&lt;/li>
&lt;li>Esimerkkejä: postgresql, caddy, mariadb, haproxy, varnish&lt;/li>
&lt;li>Nämä voivat olla mutkikkaampia: samba, nfs, jokin ftp-palvelin, jokin vaihtoehtoinen ssh, jokin dhcpd, jokin tftpd&lt;/li>
&lt;/ul>
&lt;h3 id="h5-gitar-hero">h5 Gitar Hero&lt;/h3>
&lt;p>&lt;em>Oman miniprojektin aihetta kannattaa jo haudutella. Ensimmäiset julkaissevat jo parin kanssa tehdyn ensimmäisen version.&lt;/em>&lt;/p>
&lt;ul>
&lt;li>x) Lue ja tiivistä. (Tässä x-alakohdassa ei tarvitse tehdä testejä tietokoneella, vain lukeminen tai kuunteleminen ja tiivistelmä riittää. Tiivistämiseen riittää muutama ranskalainen viiva. Kannattaa lisätä mukaan myös jokin oma havainto, idea tai kysymys.)
&lt;ul>
&lt;li>Chacon and Straub 2014: &lt;a href="https://git-scm.com/book/en/v2">Pro Git, 2ed&lt;/a>: &lt;a href="https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F">1.3 Getting Started - What is Git?&lt;/a>&lt;/li>
&lt;li>Gitin käyttö on lähinnä 'git add --all &amp;amp;&amp;amp; git commit; git pull &amp;amp;&amp;amp; git push'. Selitä tuon komennon jokainen osa. Käytä apuna itse valitsemiasi lähteitä ja viittaa niihin.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>a) Online. Tee uusi varasto GitHubiin (tai Gitlabiin tai mihin vain vastaavaan palveluun). Varaston nimessä ja lyhyessä kuvauksessa tulee olla sana &amp;quot;sunshine&amp;quot;. Aiemmin tehty varasto ei kelpaa. (Muista tehdä varastoon tiedostoja luomisvaiheessa, esim README.md ja GNU General Public License 3) Edistyneemmille voi olla hauskaa etsiä ja kokeilla jokin muu palvelu kuin Github.&lt;/li>
&lt;li>b) Dolly. Kloonaa edellisessä kohdassa tehty uusi varasto itsellesi, tee muutoksia omalla koneella, puske ne palvelimelle, ja näytä, että ne ilmestyvät weppiliittymään.&lt;/li>
&lt;li>c) Doh! Tee tyhmä muutos gittiin, älä tee commit:tia. Tuhoa huonot muutokset ‘git reset --hard’. Huomaa, että tässä toiminnossa ei ole peruutusnappia.&lt;/li>
&lt;li>d) Tukki. Tarkastele ja selitä varastosi lokia. Näytä myös, mitä muutoksia tiedostoihin on tehty. Tarkista, että nimesi ja sähköpostiosoitteesi näkyy haluamallasi tavalla ja korjaa tarvittaessa.&lt;/li>
&lt;li>e) Gitanbile. Laita Ansible-kansio versionhallintaan. Tee jokin muutos, aja ansiblella, tallenna versio (commit).&lt;/li>
&lt;li>f) Hae pari projektiin Moodlen keskustelusta. (Tästä alakohdasta f ei tarvitse tehdä vaiheittaista teknistä raporttia, riittää kun toteat, että pari on hankittu.)&lt;/li>
&lt;li>g) Vapaaehtoinen: Se toinen järjestelmä: kokeile Gittiä eri käyttöjärjestelmällä kuin sillä, millä teit muut harjoitukset. Selitä niin, että kyseistä järjestelmää osaamatonkin onnistuu. Mahdollisuuksia on runsaasti: Debian, Fedora, Windows, OSX...&lt;/li>
&lt;li>h) Vapaaehtoinen: yhteistyötä: anna kaverillesi (tai alter egollesi) oikeus kirjoittaa varastoosi (commit access). Tehkää molemmat muutoksia varastoon gitillä.&lt;/li>
&lt;/ul>
&lt;p>Vinkkejä&lt;/p>
&lt;ul>
&lt;li>Kannattaa käyttää SSH-osoitetta varastoa kloonatessa, kirjautuminen julkisella ssh-avaimella&lt;/li>
&lt;li>ssh-keygen (enter, enter, enter), cat $HOME/.ssh/id*.pub, Github: Settings: SSH keys... Vain julkisen avaimen - sen mikä päättyy .pub - saa julkaista ja tallettaa Githubiin.&lt;/li>
&lt;li>Github-varaston sivulta Code: SSH. git clone &lt;a href="https://github.com/hattupuu/earplotter.git">https://github.com/hattupuu/earplotter.git&lt;/a> ; cd earplotter&lt;/li>
&lt;li>git pull&lt;/li>
&lt;li>git add --all &amp;amp;&amp;amp; git commit; git pull &amp;amp;&amp;amp; git push&lt;/li>
&lt;li>git log --patch&lt;/li>
&lt;li>git config --global user.email &amp;quot;tonystudent@example.com&amp;quot;&lt;/li>
&lt;li>git config --global user.name &amp;quot;Tony Student&amp;quot;&lt;/li>
&lt;li>Commit message
&lt;ul>
&lt;li>Miksi? Miksi tämä commit on tehty? (Ne tiedostot ja muutokset näkyvät joka tapauksessa 'git log --patch', joten commit messagen kannattaa kertoa se syy: miksi, why?&lt;/li>
&lt;li>Yksi englanninkielinen virke määräysmuodossa ja nykyajassa: &amp;quot;Add reverse thurst estimation to main view&amp;quot;&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>GitHub-varastoon kannattaa tehdä tiedostoja luomisvaiheessa, suosittelen tekemään README.md ja vapaista lisensseistä itse tykkään GPLv3 eli GNU General Public License, version 3. Oman työsi lisenssin saat itse valita.&lt;/li>
&lt;li>Karvinen 2021: &lt;a href="https://terokarvinen.com/2021/install-debian-on-virtualbox/">Install Debian on VirtualBox&lt;/a>&lt;/li>
&lt;li>Microsoft 2023: &lt;a href="https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/">Get a Windows 11 development environment&lt;/a>: Download a virtual machine: &lt;a href="https://aka.ms/windev_VM_virtualbox">VirtualBox&lt;/a>&lt;/li>
&lt;li>Jos menet olemassaolevaan projektiin (työpaikalla, open source)... opiskele projektin käytännöt ja käytä niitä&lt;/li>
&lt;li>&lt;a href="https://github.com/terokarvinen/suolax">https://github.com/terokarvinen/suolax&lt;/a> Salt-tiloja, jotka voi ajaa suoraan salt-varastosta&lt;/li>
&lt;li>Git asennuspaketit Windowsille ja Macille &lt;a href="https://git-scm.com/downloads">https://git-scm.com/downloads&lt;/a>&lt;/li>
&lt;li>Macilla 'brew' saattaa olla myös kätevä työkalu Gitin asentamiseen&lt;/li>
&lt;li>Linuxille Git asentuu helpoimmin paketinhallinnasta: 'sudo apt-get update; sudo apt-get -y install git'&lt;/li>
&lt;/ul>
&lt;h3 id="h6-miniprojekti">h6 Miniprojekti&lt;/h3>
&lt;p>&lt;em>Loppuhuipennus: projektit esitellään kurssin lopussa. Saat soveltaa uusia taitojasi!&lt;/em>&lt;/p>
&lt;p>&lt;em>Pääset harjoittelemaan teknistä esittämistä huolettomassa ympäristössä omien luokkakavereiden kanssa. Saat myös esittää kysymyksiä, ideoita ja kommentteja kavereiden töihin. Ja samalla näet, mitä muut ovat rakentaneet.&lt;/em>&lt;/p>
&lt;p>&lt;em>Arvon esitysjärjestyksen ja ilmoitan sen esitysten alussa. Kaikkien projektien tulee olla esitysvalmiina 2026-05-05 w19 tiistaina (ja torstain ryhmällä päivää myöhemmin ke).&lt;/em>&lt;/p>
&lt;ul>
&lt;li>a) Oma miniprojekti.
&lt;ul>
&lt;li>Modernia keskitettyä hallintaa: idempotentti, infra koodina, yksi totuus&lt;/li>
&lt;li>Idempotentti
&lt;ul>
&lt;li>Pelkkä skritpi (shell script) ei kelpaa, ei myöskään skripti jaettuna kymmeneen peräkkäiseen cmd.run-tilaan&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Kannattaa testata lopputulos tyhjällä koneella
&lt;ul>
&lt;li>Vapaaehtoista: Jos videoit ruudulta samalla, sinulla on räjähtävien demojen tai tulevien kurssin ulkopuolisten esitysten varalta aina toimiva esitys. Jos laitat videon Youtubeen tai kotisivullesi, sinulla on valmis esitys käytettäväksi myös kurssin jälkeen. Vaikka live-demo on parempi kuin video, parasta on live-demo ja varalla video.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Ensin valmista, sitten hienoa.
&lt;ul>
&lt;li>Tee ensin pieni, toimiva kokonaisuus, jonka voisit hätätilassa esittää.&lt;/li>
&lt;li>Tallenna pieni kokonaisuutesi toimivana esim. kopioimalla kansio&lt;/li>
&lt;li>Tee sitten tämän toimivan päälle hienot jutut, seuraavat vaiheet ja kurottelumaalit.&lt;/li>
&lt;li>Kannattaa aloittaa ajoissa ja tehdä joka päivä&lt;/li>
&lt;li>Kaikki tai &lt;del>ei mitään&lt;/del> jotain&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>b) Etusivu. Laita projektisi etusivulle tärkeimmät tiedot
&lt;ul>
&lt;li>Etusivu voi olla esimerkiksi Github-varasto ja tiedot README.md:ssä&lt;/li>
&lt;li>Yritä laittaa keskeisimmät kohdat &amp;quot;taitoksen yläpuolelle&amp;quot;, eli näkymään jo ennen skrollausta&lt;/li>
&lt;li>Tavoitteena on, että lukija ymmärtää välittömästi ja yhdellä silmäyksellä projektin tarkoituksen (ruutukaappaus + kuvaus)&lt;/li>
&lt;li>Tiedot
&lt;ul>
&lt;li>Projektin tarkoitus, mieluiten yhdellä lyhyellä virkkeellä. Eli mitä tämä tekee / mihin tätä käytetään / mitä hyötyä tästä on / business purpose.&lt;/li>
&lt;li>Lisenssi. Saat valita, suosittelen GNU General Public License, version 3.&lt;/li>
&lt;li>Ruutukaappaus lopputuloksesta&lt;/li>
&lt;li>Oma nimesi ja mahdollinen kotisivun osoite (Saa toki käyttää myös nimimerkkiä)&lt;/li>
&lt;li>Latauslinkki (Githubissa asennusohje voi toki olla myös 'git clone ...')&lt;/li>
&lt;li>Käyttöönotto. Miten kuka tahansa sivulle tulija voi ilman muita ohjeita ajaa projektisi.&lt;/li>
&lt;li>Voit kirjoittaa suomeksi tai englanniksi; usein ohjelmat dokumentoidaan englanniksi&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>c) Showtime! Valmistaudu pitämään max 7 min esitys projektistasi.
&lt;ul>
&lt;li>Yleisö: kurssin muut opiskelijat
&lt;ul>
&lt;li>Kuulija yleensä miettii aluksi, mitä hyötyä tähän esitykseen keskittymisestä on minulle.&lt;/li>
&lt;li>Ymmärtääkö kuulija, mitä lopputulos tekee?&lt;/li>
&lt;li>Kun hyöty on selvillä, kuulija halunnee oppia tekemään saman&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Tarkoitus ja lopputulos ensin
&lt;ul>
&lt;li>Hovimestari on syyllinen.&lt;/li>
&lt;li>Yleisö kuuntelee, kun tietää, mitä hyötyä tästä on&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Esittele itsesi
&lt;ul>
&lt;li>Monissa esityksessi oman nimen ja organisaation esittely on tärkein oma hyöty&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Demo ois kiva
&lt;ul>
&lt;li>Kannattaa laittaa demo pyörimään heti, kun projektin tarkoitus ja oma nimi on selvillä&lt;/li>
&lt;li>Salt-ajot vievät usein aikaa, jota ei kannata käyttää odotteluun vaan puhumiseen&lt;/li>
&lt;li>Kerro kaikki kerrottava sillä aikaa kun salt raksuttaa&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Kokeile välineet
&lt;ul>
&lt;li>Jitsi-kanavalle pääsee milloin vain&lt;/li>
&lt;li>Ruudunjako, kamera, mikki&lt;/li>
&lt;li>Jos haluat kaksi asiakasta, niin 2 tietokonetta tai tietokone ja kännykkä&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Tästä c-alakohdasta ei tarvitse tehdä raporttia.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>Vinkit&lt;/p>
&lt;ul>
&lt;li>Katso vanhoja projekteja
&lt;ul>
&lt;li>Kurssisivujen kommenteista&lt;/li>
&lt;li>Hakukoneista&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>Tervetuloa esiintymään!&lt;/p>
&lt;p>&lt;em>Huomaa myös vapaaehtoinen h8.&lt;/em>&lt;/p>
&lt;h3 id="h8-bonus">h8 Bonus&lt;/h3>
&lt;p>Vapaaehtoinen bonus: luettele ja linkitä tähän tekemäsi&lt;/p>
&lt;ul>
&lt;li>a) Vapaaehtoiset tehtävät&lt;/li>
&lt;li>b) Ristiinarvioinnin jälkeen olennaisesti parannetut tehtävät&lt;/li>
&lt;/ul>
&lt;p>Tehtävän h8 määräaika on kurssin 24 h ennen viimeisen oppitunnin alkuao. Tämä bonustehtävä on kokonaan vapaaehtoinen.&lt;/p>
&lt;h2 id="adminstrivia">Adminstrivia&lt;/h2>
&lt;p>Sudo logo my Mark Stillman 2019, received under CC-BY-4.0.&lt;/p>
&lt;p>Apache httpd logo is a trademark of The Apache Software Foundation.&lt;/p></description></item></channel></rss>