<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tesleem Amuda</title>
    <description>The latest articles on DEV Community by Tesleem Amuda (@tesddev).</description>
    <link>https://dev.to/tesddev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1150610%2Fdb0af98e-37cd-44de-a7ae-def1a0793ee5.jpeg</url>
      <title>DEV Community: Tesleem Amuda</title>
      <link>https://dev.to/tesddev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tesddev"/>
    <language>en</language>
    <item>
      <title>Understanding Subjects in RxSwift: The Day Everything Clicked</title>
      <dc:creator>Tesleem Amuda</dc:creator>
      <pubDate>Thu, 06 Aug 2026 13:32:00 +0000</pubDate>
      <link>https://dev.to/tesddev/understanding-subjects-in-rxswift-the-day-everything-clicked-5b9m</link>
      <guid>https://dev.to/tesddev/understanding-subjects-in-rxswift-the-day-everything-clicked-5b9m</guid>
      <description>&lt;p&gt;I remember the exact moment Subjects stopped feeling like magic and started feeling like tools I could actually control.&lt;/p&gt;

&lt;p&gt;I had been using RxSwift for a while. Observables made sense. Operators were powerful. Binding worked. But every time I needed to push values into a stream myself — from a network callback, a button action, or some internal state change — I just reached for PublishSubject and moved on. It worked… until it didn’t.&lt;/p&gt;

&lt;p&gt;Then one day I sat down and actually looked at the different types of Subjects. That was the turning point. Suddenly a lot of the weird behaviour I’d been fighting made sense, and I started writing cleaner reactive code.&lt;/p&gt;

&lt;p&gt;This article is the deep-dive I wish I had back then.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Refresher: What Even Is a Subject?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Subject is both an Observable and an Observer.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;p&gt;You can subscribe to it (like a normal Observable)&lt;/p&gt;

&lt;p&gt;You can also call .onNext(), .onError(), and .onCompleted() on it yourself&lt;/p&gt;

&lt;p&gt;This dual nature is extremely useful, but it’s also where a lot of the confusion (and bugs) come from.&lt;/p&gt;

&lt;p&gt;There are four main types in RxSwift:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PublishSubject&lt;/li&gt;
&lt;li&gt; BehaviorSubject&lt;/li&gt;
&lt;li&gt; ReplaySubject&lt;/li&gt;
&lt;li&gt;AsyncSubject&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go through each one properly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. PublishSubject – The Event Bus&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;publishSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PublishSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;publishSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Nobody is listening yet → gone forever&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;publishSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;publishSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// prints "B"&lt;/span&gt;

&lt;span class="n"&gt;publishSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// prints "C"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key behaviour:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts empty&lt;/li&gt;
&lt;li&gt; Only emits values to subscribers after they subscribe&lt;/li&gt;
&lt;li&gt; Does not keep any history&lt;/li&gt;
&lt;li&gt; Perfect for discrete events (button taps, notifications, “something just happened”)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When I reach for it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UI events that shouldn’t replay&lt;/li&gt;
&lt;li&gt; One-shot signals between layers&lt;/li&gt;
&lt;li&gt; Any time I truly don’t care about past values&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common pitfall:&lt;/strong&gt;&lt;br&gt;
People sometimes use PublishSubject for state. Then a late subscriber gets nothing and the UI stays blank. That’s usually a sign you needed a BehaviorSubject instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. BehaviorSubject – State That Always Has a Current Value&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;behaviorSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Initial"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;behaviorSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Subscriber 1:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Immediately prints: Subscriber 1: Initial&lt;/span&gt;

&lt;span class="n"&gt;behaviorSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Updated"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;behaviorSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Subscriber 2:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Immediately prints: Subscriber 2: Updated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key behaviour:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires an initial value&lt;/li&gt;
&lt;li&gt; Always holds the latest value&lt;/li&gt;
&lt;li&gt; New subscribers get that latest value immediately&lt;/li&gt;
&lt;li&gt; After that, they get new values as they arrive&lt;/li&gt;
&lt;li&gt;This is the Subject I use the most in real apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Typical use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current user profile&lt;/li&gt;
&lt;li&gt;Selected tab or filter&lt;/li&gt;
&lt;li&gt;Loading / error / success state of a screen&lt;/li&gt;
&lt;li&gt;Any piece of state that the UI needs right now&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important notes:&lt;/strong&gt;&lt;br&gt;
Calling .onCompleted() or .onError() terminates it permanently. After that, new subscribers only get the terminal event.&lt;/p&gt;

