aboutsummaryrefslogtreecommitdiff
path: root/content/posts/2022-07-18-firefly-install.md
blob: 6c7a649bac08db3ca19725e47fa156d62a1fdaa1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
---
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=<RANDON_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