This commit is contained in:
marito 2025-06-15 08:14:58 +08:00
commit 23b08fb56b
14 changed files with 317 additions and 0 deletions

27
Lenvi.yaml Normal file
View File

@ -0,0 +1,27 @@
# ------------------------------------------------------------------
# Lenvi: Central Configuration for Your Development Environment
# ------------------------------------------------------------------
# 1. Set the global database engine.
# Choose one: "mariadb", "mysql", or "postgres"
db_engine: "mariadb"
# 2. Define all your Laravel sites below.
# Add, edit, or remove sites as needed.
sites:
- domain: myapp.local
project_root: /home/mar/projects/myapp
php_version: "8.2"
- domain: legacy-app.local
project_root: /home/mar/projects/legacy-app
php_version: "8.0"
- domain: another-project.local
project_root: /home/mar/projects/another-project
php_version: "8.2"
# Example of a new project you might add later:
# - domain: new-api.local
# project_root: /home/mar/projects/new-api
# php_version: "8.3"

54
README.md Normal file
View File

@ -0,0 +1,54 @@
# Lenvi Ansible Provisioner
Lenvi is a lightweight, Ansible-powered tool for managing local Laravel development environments. It provides a Homestead-like experience without the overhead of a virtual machine, running natively on Linux or on Windows via WSL2.
## Features
- **Centralized Configuration:** Manage all your projects from a single `lenvi.yaml` file.
- **Multi-PHP:** Assign a specific PHP version (e.g., 8.0, 8.2, 8.3) to each site.
- **Database Support:** Automatically creates databases using a shared MariaDB, MySQL, or PostgreSQL server.
- **Idempotent:** Safely run the provisioner at any time to update your environment.
## Prerequisites
1. **Ansible:** You must have Ansible installed.
```bash
# On Debian/Ubuntu
sudo apt update
sudo apt install python3-pip -y
pip3 install ansible
```
2. **WSL2 (for Windows users):** Install WSL2 and a Linux distribution like **Ubuntu 22.04** from the Microsoft Store. All subsequent commands must be run from the WSL2 terminal.
## How to Use
1. **Clone this repository:**
```bash
git clone <your-repo-url> ~/tools/lenvi_ansible
```
2. **Configure `lenvi.yaml`:**
Open `~/tools/lenvi_ansible/lenvi.yaml` and configure it for your projects. Set your `db_engine` and list all your sites under the `sites` key.
3. **Run the Playbook:**
Navigate to the `lenvi_ansible` directory and run the main playbook.
```bash
cd ~/tools/lenvi_ansible
ansible-playbook playbook.yml --ask-become-pass
```
Ansible will ask for your `sudo` password to install software and configure services.
### Important Note for Windows (WSL2) Users
For your Windows browser (Chrome, Firefox, etc.) to access a site like `myapp.test`, you must manually edit the **Windows hosts file**.
1. Open **Notepad** as an **Administrator**.
2. Open the file: `C:\Windows\System32\drivers\etc\hosts`
3. For each site in your `lenvi.yaml`, add a new line:
```
127.0.0.1 myapp.test
127.0.0.1 another-app.test
```
4. Save the file. You only need to do this once per new domain.
You can now access your sites in your browser!

3
ansible.cfg Normal file
View File

@ -0,0 +1,3 @@
[defaults]
inventory = inventory
host_key_checking = False

2
inventory Normal file
View File

@ -0,0 +1,2 @@
[lenvi_dev]
localhost ansible_connection=local

19
playbook.yml Normal file
View File

@ -0,0 +1,19 @@
---
- name: "Provision Lenvi Development Environment"
hosts: lenvi_dev
become: yes
vars_files:
- Lenvi.yaml
pre_tasks:
- name: "Gather a unique list of required PHP versions from sites"
ansible.builtin.set_fact:
php_versions_to_install: "{{ sites | map(attribute='php_version') | list | unique }}"
roles:
- role: common
- role: database
- role: php
- role: nginx
- role: projects

View File

@ -0,0 +1,14 @@
---
- name: "Install common dependencies"
ansible.builtin.apt:
name:
- software-properties-common
- ca-certificates
- apt-transport-https
state: present
update_cache: yes
- name: "Add Ondřej PPA for PHP"
ansible.builtin.apt_repository:
repo: "ppa:ondrej/php"
state: present

View File