&lt;p&gt;If you need something that never completes and is easier to work with from the UI side, many people prefer BehaviorRelay (from RxRelay). But under the hood it’s still built on BehaviorSubject.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common pitfall:&lt;/strong&gt;&lt;br&gt;
Creating a BehaviorSubject with a dummy initial value just to satisfy the compiler, then immediately overwriting it. That dummy value often leaks into the UI for a brief moment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. ReplaySubject – “Here’s What You Missed”&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;replaySubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ReplaySubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;bufferSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;replaySubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;replaySubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;replaySubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;replaySubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// prints:&lt;/span&gt;

&lt;span class="c1"&gt;// B&lt;/span&gt;

&lt;span class="c1"&gt;// C&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key behaviour:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keeps a buffer of the last N values&lt;/li&gt;
&lt;li&gt;New subscribers receive those buffered values first, then live values&lt;/li&gt;
&lt;li&gt;You can also create an unbounded version with .createUnbounded(), but be careful with memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When it’s useful:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need a short history (last few locations, last few search results, etc.)&lt;/li&gt;
&lt;li&gt;Multiple subscribers joining at different times should all see recent activity&lt;/li&gt;
&lt;li&gt;Debugging or logging streams where context matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common pitfall:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Using a large or unbounded buffer without thinking. It’s easy to accidentally keep a lot of objects alive and create memory pressure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. AsyncSubject – The Final Result Only&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;asyncSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AsyncSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;asyncSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;asyncSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncSubject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Only now does it print: C&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key behaviour:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ignores everything until the sequence completes&lt;/li&gt;
&lt;li&gt;Then emits only the last value (if any) and completes&lt;/li&gt;
&lt;li&gt;If it errors, subscribers get the error instead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one is the least used in day-to-day iOS work, but it’s perfect for “I only care about the final answer” scenarios — like a long-running calculation or a multi-step process that should only notify when fully done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common pitfall:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forgetting to call .onCompleted(). Without it, nothing ever emits.&lt;/li&gt;
&lt;li&gt;Side-by-Side Comparison&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw0zxrc2je8twvyjvodmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw0zxrc2je8twvyjvodmx.png" alt=" " width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Pitfalls I’ve Hit (and How to Avoid Them)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Subjects and Memory Leaks&lt;/strong&gt;&lt;br&gt;
Subjects themselves don’t cause retain cycles, but the way we hold them does.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;ViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;PublishSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;



    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="n"&gt;events&lt;/span&gt;

            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;   &lt;span class="c1"&gt;// ← easy to forget&lt;/span&gt;

                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disposed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;disposeBag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always capture self weakly inside the subscription if the subject lives on self.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Completing a Subject Too Early&lt;/strong&gt;&lt;br&gt;
Once a Subject receives .onCompleted() or .onError(), it’s done. Forever. New subscribers only get the terminal event.&lt;/p&gt;

&lt;p&gt;If you need a long-lived stream of events, never complete the Subject unless you’re intentionally shutting it down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Using the Wrong Subject for State&lt;/strong&gt;&lt;br&gt;
This is the most common intermediate mistake.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need the current value right away when someone subscribes? → BehaviorSubject&lt;/li&gt;
&lt;li&gt;Pure event that shouldn’t replay? → PublishSubject&lt;/li&gt;
&lt;li&gt;Need a few recent values? → ReplaySubject&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing wrong usually shows up as “the second screen that opens doesn’t have the data” or “old events keep firing when they shouldn’t.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Threading Surprises&lt;/strong&gt;&lt;br&gt;
Subjects are not magically thread-safe in the way some people expect. If you call .onNext from multiple threads without care, you can get race conditions.&lt;/p&gt;

&lt;p&gt;In practice I usually make sure all emissions happen on a known scheduler (often MainScheduler for UI-related subjects).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Over-using Subjects&lt;/strong&gt;&lt;br&gt;
Subjects are convenient, but they make your code more imperative. Whenever possible, prefer pure Observables that are created from existing sources (network, notifications, UI controls, etc.). Reach for a Subject only when you genuinely need to push values from outside the reactive chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Pattern I Use Often
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;SomeViewModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Private so only the ViewModel can emit&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;ViewState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



    &lt;span class="c1"&gt;// Public read-only version&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;ViewState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="n"&gt;_state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// ... network call&lt;/span&gt;

        &lt;span class="n"&gt;_state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loaded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="c1"&gt;// or&lt;/span&gt;

        &lt;span class="n"&gt;_state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern keeps the mutability private while still giving the UI a clean Observable to bind to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The day I properly understood the difference between PublishSubject, BehaviorSubject, ReplaySubject and AsyncSubject was the day my RxSwift code got noticeably cleaner. I stopped fighting the library and started choosing the right tool for the job.&lt;/p&gt;

