Getting started¶
Userli is a Symfony-based web application for self-managing email users with mailbox encryption support (Dovecot). It is built with PHP, Symfony, Doctrine ORM, and uses TailwindCSS with Symfony UX on the frontend.
We provide a docker-compose.yml that starts Userli with MariaDB, Dovecot, Roundcube, Mailcatcher, Redis, and a webhook tester to set up a complete development environment.
Warning
This setup is meant for local development only. Do not use it in production. See the Operations Guide for production installations.
| Service | URL | Purpose |
|---|---|---|
| Userli | http://localhost:8000 | Main application |
| Roundcube | http://localhost:8001 | Webmail client |
| Mailcatcher | http://localhost:1080 | Catches all outgoing emails |
| Webhook test | http://localhost:9000 | Webhook endpoint testing |
Requirements¶
podman(ordocker) with compose supportyarncomposermake
Info
If you don't have Podman or Docker installed, see the Podman or Docker installation instructions.
Setup¶
For first-time setup, run:
make dev
This will:
- Install PHP dependencies and build frontend assets (
make assets) - Start all containers (MariaDB, Redis, Caddy, Userli, worker, scheduler, Mailcatcher, webhook tester)
- Wait for MariaDB to be ready
- Run database migrations
The Makefile auto-detects whether you have Podman or Docker installed.
Load fixtures¶
To populate the environment with example data, run
make fixtures
This
- loads sample data (users, domains, API tokens, ...) and
- starts Dovecot and Roundcube (
mailprofile).
When it finishes, open http://localhost:8000 and log in with admin@example.org / password.
Info
The fixtures create user accounts (admin, user, support and suspicious, among others) on the domain example.org, all with the password password.
They also create sample aliases and vouchers.
See src/DataFixtures for details.
Info
Dovecot and Roundcube are in the mail profile and must be started after the fixtures are loaded in the database, otherwise Dovecot will fail because the API token it is configured to use will not exists in the database. make fixtures handles both in the right order.
Tip
Run make without arguments to see all available targets.
Next steps¶
- Get to know the code: Architecture
- Read the contribution guidelines
- Run the tests
-
Watch the frontend while you work:
yarn watch
Background services¶
The development environment runs three containers for the Userli application:
| Container | Purpose |
|---|---|
userli |
PHP-FPM, served by the caddy container |
userli-worker |
Async message consumer (messenger:consume async) |
userli-scheduler |
Scheduled tasks (messenger:consume scheduler_maintenance) |
The worker processes async messages (e.g. email sending, webhook delivery).
The scheduler runs recurring maintenance tasks defined in src/Schedule/.
Logs¶
Userli uses Monolog for logging, configured in config/packages/monolog.yaml.
Logs are JSON-formatted.
In development, logs are written to var/log/dev.log:
tail -f var/log/dev.log | jq
To inspect container logs:
podman compose logs -f userli
docker compose logs -f userli
Troubleshooting¶
On systems with SELinux enabled, the webserver might throw an error due to broken filesystem permissions.
Create a docker-compose.override.yml in the root directory:
---
services:
userli:
security_opt:
- label=disable
dovecot:
security_opt:
- label=disable
roundcube:
security_opt:
- label=disable