@ -0,0 +1,30 @@
---
- name: "Install MariaDB/MySQL server"
ansible.builtin.apt:
name: mariadb-server
state: present
update_cache: yes
when: db_engine == 'mariadb' or db_engine == 'mysql'
- name: "Install PostgreSQL server"
ansible.builtin.apt:
name:
- postgresql
- postgresql-contrib
state: present
update_cache: yes
when: db_engine == 'postgres'
- name: "Ensure MariaDB/MySQL service is running and enabled"
ansible.builtin.service:
name: mariadb
state: started
enabled: yes
when: db_engine == 'mariadb' or db_engine == 'mysql'
- name: "Ensure PostgreSQL service is running and enabled"
ansible.builtin.service:
name: postgresql
state: started
enabled: yes
when: db_engine == 'postgres'

View File

@ -0,0 +1,5 @@
---
- name: "Reload Nginx"
ansible.builtin.service:
name: nginx
state: reloaded

View File

@ -0,0 +1,17 @@
---
- name: "Install Nginx"
ansible.builtin.apt:
name: nginx
state: present
- name: "Ensure Nginx is enabled and started"
ansible.builtin.service:
name: nginx
state: started
enabled: yes
- name: "Remove the default Nginx site to prevent conflicts"
ansible.builtin.file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload Nginx

28
roles/php/tasks/main.yml Normal file
View File

@ -0,0 +1,28 @@
---
- name: "Install required PHP versions and extensions"
ansible.builtin.apt:
name:
# Core PHP
- "php{{ item }}"
- "php{{ item }}-fpm"
- "php{{ item }}-cli"
# Common Laravel Extensions
- "php{{ item }}-common"
- "php{{ item }}-mysql"
- "php{{ item }}-pgsql"
- "php{{ item }}-xml"
- "php{{ item }}-zip"
- "php{{ item }}-mbstring"
- "php{{ item }}-curl"
- "php{{ item }}-bcmath"
state: present
loop: "{{ php_versions_to_install }}"
when: php_versions_to_install is defined and php_versions_to_install | length > 0
- name: "Ensure all PHP-FPM services are enabled and started"
ansible.builtin.service:
name: "php{{ item }}-fpm"
enabled: yes
state: started
loop: "{{ php_versions_to_install }}"
when: php_versions_to_install is defined and php_versions_to_install | length > 0

View File

@ -0,0 +1,7 @@
---
- name: "Reload PHP-FPM Services"
ansible.builtin.service:
name: "php{{ item }}-fpm"
state: reloaded
loop: "{{ php_versions_to_install }}"
when: php_versions_to_install is defined and php_versions_to_install | length > 0

View File

@ -0,0 +1,8 @@
---
- name: "Create Nginx config for {{ project.domain }} in conf.d"
ansible.builtin.template:
src: nginx-site.conf.j2
dest: "/etc/nginx/conf.d/{{ project.domain }}.conf"
owner: root
group: root
mode: '0644'

View File

@ -0,0 +1,11 @@
---
# This loop will run the 'configure_site.yml' tasks for each site
# defined in Lenvi.yaml. Handlers are notified only once at the end.
- name: "Configure Nginx site for each project"
ansible.builtin.include_tasks: configure_site.yml
loop: "{{ sites }}"
loop_control:
loop_var: project
notify:
- Reload Nginx
- Reload PHP-FPM Services

View File

@ -0,0 +1,92 @@
server {
listen 80;
server_name {{ project.domain }};
root {{ project.project_root }}/public;
index index.php;
access_log /var/log/nginx/{{ project.domain }}-access.log;
error_log /var/log/nginx/{{ project.domain }}-error.log;
# General performance
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30s;
types_hash_max_size 2048;
server_tokens off;
client_max_body_size 100M;
client_body_buffer_size 128k;
# Security headers
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
# Gzip compression
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/x-javascript
application/xml
application/xml+rss
font/ttf
font/otf
image/svg+xml;
# Laravel-friendly routing
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM handling
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php{{ project.php_version }}-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 64k;
fastcgi_temp_file_write_size 64k;
fastcgi_intercept_errors on;
}
# Block hidden files
location ~ /\.(?!well-known).* {
deny all;
}
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2?|ttf|svg|eot)$ {
expires 30d;
access_log off;
add_header Cache-Control "public";
}
# Maintenance mode redirect (Laravel down file)
if (-f $document_root/storage/framework/down) {
return 503;
}
# Optional: Nginx status endpoint (local only)
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}