&lt;p&gt;You don’t need to memorise every edge case. Just remember the core idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Publish → pure events  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Behavior → current state  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replay → recent history  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Async → final result only  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F69uyazyj9rqkmll1ufln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F69uyazyj9rqkmll1ufln.png" alt=" " width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that clicks, the rest becomes muscle memory.&lt;/p&gt;

&lt;p&gt;If you’ve been using mostly PublishSubject for everything (like I did for a long time), try rewriting one of your ViewModels with the more appropriate Subject types. You’ll feel the difference quickly.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>rxswift</category>
      <category>uikit</category>
      <category>swiftui</category>
    </item>
    <item>
      <title>How I Automated Ubuntu Server Hardening with One Script</title>
      <dc:creator>Tesleem Amuda</dc:creator>
      <pubDate>Fri, 31 Jul 2026 00:51:54 +0000</pubDate>
      <link>https://dev.to/tesddev/how-i-automated-ubuntu-server-hardening-with-one-script-209a</link>
      <guid>https://dev.to/tesddev/how-i-automated-ubuntu-server-hardening-with-one-script-209a</guid>
      <description>&lt;h1&gt;
  
  
  Securing and Automating a Cloud Server
&lt;/h1&gt;

&lt;p&gt;The first time I spun up a cloud server, I thought the hard part was over. It wasn't. The server was open to the world: root login enabled, port 22 broadcasting itself to every scanner on the internet, no firewall, and no certificate.&lt;/p&gt;

&lt;p&gt;I checked &lt;code&gt;/var/log/auth.log&lt;/code&gt; a few hours later and found hundreds of failed login attempts. That was the moment I understood why SSH hardening isn't optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SSH Hardening Matters
&lt;/h2&gt;

&lt;p&gt;SSH is the front door to your server. By default, that door is wide open: port 22, password authentication allowed, and root login permitted. Automated bots scan millions of IP addresses every hour looking for exactly this.&lt;/p&gt;

&lt;p&gt;Hardening SSH means closing that gap before anything else touches the server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disable root login: &lt;code&gt;PermitRootLogin no&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Disable password authentication and use keys only: &lt;code&gt;PasswordAuthentication no&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Move SSH off port 22—I use port &lt;code&gt;2247&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Restrict login to one user: &lt;code&gt;AllowUsers deploy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Disconnect idle sessions after 10 minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ClientAliveInterval 300&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ClientAliveCountMax 2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These five changes eliminate the vast majority of automated attacks. You're not invisible, but you're no longer an easy target.&lt;/p&gt;

&lt;h2&gt;
  
  
  What UFW Does
&lt;/h2&gt;

&lt;p&gt;UFW—Uncomplicated Firewall—is Ubuntu's approachable interface to &lt;code&gt;iptables&lt;/code&gt;. Rather than writing low-level rules, you express intent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ufw default deny incoming
ufw default allow outgoing

ufw allow 2247/tcp   &lt;span class="c"&gt;# SSH on custom port&lt;/span&gt;
ufw allow 80/tcp     &lt;span class="c"&gt;# HTTP&lt;/span&gt;
ufw allow 443/tcp    &lt;span class="c"&gt;# HTTPS&lt;/span&gt;

ufw &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything not explicitly allowed is blocked. That's the principle of least privilege applied to networking, and it's the same principle that governs good Kubernetes &lt;code&gt;NetworkPolicies&lt;/code&gt;, IAM roles, and RBAC.&lt;/p&gt;

&lt;p&gt;Start learning it here.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Let's Encrypt Works
&lt;/h2&gt;

&lt;p&gt;Let's Encrypt is a free, automated Certificate Authority trusted by major browsers. The flow is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You point a domain at your server's IP address.&lt;/li&gt;
&lt;li&gt;Certbot serves a challenge file over HTTP to prove that you control the domain.&lt;/li&gt;
&lt;li&gt;Let's Encrypt issues a certificate valid for 90 days.&lt;/li&gt;
&lt;li&gt;Certbot rewrites your Nginx configuration to serve HTTPS and redirect HTTP automatically.&lt;/li&gt;
&lt;li&gt;A scheduled task renews the certificate before it expires—no manual work needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is a free, automatically maintained HTTPS website.&lt;/p&gt;

