Skip to main content

Self-Hosting

This guide covers deploying Gäld on your own server in production. For local development, see Getting Started.

Server Requirements

ComponentMinimum version
PHP8.4
PostgreSQL16
Redis7
MeiliSearchLatest
Nginx (or Caddy)
Node.js (build only)20

A single VPS with 2 vCPU, 2 GB RAM, and 20 GB SSD is sufficient for most small organisations.

MeiliSearch is optional

If MeiliSearch is unavailable, Gäld falls back to database search automatically. Results may be slower and less fuzzy, but the application continues to function.

Docker Installation

The quickest way to run Gäld is with Docker Compose (Laravel Sail):

git clone https://github.com/Scanix/Gaeld.git
cd Gaeld/api
cp .env.example .env
docker compose up -d
docker compose exec laravel.test php artisan key:generate
docker compose exec laravel.test php artisan gaeld:install

This starts the following services:

ServicePort
Gäld (PHP + Nginx)8080
PostgreSQL 165432
Redis 76379
MeiliSearch7700
Mailpit (dev mail)8025

For production Docker deployments, set APP_ENV=production and APP_DEBUG=false in .env and use a reverse proxy with SSL termination in front of the container.

Manual Installation

git clone https://github.com/Scanix/Gaeld.git /var/www/gaeld
cd /var/www/gaeld
composer install --no-dev --optimize-autoloader
npm install && npm run build
cp .env.example .env
php artisan key:generate

Edit .env with your production values (see Environment Variables below).

php artisan gaeld:install

Nginx Configuration

server {
listen 80;
server_name app.example.com;
root /var/www/gaeld/public;
index index.php;

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

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

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

Add an SSL certificate (e.g. via Certbot) and redirect port 80 to 443 before going live.

PHP-FPM Pool

Create or edit /etc/php/8.4/fpm/pool.d/gaeld.conf:

[gaeld]
user = www-data
group = www-data
listen = /run/php/php8.4-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

Restart: systemctl restart php8.4-fpm

Queue Worker (systemd)

Gäld uses Laravel queues for background jobs (bank imports, notifications). Run a persistent worker:

# /etc/systemd/system/gaeld-worker.service
[Unit]
Description=Gäld Queue Worker
After=network.target

[Service]
User=www-data
WorkingDirectory=/var/www/gaeld
ExecStart=/usr/bin/php artisan queue:work --sleep=3 --tries=3 --max-time=3600
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Enable and start:

systemctl enable gaeld-worker
systemctl start gaeld-worker

Scheduled Tasks (cron)

Add to the www-data crontab:

* * * * * /usr/bin/php /var/www/gaeld/artisan schedule:run >> /dev/null 2>&1

File Storage and Permissions

chown -R www-data:www-data /var/www/gaeld/storage /var/www/gaeld/bootstrap/cache
chmod -R 775 /var/www/gaeld/storage /var/www/gaeld/bootstrap/cache

Generated files (invoice PDFs, bank imports) are stored in storage/app/. Mount this on persistent storage if using containers.

Environment Variables

VariableDescriptionExample
APP_ENVEnvironmentproduction
APP_URLPublic URLhttps://app.example.com
APP_DEBUGDebug mode (disable in production)false
DB_HOSTPostgreSQL host127.0.0.1
DB_DATABASEDatabase namegaeld
DB_USERNAMEDB usergaeld
DB_PASSWORDDB password
REDIS_HOSTRedis host127.0.0.1
CACHE_DRIVERCache backendredis
QUEUE_CONNECTIONQueue backendredis
SCOUT_DRIVERSearch drivermeilisearch
MEILISEARCH_HOSTMeiliSearch URLhttp://127.0.0.1:7700
MEILISEARCH_KEYMeiliSearch master keyyour-master-key
MAIL_MAILERMail driversmtp or mailgun
MAIL_FROM_ADDRESSSender addressnoreply@example.com
FEATURE_BANK_SYNCEnable bank importtrue
FEATURE_AUTOMATIONEnable rule enginetrue
FEATURE_API_ACCESSEnable REST APItrue
PLUGINS_ENABLEDEnable plugin systemtrue

Updating

After pulling a new release:

cd /var/www/gaeld
git pull
composer install --no-dev --optimize-autoloader
npm install && npm run build
php artisan gaeld:update
systemctl restart gaeld-worker

gaeld:update runs pending migrations, clears caches, and restarts queues safely.

Backups

Back up:

  1. PostgreSQL database: pg_dump gaeld > gaeld_$(date +%F).sql
  2. Storage directory: storage/app/ (contains generated PDFs and uploads)
  3. .env file: store securely outside the web root

Consider a daily cron job and off-site replication for production environments.