RU | EN | DE

Writing the First Code (“Hello World”) 📝

Let’s order Puppet to create a file. Not manually, but through code.

  1. Navigate to the “manifests” folder (these are instructions for Puppet):
cd /etc/puppetlabs/code/environments/production/manifests
  1. Create the main file site.pp:
sudo nano site.pp
  1. Paste this code (this is the Puppet DSL language):
file { '/tmp/hello_vitaliy.txt':
  ensure  => present,
  content => "Hello! This is my first file, created through Puppet.\n",
  mode    => '0644',
}

(We’re saying: “I want the file /tmp/hello_vitaliy.txt to exist, with this content”).

  1. Save (Ctrl+O, Enter, Ctrl+X).

  2. Apply the magic: Run the agent:

sudo puppet agent -t

If you see Notice: /Stage[main]/Main/File[/tmp/hello_vitaliy.txt]/ensure: created, Puppet created the file by itself! You can check: cat /tmp/hello_vitaliy.txt.

Applying to a Client

1. Go to the Linux server: Open the main manifest file:

sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp

2. Add this code: (Delete old content if any, or just append at the end).

node 'srv-dc01.vbo.local' {
  file { 'c:/hello_from_linux.txt':
    ensure  => present,
    content => "Hello, Windows! I am managing you from Linux.\n",
  }
}

Important: The name srv-dc01.vbo.local. It must exactly match the client’s name.

3. Save the file (Ctrl+O, Enter, Ctrl+X).

4. Go to the client and apply: In PowerShell enter again:

puppet agent -t

If you see File[c:/hello_from_linux.txt]/ensure: created, go check drive C:\. A file should have appeared! 📄

Creating a User 👤

Creating text files is for practice. Admins use Puppet to manage users, install programs, and start services. Let’s tell Puppet to create a new user on your client and give them permissions.

1. On the Linux server: Open site.pp again:

sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp

2. Modify the code: You can delete the old file block or just add a new one below. Enter this (pay attention to the password — Windows requires it to be complex!):

node 'srv-dc01.vbo.local' {
 
  user { 'pup_admin':
    ensure   => present,
    password => 'SuperSecretPass123!',
    groups   => ['Administrators'],
    comment  => 'Admin, created via Puppet',
    managehome => true,
  }
 
}

(This code says: “I want user pup_admin with this password, in the Administrators group”).

3. Save (Ctrl+O, Enter, Ctrl+X).

4. On Windows Server: Run the apply command:

puppet agent -t

Installing Software (Turning Windows into a Web Server) 🌐

Creating users is boring. Let’s install a real service. We’ll turn your Windows Server 2022 into a web server (IIS) so it can serve websites. Puppet has ready-made “modules” (like plugins) for this. But to avoid complicating module installation now, we’ll do it via a PowerShell command wrapped in Puppet.

1. For Puppet to be able to execute PowerShell commands, download the official extension. Execute on the Linux server:

sudo /opt/puppetlabs/bin/puppet module install puppetlabs-powershell

2. On the Linux server: Open site.pp:

sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp

3. Add the IIS install task: Insert this block inside node 'srv-dc01.vbo.local' { ... }. Note: Don’t delete the old content, just add this below user creation, but before the closing }.

  # Task 3: Turn the server into a Web server (IIS)
  exec { 'Install-IIS':
    command   => 'Install-WindowsFeature -Name Web-Server -IncludeManagementTools',
    provider  => powershell,
    # This magic checks: "If IIS is already installed, do nothing"
    onlyif    => 'if ((Get-WindowsFeature -Name Web-Server).InstallState -eq "Installed") { exit 1 } else { exit 0 }',
    logoutput => true,
  }

4. Save and exit.

5. On Windows run:

puppet agent -t

Website Replacement 🎩🐇

The standard blue page is boring. Let’s prove we completely own this server. We’ll replace the main website page with our own, without logging into Windows.

1. On the Linux server: Open site.pp:

sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp

2. Add new code: Inside the node 'srv-dc01.vbo.local' block, below the IIS installation, add these lines:

  # Task 4: Remove the standard IIS placeholder
  file { 'c:/inetpub/wwwroot/iisstart.htm':
    ensure => absent,
  }
 
  # Task 5: Create our website
  file { 'c:/inetpub/wwwroot/index.html':
    ensure  => present,
    content => "<html>
                  <body style='background-color: black; color: green; font-family: monospace;'>
                    <h1>MISSION ACCOMPLISHED</h1>
                    <p>This site was captured and is managed via Puppet!</p>
                    <p>Vitaliy + Gemi = Dream Team 🚀</p>
                  </body>
                </html>",
  }