&lt;p&gt;The following command confirms that the renewal pipeline works without modifying your live certificate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;certbot renew &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Idempotency Means—and Why It Matters
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Idempotent&lt;/strong&gt; means that running the same operation twice produces the same result as running it once.&lt;/p&gt;

&lt;p&gt;It sounds academic. It isn't.&lt;/p&gt;

&lt;p&gt;In practice, it means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;deploy&lt;/code&gt; already exists, skip it instead of returning an error.&lt;/li&gt;
&lt;li&gt;If the certificate already exists, skip it instead of requesting a duplicate.&lt;/li&gt;
&lt;li&gt;If packages are already installed, &lt;code&gt;apt-get&lt;/code&gt; handles them gracefully.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without idempotency, rerunning a setup script after a partial failure could lock you out of your own server. With it, you can run the script confidently after any interruption.&lt;/p&gt;

&lt;p&gt;This habit carries forward into Ansible, Terraform, and every automation tool you'll use at a professional level.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Script
&lt;/h2&gt;

&lt;p&gt;The complete script is available here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tesddev/server-bootstrap" rel="noopener noreferrer"&gt;github.com/tesddev/server-bootstrap&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On a fresh Ubuntu 22.04 server, one command does everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;bash setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order, the script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Updates the system and installs essential packages.&lt;/li&gt;
&lt;li&gt;Creates a non-root &lt;code&gt;deploy&lt;/code&gt; user and copies in the SSH key.&lt;/li&gt;
&lt;li&gt;Hardens SSH by changing the port, disabling root login and password authentication, and setting an idle timeout.&lt;/li&gt;
&lt;li&gt;Configures UFW with an explicit allowlist.&lt;/li&gt;
&lt;li&gt;Installs Nginx and serves a custom page.&lt;/li&gt;
&lt;li&gt;Obtains a Let's Encrypt certificate using Certbot.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What You Get at the End
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SSH restricted to key authentication on a non-standard port&lt;/li&gt;
&lt;li&gt;A firewall permitting only necessary traffic&lt;/li&gt;
&lt;li&gt;A live website at &lt;a href="https://tes-devops.duckdns.org" rel="noopener noreferrer"&gt;https://tes-devops.duckdns.org&lt;/a&gt; with a valid, automatically renewing certificate&lt;/li&gt;
&lt;li&gt;A script you can run on any new server today or six months from now&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Real Lesson
&lt;/h2&gt;

&lt;p&gt;Manual server setup doesn't scale, and more importantly, it doesn't reproduce reliably. The same steps performed by two different people on two different days will produce two subtly different servers.&lt;/p&gt;

&lt;p&gt;Scripts don't have that problem.&lt;/p&gt;

&lt;p&gt;Writing small, idempotent automation scripts is one of the most transferable habits in DevOps. Everything that follows—Ansible playbooks, Terraform modules, and Kubernetes manifests—is this same idea applied at a larger scale.&lt;/p&gt;

&lt;p&gt;➡️ &lt;a href="https://github.com/tesddev/server-bootstrap" rel="noopener noreferrer"&gt;View the server-bootstrap repository on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>ubuntu</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Automated User Management with Bash Script</title>
      <dc:creator>Tesleem Amuda</dc:creator>
      <pubDate>Mon, 01 Jul 2024 15:36:41 +0000</pubDate>
      <link>https://dev.to/tesddev/automated-user-management-with-bash-script-3b3e</link>
      <guid>https://dev.to/tesddev/automated-user-management-with-bash-script-3b3e</guid>
      <description>&lt;p&gt;Managing user accounts in a Linux environment can be tedious, especially when dealing with a large number of new employees. To simplify this process, we can use a Bash script to automate user and group creation, ensuring appropriate permissions and logging. Below is a detailed breakdown of a Bash script that accomplishes this.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;Script Overview&lt;/strong&gt;&lt;/h3&gt;&lt;br&gt;
The script reads a text file containing usernames and group names, creates users and groups as specified, sets up home directories with appropriate permissions and ownership, generates random passwords for the users, and logs all actions to /var/log/user_management.log. It also securely stores the generated passwords in /var/secure/user_passwords.txt.&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;Script Breakdown&lt;/strong&gt;&lt;/h3&gt;&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

