Self-Hosting
This guide covers deploying Gäld on your own server in production. For local development, see Getting Started.
Server Requirements
| Component | Minimum version |
|---|---|
| PHP | 8.4 |
| PostgreSQL | 16 |
| Redis | 7 |
| MeiliSearch | Latest |
| 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.
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:
| Service | Port |
|---|---|
| Gäld (PHP + Nginx) | 8080 |
| PostgreSQL 16 | 5432 |
| Redis 7 | 6379 |
| MeiliSearch | 7700 |
| 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
| Variable | Description | Example |
|---|---|---|
APP_ENV | Environment | production |
APP_URL | Public URL | https://app.example.com |
APP_DEBUG | Debug mode (disable in production) | false |
DB_HOST | PostgreSQL host | 127.0.0.1 |
DB_DATABASE | Database name | gaeld |
DB_USERNAME | DB user | gaeld |
DB_PASSWORD | DB password | … |
REDIS_HOST | Redis host | 127.0.0.1 |
CACHE_DRIVER | Cache backend | redis |
QUEUE_CONNECTION | Queue backend | redis |
SCOUT_DRIVER | Search driver | meilisearch |
MEILISEARCH_HOST | MeiliSearch URL | http://127.0.0.1:7700 |
MEILISEARCH_KEY | MeiliSearch master key | your-master-key |
MAIL_MAILER | Mail driver | smtp or mailgun |
MAIL_FROM_ADDRESS | Sender address | noreply@example.com |
FEATURE_BANK_SYNC | Enable bank import | true |
FEATURE_AUTOMATION | Enable rule engine | true |
FEATURE_API_ACCESS | Enable REST API | true |
PLUGINS_ENABLED | Enable plugin system | true |
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:
- PostgreSQL database:
pg_dump gaeld > gaeld_$(date +%F).sql - Storage directory:
storage/app/(contains generated PDFs and uploads) .envfile: store securely outside the web root
Consider a daily cron job and off-site replication for production environments.