3. Save (Ctrl+O, Enter, Ctrl+X).

4. On Windows: Apply changes:

puppet agent -t

Professional Style. IIS. (Modules) 🏗️

We installed IIS the “dirty” way — through a PowerShell command (exec). That works, but it’s not the Puppet Way.

Step 1. Download the “Driver” for IIS (On Linux server) 🧩

We need the official module from PuppetLabs that teaches the server to manage IIS. On Linux:

sudo /opt/puppetlabs/bin/puppet module install puppetlabs-iis
sudo /opt/puppetlabs/bin/puppet module install puppetlabs-pwshlib

You should see: Notice: Installing -- do not interrupt ... And finally: └─ puppetlabs-iis (v...).

Step 2. Rewrite the Code 📝

Now the interesting part. We’ll delete the scary PowerShell block and replace it with the elegant iis_feature resource.

  1. Open the file:
sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp
  1. Completely replace the content of the node block with this code:
node 'srv-dc01.vbo.local' {
 
  # --- Block 1: User (same as before) ---
  user { 'pup_admin':
    ensure     => present,
    password   => 'SuperSecretPass123!',
    groups     => ['Administrators'],
    managehome => true,
  }
 
  # --- Block 2: IIS (PROFESSIONAL STYLE) ---
  # Instead of exec, we use the module's native resource
  iis_feature { 'Web-Server':
    ensure                   => present,
    include_management_tools => true,
  }
 
  # --- Block 3: Website ---
  
  # Remove old placeholder
  file { 'c:/inetpub/wwwroot/iisstart.htm':
    ensure => absent,
  }
 
  # Our website
  file { 'c:/inetpub/wwwroot/index.html':
    ensure  => present,
    content => "<html>
                  <body style='background-color: black; color: green; font-family: monospace;'>
                    <h1>MISSION ACCOMPLISHED</h1>
                    <p>This site was created with Gemini and Puppet!</p>
                    <p>Vitaliy + Gemi = Dream Team 🚀</p>
                  </body>
                </html>",
  }
}
  1. Save (Ctrl+O, Enter, Ctrl+X).

Step 3. Testing on Windows 🧪

Now something important happens. IIS is already installed.

  • If this were a dumb script, it would try to install it again and throw an error.
  • The smart module checks: “Ah, Web-Server is already present. Management tools too. So I do nothing.” Run on Windows:
puppet agent -t

Second Website on Port 8080 🏗️

We’re using the iis_site and iis_application_pool resources. This is what we installed the module for.

1. Execute on the Linux server:

sudo /opt/puppetlabs/bin/puppetserver gem install ruby-pwsh
sudo systemctl restart puppetserver

2. On Linux server: Open site.pp:

sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp

3. Add this code INSIDE the node block: (You can add this at the very bottom, before the closing curly brace }).

  # --- Block 4: New site "Secret Project" on port 8080 ---
 
  # 1. Create folder for the new site
  file { 'c:/inetpub/secret_site':
    ensure => directory,
  }
 
  # 2. Drop a file there
  file { 'c:/inetpub/secret_site/index.html':
    ensure  => present,
    content => "<h1>SECRET AREA 51</h1><p>Access for Vitaliy and Gemi only.</p>",
  }
 
  # 3. Create Application Pool (for process isolation — Best Practice)
  iis_application_pool { 'SecretPool':
    ensure => present,
    state  => 'started',
  }
 
  # 4. Create the Site and bind it to port 8080
  iis_site { 'SecretSite':
    ensure          => started,
    physicalpath    => 'c:\\inetpub\\secret_site',
    applicationpool => 'SecretPool',
    bindings        => [
      {
        'protocol'           => 'http',
        'bindinginformation' => '*:8080:',
      }
    ],
    require         => File['c:/inetpub/secret_site'], # Folder first, then site!
  }
 
  # 5. Open port in Firewall (otherwise no external access)
  exec { 'Open-Port-8080':
    command   => 'New-NetFirewallRule -DisplayName "Puppet-8080" -Direction Inbound -LocalPort 8080 -Protocol TCP -Action Allow',
    provider  => powershell,
    onlyif    => 'if (Get-NetFirewallRule -DisplayName "Puppet-8080" -ErrorAction SilentlyContinue) { exit 1 } else { exit 0 }',
  }

4. Save and exit.

5. On Windows: Run the agent:

puppet agent -t