# Check if the input file is provided
if [ $# -eq 0 ]; then
    echo "Usage: $0 &amp;lt;user_list_file&amp;gt;"
    exit 1
fi

user_list_file="$1"

# Log and password file paths
log_file="/var/log/user_management.log"
password_file="/var/secure/user_passwords.txt"

# Create the necessary directories and set permissions
mkdir -p /var/log
mkdir -p /var/secure
touch "$log_file"
touch "$password_file"
chmod 600 "$password_file"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Input File Check&lt;/strong&gt;: The script starts by ensuring that an input file is provided. This file should contain the list of users to be managed.&lt;br&gt;
&lt;strong&gt;Directory and File Setup&lt;/strong&gt;: It creates directories and files necessary for logging and storing passwords. Permissions are set to ensure security.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Function to log actions
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" &amp;gt;&amp;gt; "$log_file"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Logging Function&lt;/strong&gt;: A function log_action is defined to log each action taken by the script. This helps in auditing and troubleshooting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Read the user list file
while IFS=';' read -r username groups; do
    # Remove whitespace
    username=$(echo "$username" | xargs)
    groups=$(echo "$groups" | xargs)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reading the User List&lt;/strong&gt;: The script reads each line from the input file, expecting a username and groups separated by a semicolon. Whitespace is trimmed to ensure clean data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Ensure all specified groups exist
    for group in $(echo "$groups" | tr ',' ' '); do
        if ! getent group "$group" &amp;gt;/dev/null; then
            groupadd "$group"
            if [ $? -eq 0 ]; then
                log_action "Created group $group"
            else
                log_action "Failed to create group $group"
                continue
            fi
        else
            log_action "Group $group already exists"
        fi
    done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Group Management&lt;/strong&gt;: The script checks if each specified group exists and creates it if it doesn't. Actions are logged accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Create the personal group
    if ! getent group "$username" &amp;gt;/dev/null; then
        groupadd "$username"
        if [ $? -eq 0 ]; then
            log_action "Created group $username"
        else
            log_action "Failed to create group $username"
            continue
        fi
    else
        log_action "Group $username already exists"
    fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Personal Group Creation&lt;/strong&gt;: For each user, a personal group with the same name is created if it doesn't already exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Create the user with the personal group
    if ! id -u "$username" &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
        useradd -m -g "$username" -s /bin/bash "$username"
        if [ $? -eq 0 ]; then
            log_action "Created user $username with personal group $username"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;User Creation&lt;/strong&gt;: If the user doesn't already exist, the script creates the user account, assigns the personal group, and sets the default shell to bash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            # Set the user's additional groups
            if [ -n "$groups" ]; then
                usermod -aG "$groups" "$username"
                if [ $? -eq 0 ]; then
                    log_action "Added user $username to groups $groups"
                else
                    log_action "Failed to add user $username to groups $groups"
                fi
            fi

            # Generate a random password
            password=$(openssl rand -base64 12)
            echo "$username:$password" | chpasswd
            if [ $? -eq 0 ]; then
                log_action "Set password for user $username"
            else
                log_action "Failed to set password for user $username"
            fi

            # Save the password securely
            echo "$username,$password" &amp;gt;&amp;gt; "$password_file"
        else
            log_action "Failed to create user $username"
        fi
    else
        log_action "User $username already exists"
    fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Additional Group Assignment&lt;/strong&gt;: If additional groups are specified, the user is added to these groups.&lt;br&gt;
&lt;strong&gt;Password Management&lt;/strong&gt;: A random password is generated and set for the user. The password is stored securely in a file with restricted permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Set home directory permissions
    chmod 700 "/home/$username"
    chown "$username:$username" "/home/$username"
    log_action "Set permissions for /home/$username"
done &amp;lt; "$user_list_file"

log_action "Script execution completed."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Home Directory Permissions&lt;/strong&gt;: The script sets strict permissions on the user's home directory to ensure privacy and security.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;Key Features&lt;/strong&gt;&lt;/h3&gt;&lt;p&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;u&gt;Group Creation&lt;/u&gt;: Ensures all specified groups exist before assigning users to them, preventing errors and ensuring proper group membership.&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;User Creation&lt;/u&gt;: Creates users with personal groups and sets up their home directories with appropriate permissions.&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Password Generation&lt;/u&gt;: Generates random, secure passwords for new users and stores them securely.&lt;/li&gt;
&lt;li&gt;
&lt;u&gt;Logging&lt;/u&gt;: Logs all actions to a log file for audit purposes and troubleshooting.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;h3&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;&lt;br&gt;
This script is a robust solution for managing user accounts in a Linux environment. By automating the creation and management of users and groups, it saves time and reduces the potential for errors.&lt;p&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>bash</category>
      <category>documentation</category>
      <category>bashscripting</category>
    </item>
  </channel>
</rss>
