--- title: "Running firefly3 on alpine" date: 2022-07-18 tags: ['alpine', 'linux', 'php', 'nginx'] --- **Disclaimer:** before starting be aware that I'm not a sysadmin nor I have a deep knowledge in security. This is me reporting the steps I did as a learning experiment, so take this tutorial as your own risk. I have a pretty decent knowledge in container technology, I maintain several container on my local server for many applications. However I've decided to take a step back and learn a bit more how those applications are really deployed and kept without containers, and first candidate being Firefly[^1]. I have it currently running on container but let's install in a distribution. For the distro of choice I'll pick alpine, for its small footprint and the use of OpenRC (nothing against systemd though). *I don't want to extend this tutorial to cover every single part, so for the next steps I'll assume that you have a running instance of PostgreSQL and Alpine.* ## Dependencies First we need to install all the necessary packages to get firefly running. Let's go through them and check are they are used for. ```shell apk add curl tar gzip ``` cURL is needed to download the source code from Github and tar gzip are for extracting the compressed code. ```shell apk add composer ``` Composer is a dependency manager for PHP. It is required to download the dependencies of the project. Now we need to download the list of dependencies list in the site[^2]. ``` Extra packages Install the following PHP modules: PHP BCMath Arbitrary Precision Mathematics PHP Internationalization extension PHP Curl PHP Zip PHP Sodium PHP GD PHP XML PHP MBString PHP whatever database you're gonna use. ``` For those we have the following alpine packages: ```shell apk add \ php8 \ php8-curl \ php8-zip \ php8-sodium \ php8-gd \ php8-xml \ php8-mbstring \ php8-bcmath \ php8-pgsql ``` But that is not everything, I don't know if I lack knowledge in the PHP stack but the application will later complain about a lot of missing dependencies, those being: ```shell apk add \ php8-fileinfo \ php8-intl \ php8-session \ php8-simplexml \ php8-tokenizer \ php8-xmlwriter \ php8-dom \ php8-pdo_pgsql \ php8-shmop ``` A tip that may as well help you later. Some of those not listed packages are described in the their project for the docker image[^3] and its base image[^4]. It can also help with describing the necessary steps. As the next step we need to install the pieces of software that will actually run the project: ```shell apk add nginx php8-fpm ``` Nginx will act as reverse proxy and php8-fpm will actually run the project. You can use lighttpd as well as some others. ## Deploying the code Now we have all necessary packages, lets download the project into on server, grab the latest release from Github, at the time of this writing is `5.7.9`. Download into the `/var/www/firefly`. The folder location is kinda up you, I think nginx itself has another default folder for its sites, but I always use www folder to store the projects. ```shell mkdir -p /var/www/firefly ``` Create the folder then download/extract the source code: ```shell curl -SL https://github.com/firefly-iii/firefly-iii/archive/refs/tags/5.7.9.tar.gz | \ tar zxC /var/www/firefly --strip-components 1 ``` This piece of code was taken from the dockerfile[^5]. Now move to the `/var/www/firefly` and install its dependencies with composer: ```shell cd /var/www/firefly composer install --prefer-dist --no-dev --no-scripts ``` ## Config files ### Firefly Firefly makes the process of setting up the connection strings and other configuration quite easy. We'll only need to create an `.env` file with all the information needed. Fill the information according with your setup: ```ini # /var/wwww/firefly/.env DB_CONNECTION=pgsql DB_HOST=localhost DB_PORT=5432 DB_DATABASE=firefly DB_USERNAME=admin DB_PASSWORD=admin APP_KEY= ``` To generate a random key just run: ```shell head /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32 && echo ``` Once you have set it up we need to bootstrap the project: ```shell php artisan config:cache ``` To update the cached configuration. If everything is setup properly the process finish successfully. ```shell php artisan firefly-iii:create-database php artisan migrate:refresh --seed php artisan firefly-iii:upgrade-database ``` To bootstrap the database. ### Permission Now comes the part where we should be careful. So far we (or at least I) have been setting up everything as root but that is not ideal. We want to restrict as much as possibly permission to the processes, it should only see do what it meant to. So to minimize the effect of the process we will make it run as a user with almost no permission, and for purpose we will create a `www-data` user. Quite often that user is already create if not run the following command: ```shell adduser www-data --disabled-password ``` Add `--ingroup www-data` if it complains if the groups exists. `--disabled-password` so we don't allow login with password, because it is not meant to be logged with. Once the user is created we need to change the which user the process runs one. By default it uses a `nobody` which is a user with no permission except those which every other user has. Update the user given in the `/etc/php8/php-fpm.d/www.conf` file. From: ```shell user = nobody group = nobody ``` To: ```shell user = www-data group = www-data ``` If the `php-fpm8` is running restart it: ```shell rc-service php-fpm8 restart ``` At last we need to recursively update the permission of www folder because probably it is owned by root. ```shell chown -R www-data:www-data /var/www/ ``` ### Nginx We will need to edit the nginx config file to find and run the project, add the following server inside of `/etc/nginx/http.d/`, by default nginx will read all `.config` inside of that folder. Just like the www folder this is more a personal choice, you have some room to choose where you want to config this server. ```shell # /etc/nginx/http.d/firefly.conf server { listen 8080; server_name localhost; root /var/www/firefly/public; location ~ \.php$ { try_files $uri $uri/ =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass 127.0.0.1:9000; include fastcgi.conf; } location / { try_files $uri /index.php$is_args$args; } } ``` This will set up the process in the port 8080. It is just an exemple, adapt it to your needs. ### Services Now that we have everything set up we can start the service to serve firefly: ```shell rc-service php-fpm8 start rc-service nginx start ``` `http://localhot:8080/` (or your server's hostname) should be up and running. And to make autostart: ```shell rc-update add php-fpm8 default rc-update add nginx default ``` ## Debugging In case of error you can add debugging setting to your env file so it will nicely return the error. ```ini # /var/wwww/firefly/.env # ... APP_DEBUG=true APP_LOG_LEVEL=debug ``` [^1]: https://www.firefly-iii.org/ [^2]: https://docs.firefly-iii.org/firefly-iii/installation/self_hosted/?mtm_campaign=docu-internal&mtm_kwd=self_hosted [^3]: https://dev.azure.com/Firefly-III/_git/MainImage [^4]: https://dev.azure.com/firefly-iii/_git/BaseImage [^5]: https://dev.azure.com/Firefly-III/MainImage/_git/MainImage?path=/Dockerfile&version=GC520b8f865ea623a8625fe64e9f583406849be91a&line=14&lineEnd=15&lineStartColumn=1&lineEndColumn=1&lineStyle=plain&_a=contents