|
4 | 4 | {% set meta = { |
5 | 5 | title: 'Development Environment | AlmaLinux 10 on WSL 2', |
6 | 6 | description: 'AlmaLinux 10 on WSL 2 for a RHEL-compatible local stack. One Ansible playbook installs PHP, Apache, ' |
7 | | - ~ 'MariaDB, Composer, Node.js and phpMyAdmin, and provisions a virtualhost for every project you add.', |
| 7 | + ~ 'MariaDB, Composer, Node.js and phpMyAdmin, and a second provisions a virtualhost for every project you add.', |
8 | 8 | openGraphImage: '/opengraph/pages/twitter-card-wsl2.png', |
9 | 9 | } %} |
10 | 10 |
|
|
24 | 24 | .spec-table td { color: var(--text); } |
25 | 25 | .spec-note { margin-top: 14px; font-size: 13.5px; color: var(--text-dim); } |
26 | 26 | .step-cmd { display: block; margin-top: 12px; font-family: var(--mono); font-size: 12.5px; color: var(--teal); overflow-x: auto; } |
| 27 | + pre.step-cmd { margin-bottom: 0; white-space: pre; } |
27 | 28 |
|
28 | 29 | /* Windows/AlmaLinux boundary diagram in the hero - scoped to this page. */ |
29 | 30 | .ws-flow { display: block; width: 100%; height: auto; margin-top: 6px; } |
|
48 | 49 | <div class="wrap hero-grid"> |
49 | 50 | <div> |
50 | 51 | <span class="eyebrow">Development environment . AlmaLinux 10 . WSL2</span> |
51 | | - <h1>AlmaLinux development, one playbook away on WSL2</h1> |
| 52 | + <h1>Development Environment</h1> |
52 | 53 | <p class="sub"> |
53 | 54 | Dotkernel's local environment runs <strong>AlmaLinux 10</strong> - inside <strong>WSL 2</strong> on Windows, or on bare |
54 | 55 | metal with no WSL at all. One <strong>Ansible</strong> playbook installs PHP, Apache, MariaDB, Composer, Node.js and |
|
75 | 76 | <div class="hero-visual"> |
76 | 77 | <div class="pipeline"> |
77 | 78 | <div class="pipeline-label"><span>Windows host, Linux environment</span></div> |
78 | | - <svg class="ws-flow" viewBox="0 0 400 200" role="img" aria-label="Two panels, Windows on the left with Terminal and IDE boxes, and AlmaLinux 10 on the right listing the components one playbook installs - web server, database, PHP, Node.js, Git and Composer, and Ansible - separated by a WSL 2 boundary"> |
| 79 | + <svg class="ws-flow" viewBox="0 0 400 200" role="img" aria-label="Two panels, Windows on the left with Terminal and IDE boxes, and AlmaLinux 10 on the right listing the components one playbook installs - web server, database, PHP, Node.js, and Git and Composer - separated by a WSL 2 boundary"> |
79 | 80 | <defs> |
80 | 81 | <marker id="ws-arrowhead" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"> |
81 | 82 | <path d="M0,0 L10,5 L0,10 Z" class="ws-arrow"/> |
|
113 | 114 |
|
114 | 115 | <rect class="ws-comp" x="230" y="142" width="120" height="20" rx="5"/> |
115 | 116 | <text class="ws-comp-label" x="290" y="156">Git & Composer</text> |
116 | | - |
117 | | - <rect class="ws-comp" x="230" y="166" width="120" height="20" rx="5"/> |
118 | | - <text class="ws-comp-label" x="290" y="180">Ansible</text> |
119 | 117 | </svg> |
120 | 118 | </div> |
121 | 119 | </div> |
|
134 | 132 | Windows-native rebuild of every tool. |
135 | 133 | </p> |
136 | 134 | <p class="lede"> |
137 | | - Everything here also runs the same way without WSL, directly on a bare AlmaLinux 10 host - the |
138 | | - Ansible playbooks do not know or care which one they are provisioning. |
| 135 | + Everything from Setup Packages onwards also runs on a bare AlmaLinux 10 host without WSL - the |
| 136 | + Ansible playbooks do not know or care which one they are provisioning. Connect over SSH, and use |
| 137 | + the server's IP address instead of <code>localhost</code> when you test it. |
139 | 138 | </p> |
140 | 139 | </div> |
141 | 140 | <div class="traits"> |
|
167 | 166 | <div class="section-head"> |
168 | 167 | <span class="eyebrow">Setup</span> |
169 | 168 | <h2>Three steps to a running shell</h2> |
170 | | - <p>Each step runs in a different place - Windows Terminal for the first two, the AlmaLinux 10 shell for |
171 | | - the third. The full walkthrough, prompts and all, is in the docs.</p> |
| 169 | + <p>Steps 1 and 2 run in Windows Terminal and step 3 in the AlmaLinux 10 shell; step 2 ends inside the |
| 170 | + new distro with a quick systemd check. The full walkthrough, prompts and all, is in the docs.</p> |
172 | 171 | </div> |
173 | 172 |
|
174 | 173 | <div class="standards-grid"> |
175 | 174 | <div class="standard"> |
176 | 175 | <h4>1 . Terminal & requirements</h4> |
177 | | - <p>Install Windows Terminal, then confirm WSL 2 is enabled - Hyper-V, Virtual Machine Platform and |
178 | | - Windows Subsystem for Linux, all turned on in Windows features.</p> |
179 | | - <code class="step-cmd">wsl -v</code> |
| 176 | + <p>On Windows 11, install Windows Terminal, then check for a modern WSL 2 install. If |
| 177 | + <code>wsl --version</code> isn't recognized, install WSL 2 with |
| 178 | + <code>wsl --install --no-distribution</code> and restart when prompted.</p> |
| 179 | + <code class="step-cmd">wsl --version</code> |
180 | 180 | </div> |
181 | 181 | <div class="standard"> |
182 | 182 | <h4>2 . Install AlmaLinux 10</h4> |
183 | 183 | <p>Stop any other running distro, then install AlmaLinux 10 and create your Unix username and |
184 | 184 | password when prompted.</p> |
185 | 185 | <code class="step-cmd">wsl --install -d AlmaLinux-10</code> |
| 186 | + <p>Before moving on, confirm systemd is active inside AlmaLinux 10 - the playbook needs it. If the |
| 187 | + check below prints an error instead of a status, add <code>systemd=true</code> under |
| 188 | + <code>[boot]</code> in <code>/etc/wsl.conf</code>, run <code>wsl --shutdown</code> from Windows |
| 189 | + Terminal and reopen the distro.</p> |
| 190 | + <code class="step-cmd">systemctl is-system-running</code> |
186 | 191 | </div> |
187 | 192 | <div class="standard"> |
188 | 193 | <h4>3 . Setup packages</h4> |
189 | | - <p>Clone <code>dotkernel/development</code>, fill in <code>config.yml</code> with your Git identity and MariaDB |
190 | | - root password, and let Ansible provision the rest.</p> |
| 194 | + <p>Inside AlmaLinux 10, update the system, add the EPEL and Remi repositories, and install |
| 195 | + <code>ansible-core</code> with the <code>community.general</code> and <code>community.mysql</code> |
| 196 | + collections. Then clone the <code>alma-linux-10</code> branch of <code>dotkernel/development</code>, |
| 197 | + copy <code>wsl/config.yml.dist</code> to <code>config.yml</code>, fill in your Git identity and |
| 198 | + MariaDB root password, and run the playbook from <code>development/wsl</code>.</p> |
191 | 199 | <code class="step-cmd">ansible-playbook -i hosts install.yml --ask-become-pass</code> |
192 | 200 | </div> |
193 | 201 | </div> |
194 | 202 |
|
195 | 203 | <p class="spec-note"> |
196 | 204 | Not using WSL? Skip straight to Setup Packages on a bare AlmaLinux 10 host - the same playbook runs |
197 | | - there unchanged. |
| 205 | + there unchanged; test it with the server's IP address instead of <code>localhost</code>. |
| 206 | + </p> |
| 207 | + <p class="spec-note"> |
| 208 | + After setup, |
| 209 | + <a href="https://docs.dotkernel.org/development/v2/editor-integration/" target="_blank" rel="noopener">Editor Integration</a> |
| 210 | + connects VS Code or PhpStorm, and |
| 211 | + <a href="https://docs.dotkernel.org/development/v2/wsl-configuration/" target="_blank" rel="noopener">WSL Configuration</a> |
| 212 | + covers where to keep projects and how to cap WSL's memory and CPU. |
198 | 213 | </p> |
199 | 214 | </div> |
200 | 215 | </section> |
|
223 | 238 | </tr> |
224 | 239 | <tr> |
225 | 240 | <th scope="row">Database</th> |
226 | | - <td>MariaDB 11.4 LTS, plus phpMyAdmin for browsing it.</td> |
| 241 | + <td>MariaDB 12.3 from the MariaDB repository, plus phpMyAdmin for browsing it.</td> |
227 | 242 | </tr> |
228 | 243 | <tr> |
229 | 244 | <th scope="row">PHP</th> |
230 | | - <td>8.4 by default via the Remi repository; <code>php81</code> … <code>php85</code> aliases switch |
| 245 | + <td>8.5 by default via the Remi repository; <code>php81</code> … <code>php85</code> aliases switch |
231 | 246 | versions.</td> |
232 | 247 | </tr> |
233 | 248 | <tr> |
|
236 | 251 | </tr> |
237 | 252 | <tr> |
238 | 253 | <th scope="row">Git & Composer</th> |
239 | | - <td>Your Git identity from <code>config.yml</code>, and the latest Composer, kept current with |
240 | | - <code>composer self-update</code>.</td> |
241 | | - </tr> |
242 | | - <tr> |
243 | | - <th scope="row">Ansible</th> |
244 | | - <td><code>community.general</code> and <code>community.mysql</code> collections - the same tool that just |
245 | | - installed itself.</td> |
| 254 | + <td>Your Git identity from <code>config.yml</code>, and the latest Composer at install time; update |
| 255 | + it later with <code>composer self-update</code>.</td> |
246 | 256 | </tr> |
247 | 257 | </tbody> |
248 | 258 | </table> |
|
261 | 271 | file - any <code>*.localhost</code> domain is routed automatically. |
262 | 272 | </p> |
263 | 273 | <p class="lede"> |
264 | | - List the domains you want under <code>config.yml</code>'s <code>virtualhosts</code> key and run the playbook. |
| 274 | + List the domains you want under <code>config.yml</code>'s <code>virtualhosts</code> key and run |
| 275 | + <code>create-virtualhost.yml</code> - a separate playbook you re-run for every new project, without |
| 276 | + repeating <code>install.yml</code>. |
265 | 277 | Existing entries are left untouched, so you keep adding to the same file as your project grows. |
266 | 278 | </p> |
267 | 279 | <div class="hero-ctas"> |
|
270 | 282 | </div> |
271 | 283 | <div class="callout"> |
272 | 284 | <h4>One playbook, every domain</h4> |
273 | | - <p>In <code>development/wsl/config.yml</code>, under <code>virtualhosts</code>:</p> |
274 | | - <code class="step-cmd">api.dotkernel.localhost</code> |
| 285 | + <p>In <code>development/wsl/config.yml</code>, under <code>config.virtualhosts</code>:</p> |
| 286 | + <pre class="step-cmd">config: |
| 287 | + virtualhosts: |
| 288 | + - "api.dotkernel.localhost"</pre> |
| 289 | + <p> |
| 290 | + <code>api.dotkernel.localhost</code> is only an example - use any name your project needs, such as |
| 291 | + <code>laravel.localhost</code> or <code>shop.localhost</code>, as long as it ends in |
| 292 | + <code>.localhost</code> and uses only lowercase letters, numbers and hyphens. Add one list item per |
| 293 | + project. |
| 294 | + </p> |
275 | 295 | <p>Then provision it:</p> |
276 | 296 | <code class="step-cmd">ansible-playbook -i hosts create-virtualhost.yml --ask-become-pass</code> |
277 | 297 | <p> |
278 | | - Files go under <code>/var/www/api.dotkernel.localhost/html</code>, with the document root at |
279 | | - <code>html/public</code>. |
| 298 | + Files go under <code>/var/www/<your-domain>/html</code> - for example |
| 299 | + <code>/var/www/api.dotkernel.localhost/html</code> - with the document root at |
| 300 | + <code>html/public</code>. <code>html/public</code> doesn't exist until you place a project there, |
| 301 | + so the URL shows an error until then. |
280 | 302 | </p> |
281 | 303 | </div> |
282 | 304 | </div> |
|
310 | 332 | <summary>How do I fix permission issues? <span class="chev">+</span></summary> |
311 | 333 | <div class="acc-body"> |
312 | 334 | <p>Local development only: <code>chmod -R 777 data</code>, <code>log</code> or |
313 | | - <code>public/uploads</code>, whichever directory the error names.</p> |
| 335 | + <code>public/uploads</code>, whichever directory the error names. Don't carry this into |
| 336 | + staging or production.</p> |
314 | 337 | </div> |
315 | 338 | </details> |
316 | 339 | <details class="acc"> |
317 | 340 | <summary>Where are the error logs? <span class="chev">+</span></summary> |
318 | 341 | <div class="acc-body"> |
319 | | - <p>Apache: <code>/var/log/httpd/error_log</code>. PHP-FPM: <code>/var/log/php-fpm/error.log</code> and |
320 | | - <code>www-error.log</code>.</p> |
| 342 | + <p>Apache: <code>/var/log/httpd/error_log</code>, plus |
| 343 | + <code>/var/www/<virtualhost>/log/error.log</code> for each virtualhost. PHP-FPM: |
| 344 | + <code>/var/log/php-fpm/error.log</code> and <code>www-error.log</code>.</p> |
321 | 345 | </div> |
322 | 346 | </details> |
323 | | - </div> |
324 | | - <div> |
325 | 347 | <details class="acc"> |
326 | 348 | <summary>How do I update Composer? <span class="chev">+</span></summary> |
327 | 349 | <div class="acc-body"> |
|
336 | 358 | it like any other command.</p> |
337 | 359 | </div> |
338 | 360 | </details> |
| 361 | + </div> |
| 362 | + <div> |
339 | 363 | <details class="acc"> |
340 | 364 | <summary>How do I delete a virtualhost? <span class="chev">+</span></summary> |
341 | 365 | <div class="acc-body"> |
342 | 366 | <p>Remove its folder under <code>/var/www/</code>, its Apache config and enabled-site symlink, then |
343 | 367 | <code>sudo systemctl restart httpd</code>.</p> |
344 | 368 | </div> |
345 | 369 | </details> |
| 370 | + <details class="acc"> |
| 371 | + <summary>Why does the playbook fail with a systemd error? <span class="chev">+</span></summary> |
| 372 | + <div class="acc-body"> |
| 373 | + <p>systemd isn't active in the distro yet. Add <code>systemd=true</code> under <code>[boot]</code> in |
| 374 | + <code>/etc/wsl.conf</code>, run <code>wsl --shutdown</code> from Windows Terminal, reopen |
| 375 | + AlmaLinux 10 and re-run <code>install.yml</code>.</p> |
| 376 | + </div> |
| 377 | + </details> |
| 378 | + <details class="acc"> |
| 379 | + <summary>What if port 80 is already in use? <span class="chev">+</span></summary> |
| 380 | + <div class="acc-body"> |
| 381 | + <p>Find the Windows service holding it with <code>netstat -ano | findstr :80</code> and stop it, or |
| 382 | + change Apache's <code>Listen</code> port in <code>/etc/httpd/conf/httpd.conf</code> and restart |
| 383 | + httpd.</p> |
| 384 | + </div> |
| 385 | + </details> |
| 386 | + <details class="acc"> |
| 387 | + <summary>Is this environment safe to expose beyond localhost? <span class="chev">+</span></summary> |
| 388 | + <div class="acc-body"> |
| 389 | + <p>No. It is for local development only: the MariaDB root password is stored in plaintext, |
| 390 | + phpMyAdmin allows root login and the firewall is off by default.</p> |
| 391 | + </div> |
| 392 | + </details> |
346 | 393 | <details class="acc"> |
347 | 394 | <summary>Can I run this without WSL? <span class="chev">+</span></summary> |
348 | 395 | <div class="acc-body"> |
349 | | - <p>Yes - every instruction here works the same way on a bare AlmaLinux 10 host.</p> |
| 396 | + <p>Yes - from Setup Packages onwards the steps are the same on a bare AlmaLinux 10 host. Skip the |
| 397 | + WSL steps, connect over SSH, and use the server's IP address instead of |
| 398 | + <code>localhost</code>.</p> |
350 | 399 | </div> |
351 | 400 | </details> |
352 | 401 | </div> |
|
358 | 407 | <div class="wrap about-inner"> |
359 | 408 | <div> |
360 | 409 | <span class="eyebrow">Built for how the platform ships</span> |
361 | | - <h2>Provision once, match production everywhere.</h2> |
| 410 | + <h2>Provision once, match your production OS</h2> |
362 | 411 | </div> |
363 | 412 | <div> |
364 | 413 | <p class="about-text"> |
365 | 414 | The WSL 2 + AlmaLinux 10 setup is maintained by the same team behind the rest of the Headless |
366 | | - Platform, so the local environment stays in step with what actually runs in production - not a |
367 | | - Docker approximation of it. |
| 415 | + Platform, so the local environment stays on the same OS family as production - not a Docker |
| 416 | + approximation of it. It is a local development environment only: security is relaxed by default, |
| 417 | + so never expose it to a network. |
368 | 418 | </p> |
369 | 419 | <div class="about-cta"> |
370 | 420 | <a class="btn btn-ghost" href="{{ url('page::contact') }}">Talk to us -></a> |
|
0 commit comments