Librarian

Other Deployment Options

Since version 4, Librarian is a static site builder, which means you don't need a web server with PHP installed in order to host your site - you only need PHP to build it.

However, the legacy way of serving pages with Librarian is still possible if your site relies on dynamic functionalities.

Deploying Librarian with Nginx + PHP-FPM

To deploy Librarian with Nginx, you'll need to also install PHP-FPM on the server (MySQL not needed!). Check out this LEMP tutorial for details on how to get these installed - you can skip the MySQL step(s).

This is an example of functional Nginx configuration to host a Librarian website with PHP-FPM (PHP 7.4):

server {
    listen 80;
    server_name domain_name www.domain_name;
    root /var/www/librarian-website;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Deploying Librarian with Ansible

Because Librarian uses a relatively simple stack, and is a stateless application, automating its deployment with a tool like Ansible is not very difficult.

We've created an Ansible example setup that you can copy to set up your application within a remote production environment with Nginx + PHP-FPM. The setup included in that repository is the same used by the Librarian documentation (which is a Librarian app) for setting up the remote server and deploying the application to production with Nginx + PHP-FPM.

For more information about Ansible, you can check this reference guide.

Downloading the Files

You can download the files in this repository and save them in the root folder of your Librarian application.

cd ~/my-librarian-app
curl -LO https://github.com/librarianphp/librarian-ansible/archive/refs/tags/0.1.zip
unzip 0.1.zip

This will extract the Ansible files to a folder named librarian-ansible-0.1 in your application directory. You can rename this to ansible:

mv librarian-ansible-0.1 ansible

To avoid issues with rsync when uploading the application files to the remote servers, ideally the deploy.yml playbook should be located at the root of your application. The other Ansible files can stay where they are.

mv ansible/deploy.yml .

You may want to include the inventory file and the group_vars/all.yml in your project's .gitignore at your own discretion, but overall you should want to keep the provisioning scripts in version control to take full advantage of Ansible's infrastructure as code capabilities.

Setting Up Inventory

You'll need to edit the inventory file and replace the example IP address with your own server's IP address.

[dev]
librarian ansible_host=192.168.10.10

[all:vars]
ansible_python_interpreter=/usr/bin/python3

After saving and closing the file, you can test out your connection with a ping command:

ansible all -i inventory -m ping -u root

Setting Up Required Variables

Both playbooks use variables defined within group_vars/all.yml. There are two important variables that need to be changed here:

  • http_host - The domain name or IP address for your Librarian website, this will be used to configure Nginx.
  • app_root_dir - For the rsync command to work without issues, you need to set the application directory name here.

You may also want to change the remote_system_user. This user will be created on the server as a passwordless sudo user that you'll then use to run the deploy playbook to deploy your application whenever you want to. That is important for the rsync module to work without issues.

# group_vars/all.yml
---
# Initial Server Setup
remote_system_user: librarian
sys_packages: [ 'curl', 'vim', 'git', 'ufw', 'acl', 'imagemagick', 'curl']

# PHP
php_packages: [ "php-imagick", "php-curl", "php-json", "php-mbstring", "php-bcmath", "php-xml" ]

# Web Server Setup
http_host: librarianphp.dev
remote_www_root: /var/www
app_root_dir: librarian
document_root: "{{ remote_www_root }}/{{ app_root_dir }}/web"

Running the Server Setup

The server-setup.yml includes roles to set up an Nginx + PHP-FPM server.

The server-setup.yml playbook can be used on a fresh Ubuntu server to set up all requirements including Composer.

# server-setup.yml
---
- hosts: all
  become: true
  roles:
    - { role: setup, tags: ['setup'] }

    - { role: php, tags: ['php', 'web', 'php-fpm'] }

    - { role: nginx, tags: ['nginx', 'web', 'http'] }

    - { role: composer, tags: ['composer'] }

You can run this playbook with:

ansible-playbook -i inventory server-setup.yml -u root

Running the Deploy Playbook

The deploy.yml playbook will make sure the remote document root exists, and will rsync the current folder (.) with the remote server.

It will then try to execute composer install on the application's root folder.

---
- hosts: all
  become: true
  vars_files:
    - ansible/group_vars/all.yml
  tasks:
    - name: Make sure the remote app root exists and has the right permissions
      file:
        path: "{{ remote_www_root }}/{{ app_root_dir }}"
        state: directory
        mode: '0755'
        owner: "{{ remote_system_user }}"
        group: "{{ remote_system_user }}"

    - name: Rsync application files to the remote server
      synchronize:
        src: "."
        dest: "{{ remote_www_root }}"
        rsync_opts:
          - "--no-motd"
          - "--exclude=.git"
          - "--exclude=.github"
          - "--exclude=ansible"
          - "--exclude=docker-compose*"
          - "--exclude=Dockerfile"
          - "--exclude=vendor"
      tags: [ 'sync' ]

    - name: Set up additional directory permissions for www-data user on storage folder
      acl:
        path: "{{ remote_www_root }}/{{ app_root_dir }}/var/"
        entry: group:www-data:rwX
        recursive: yes
        state: present

    - name: Install Dependencies with Composer
      become: false
      composer:
        command: install
        working_dir: "{{ remote_www_root }}/{{ app_root_dir }}"
      tags: [ 'composer' ]

Considering you have previously run the server-setup.yml playbook and has a passwordless sudo created and named librarian, you can run the deploy playbook with:

ansible-playbook -i inventory deploy.yml -u librarian

Only Syncing Files

If all you want to do is synchronize the app files (upload changes), then you can run:

ansible-playbook -i inventory deploy.yml -u librarian --tags=sync

Running only Composer

If you just want to run a composer install on the app's folder, you can run the deploy playbook like this:

ansible-playbook -i inventory deploy.yml -u librarian --tags=composer

Built with Librarian by @erikaheidi.

Back to top