diff --git a/content/posts/20210326-example-webserver/index.md b/content/posts/20210326-example-webserver/index.md index 393bdbc..848369f 100644 --- a/content/posts/20210326-example-webserver/index.md +++ b/content/posts/20210326-example-webserver/index.md @@ -2,65 +2,94 @@ title: "Example: Webserver (nginx+php-fpm)" author: "phoenix" date: 2021-03-26T10:49:29+01:00 +PublishDate: 2021-03-26T10:49:29+01:00 +Lastmod: 2022-06-29T09:56:07+01:00 + --- -In this post we are going to setup our example `jellyfish` host to run `nginx `and `php-fpm`. The provided [example playbook](jellyfish.yml) should be a good starting point for your own webserver. +In this post we are going to setup our example `jellyfish` host to run `nginx `and `php-fpm`. Checkout the provided [jellyfish.yml](jellyfish.yml) playbook for a quickstart. This example playbook also configures a virtual host and creates a typical `phpinfo.php` file to test your setup. -In addition, the exaple playbook also setups the `jellyfish.conf` nginx virtual host file to run `php` files with `php-fpm` and we create a typical `phpinfo.php` file to test our setup +This provides a solid example to setup your own webserver running `nginx` with `php-fpm` atop which you can later on run other php applications like [nextcloud](https://nextcloud.com/) or [MediaWiki](https://www.mediawiki.org/wiki/MediaWiki). -# Example +## Playbook -This [example playbook](jellyfish.yml) sets up a webserver with `nginx` and `php-fpm`. +The [jellyfish.yml](jellyfish.yml) example playbook sets up a webserver with `nginx` and `php-fpm`: - --- - - hosts: jellyfish - user: root - - roles: - - role: geekoops-nginx - vars: - config_firewall: true - firewall_zone: "public" - - role: geekoops-php-fpm - vars: - apcu_enable: true - apcu_shm_size: 32M - php_memlimit: 256M - php_maxuploadsize: 64M - - tasks: - - name: Deploy jellyfish config for nginx - copy: - content: | - server { - listen 80 default_server; - listen [::]:80 default_server; - server_name jellyfish; - location / { - proxy_pass http://127.0.0.1:3000/; - } - } - dest: "/etc/nginx/vhosts.d/jellyfish.conf" - group: "root" - owner: "root" - mode: 0754 - notify: Restart nginx - - name: Deploy phpinfo script - copy: - content: "" - dest: "/srv/www/phpinfo.php" - group: "www" - owner: "wwwrun" - mode: 0754 - - handlers: - - name: Restart nginx - systemd: - name: nginx - state: restarted +```yaml +--- +- hosts: jellyfish + user: root -# Example + roles: + - role: geekoops-nginx + vars: + config_firewall: true + firewall_zone: "public" + - role: geekoops-php-fpm + vars: + apcu_enable: true + apcu_shm_size: 32M + php_memlimit: 256M + php_maxuploadsize: 64M -For this example, ensure you have installed `ansible` on your host machine + tasks: + - name: Deploy jellyfish config for nginx + copy: + content: | + server { + listen 80 default_server; + listen [::]:80 default_server; + server_name jellyfish; + root /srv/www/htdocs; + location / { + try_files $uri $uri/ =404; + } + location ~ \.php$ { + fastcgi_pass unix:/run/php-fpm/php-fpm.sock; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } + } + dest: "/etc/nginx/vhosts.d/jellyfish.conf" + group: "root" + owner: "root" + mode: 0754 + notify: Restart nginx + - name: Ensure nginx is in the www group + user: + name: nginx + groups: www + append: yes + notify: Restart nginx + - name: Deploy phpinfo script + copy: + content: "" + dest: "/srv/www/htdocs/phpinfo.php" + group: "www" + owner: "wwwrun" + mode: 0754 +# Note: The current php-fpm apparmor profile does not allow access to /srv/www. +# We set app-armor to complain in this role. Note that you should use e.g. +# `yast apparmor` to update your AppArmor profile instead of disabling AppArmor +# as a whole! + - name: Ensure aa-complain is installed + package: + name: apparmor-utils + state: present + - name: Put app-armor to complain mode + shell: aa-complain /etc/apparmor.d/php-fpm + + handlers: + - name: Restart nginx + systemd: + name: nginx + state: restarted +``` + + +# Step-by-setup guid + +Let's start with the basics. First ensure you have `ansible` installed on your host machine sudo zypper in ansible @@ -71,27 +100,40 @@ Then, we need a working directory, let's say `jellyfish`. All next steps should be run in this directory. -## No install required: JeOS VM +We first setup a JeOS VM as our playing ground. Skip down to the [Running the playbook](#running-the-playbook) section in case you have already your VM up and running and just want the playbook to run. -The most easy way of just getting a openSUSE Leap VM running, is to use the JeOS image, available at https://get.opensuse.org/leap. Download the KVM or XEN HVM image, import it into your `virt-manager` and your're ready to go! +## Ready in under 5 minutes: openSUSE JeOS -Once you fire the machine up, you just need a handful of configuration steps, and then your have a functional JeOS VM, which is enough for this setup. +> No installation required! This VM image is ready in under 5 minutes. -### JeOS installation +The most easy way of just getting a openSUSE Leap VM running, is to use the JeOS image. JeOS (or MinimalVM) is a slimmed down image that contains just enough to run as a VM. It boots directly from the provided `qcow2` image and does not need to be installed. A handful of configuration steps in the first-run wizard and you're good to go! You have your openSUSE Leap VM up and running in under 5 minutes. +JeOS can be downloaded from https://get.opensuse.org/leap in Alternative Downloads". Download the KVM and XEN image, import it into your `virt-manager` and we're ready to go. + +### JeOS VM: Step-by-step guide Back in our `jellyfish` directory, we first download the VM image (which is also our hard disk) - $ wget -O jellyfish.cow2 https://download.opensuse.org/distribution/leap/15.2/appliances/openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2 + $ wget -O jeos-openSUSE-Leap-15_4.qcow2 https://download.opensuse.org/distribution/leap/15.4/appliances/openSUSE-Leap-15.4-JeOS.x86_64-kvm-and-xen.qcow2 + +Create a `qcow2` overlay, so that multiple machines could in principle use the same `qcow2` image as base and we only store the overlay in a separate image file: + + qemu-img create -b jeos-openSUSE-Leap-15_4.qcow2 -f qcow2 -F qcow2 jellyfish.qcow2 30G Then we run `virt-install` to setup and run our `jellyfish` server: - $ virt-install --name=jellyfish --file=$PWD/jellyfish.qcow2 --vcpus=2 --ram=2048 --os-type=linux --os-variant=opensuse15.2 --boot hd + $ virt-install --name=jellyfish --file=$PWD/jellyfish.qcow2 --vcpus=2 --ram=2048 --os-variant=opensuse15.4 --boot hd -After a handful of configuration steps, you have a functional system in just some minutes +After a handful of configuration steps, you have a functional system in just some minutes. -![Jellyfish setup](/img/jellyfish-jeos.gif) +![Jellyfish setup](jellyfish-jeos.gif) -Now, you have to ensure, you have root ssh access to `jellyfish`. For that, first log in, then find out the ip address using `ip address` (or `ip a` in short): +As you can see in this gif, it only took me 1:30 minutes to get a functional openSUSE Leap 15.4 system using the JeOS image. + +### Provide ssh access for ansible + +Ansible requies ssh access to the machines it is expected to provision. In this example we will assign the `jellyfish` hostname to the VM IP address via `/etc/hosts`. In a more mature environment you might need to update the DHCP server but that's outside of the scope of this tutorial. + +First we need to find out the IP address of the VM. For that, we log in via the `virt-manager` console, then run `ip address` (or `ip a` in short) to list the currently assigned IP addresses. See the `192.168.122.116` in the output below: # ip a 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 @@ -107,14 +149,9 @@ Now, you have to ensure, you have root ssh access to `jellyfish`. For that, firs inet6 fe80::5054:ff:fe85:f7a/64 scope link valid_lft forever preferred_lft forever -Then on your host system, do - ssh-copy-id root@jellyfish - -Done. Now it's a good time to create a VM snapshot, in case you want to have a fresh system. - -Also, add the IP address to `/etc/hosts` otherwise you will need to replace `jellyfish` by the ip address in all following commands. -Add the last line `192.168.122.116 jellyfish` to your `/etc/hosts` file. +Now, as root on your local machine, add the IP address to `/etc/hosts` otherwise you will need to replace `jellyfish` by the ip address in all following commands. +We have been adding the last line `192.168.122.116 jellyfish` to your `/etc/hosts` file. vim /etc/hosts @@ -136,17 +173,25 @@ Add the last line `192.168.122.116 jellyfish` to your `/etc/hosts` file. ::1 hotdog [...] + # This is what we add here to assign an IP our amazing jellyfish VM 192.168.122.116 jellyfish -Remember to remove this line afterwards, in case you don't want to keep your `jellyfish` :-) + +Now let's copy the ssh-key from your host via + + ssh-copy-id root@jellyfish + +Done. Check if you can login via `ssh root@jellyfish`. Now would be a good time to power off your VM and create a VM snapshot, so in case something goes wrong in the next step you have your "saved game" slot you can always rollback to. + +Remember to remove the `jellyfish` from `/etc/hosts` afterwards, in case you don't want to keep your `jellyfish` :-) ## Running the playbook -First ensure, that you have root access to `jellyfish` +First ensure (one more time), that you have root access to `jellyfish` ssh root@jellyfish -Back in our `jellyfish` directory, we need to get the roles and the playbook. Let's say +Back in our `jellyfish` directory, we need to get the roles and the playbook: # Download the ansible repositories git clone https://github.com/GeekOops/geekoops-nginx @@ -154,16 +199,28 @@ Back in our `jellyfish` directory, we need to get the roles and the playbook. Le # Download playbook curl -o jellyfish.yml https://geekoops.github.io/posts/20210326-example-webserver/jellyfish.yml - + +Next we need to create an [inventory](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html). And inventory is a list of hosts or host groups that belongs to a certain deployment. In our basic setup we only hold the `jellyfish` host, but you can see this really as an inventory of all servers that you would manage via ansible. Let's stay simple here: + # Create inventory echo "jellyfish" > inventory -Now let's run the playbook. `ansible` will then install all packages and configure `nginx` for you +We now have all ingredients that we need. We have the playbook, we have the roles and we have the inventory. So from here nothing is holding us back, let's fire `ansible` up and run the playbook using `ansible-playbook`: - ansible-playbook -i inventory jellyfish.yml + ansible-playbook -i inventory jellyfish.yml # Use the custom inventory instead of the default (/etc/ansible) + +Go grab something to drink and let `ansible` sparkle it's magical fairy dust. When you return the playbook has hopefully setup your machines to the desired state: + +![ansible running](jellyfish-running.gif) + +What you hope for is to see something like the following after about 1-2 minutes of ansible running: + +![Screenshot of ansible completing its task](jellyfish-completed.png) + +The `ok=22 changed=17 failed=0` tells you that ansible was successful. Now in your browser navigate to [http://jellyfish/phpinfo.php](http://jellyfish/phpinfo.php) and you should see, the output of phpinfo: -![Output of phpinfo in webbrowser](/img/jellyfish-phpinfo.png) +![Output of phpinfo in webbrowser](jellyfish-phpinfo.png) Congratulations. You have successfully deployed a `nginx` + `php-fpm` webserver instance. Time to celebrate! \ No newline at end of file diff --git a/content/posts/20210326-example-webserver/jellyfish-completed.png b/content/posts/20210326-example-webserver/jellyfish-completed.png new file mode 100644 index 0000000..f4b9a82 Binary files /dev/null and b/content/posts/20210326-example-webserver/jellyfish-completed.png differ diff --git a/content/posts/20210326-example-webserver/jellyfish-jeos.gif b/content/posts/20210326-example-webserver/jellyfish-jeos.gif new file mode 100644 index 0000000..3f61996 Binary files /dev/null and b/content/posts/20210326-example-webserver/jellyfish-jeos.gif differ diff --git a/content/posts/20210326-example-webserver/jellyfish-phpinfo.png b/content/posts/20210326-example-webserver/jellyfish-phpinfo.png new file mode 100644 index 0000000..b54b169 Binary files /dev/null and b/content/posts/20210326-example-webserver/jellyfish-phpinfo.png differ diff --git a/content/posts/20210326-example-webserver/jellyfish-running.gif b/content/posts/20210326-example-webserver/jellyfish-running.gif new file mode 100644 index 0000000..0582676 Binary files /dev/null and b/content/posts/20210326-example-webserver/jellyfish-running.gif differ diff --git a/content/posts/20210326-example-webserver/jellyfish.yml b/content/posts/20210326-example-webserver/jellyfish.yml index 98bef17..4d9bc7f 100644 --- a/content/posts/20210326-example-webserver/jellyfish.yml +++ b/content/posts/20210326-example-webserver/jellyfish.yml @@ -27,7 +27,7 @@ try_files $uri $uri/ =404; } location ~ \.php$ { - fastcgi_pass unix:/var/run/php-fpm.sock; + fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; @@ -38,10 +38,10 @@ owner: "root" mode: 0754 notify: Restart nginx - - name: Ensure nginx has access to php + - name: Ensure nginx is in the www group user: name: nginx - group: www + groups: www append: yes notify: Restart nginx - name: Deploy phpinfo script @@ -51,6 +51,16 @@ group: "www" owner: "wwwrun" mode: 0754 +# Note: The current php-fpm apparmor profile does not allow access to /srv/www. +# We set app-armor to complain in this role. Note that you should use e.g. +# `yast apparmor` to update your AppArmor profile instead of disabling AppArmor +# as a whole! + - name: Ensure aa-complain is installed + package: + name: apparmor-utils + state: present + - name: Put app-armor to complain mode + shell: aa-complain /etc/apparmor.d/php-fpm handlers: - name: Restart nginx diff --git a/content/posts/20210326-php-fpm.md b/content/posts/20210326-php-fpm.md index 43998dc..452250f 100644 --- a/content/posts/20210326-php-fpm.md +++ b/content/posts/20210326-php-fpm.md @@ -9,7 +9,7 @@ This role works with openSUSE Leap and is intended to ship enough requirements f ## Role Variables -This ansible role comes with a minimal set of configuration parameters. +This ansible role comes with a large set of [configuration parameters](https://github.com/GeekOops/geekoops-php-fpm#role-variables). Among others here are some of the most important ones: | Value | Description | Default | diff --git a/static/img/jellyfish-jeos.gif b/static/img/jellyfish-jeos.gif deleted file mode 100644 index ccde5bd..0000000 Binary files a/static/img/jellyfish-jeos.gif and /dev/null differ diff --git a/static/img/jellyfish-phpinfo.png b/static/img/jellyfish-phpinfo.png deleted file mode 100644 index 0dc89e2..0000000 Binary files a/static/img/jellyfish-phpinfo.png and /dev/null differ