Backend API server for Fulgur, a multiplatform text editor. Enables file synchronization between devices with end-to-end encryption. Self-hostable to keep user data private.
Despite already having all the needed features to be perfectly effective together with Fulgur, this server is still in active development and is not yet recommended for production. There's still some work to be done (which may imply breaking changes), and more testing, for Fulgurant to be given the green light for production with a direct, public access. If you want to test Fulgurant, please run it in a private environment not facing the wild internet yet.
The main dashboard (for all users): allows to manage the user's devices and ongoing shares, refresh the API keys' validity.
The Admin dashboard (for Admin users only): allows to manage the users (edit the role, deletion).
- User authentication with email verification
- Device management and API key generation
- End-to-end encrypted file sharing (AES-256-GCM)
- Automatic share expiration and cleanup
- Admin and User type accounts
- Web interface for profile, shares and device management
- Web interface for Admin users for user management
- SQLite and PostgreSQL database support
- REST API for desktop app integration
- SSE support for notifying a Fulgur instance of available shares
- More polished Admin interface (accounts creation/edition,...)
- Docker image
- Rust 1.90 or later
Build the project:
cargo build --releaseRun the server:
cargo runThe server starts by default on http://127.0.0.1:3000 (see Optional settings to change this behaviour)
Run tests:
cargo testCreate a .env file in the project root. Use .env.example as a starting point.
Fulgurant uses:
- Device key (
fulgur_...) only forPOST /api/token - JWT access token for all other
/api/*calls
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
No | sqlite:data/database.db |
Database connection string. SQLite: sqlite:data/database.db. PostgreSQL: postgresql://user:pass@host:5432/db |
JWT_SECRET |
Yes | - | JWT signing secret (minimum 32 characters) |
JWT_EXPIRY_SECONDS |
No | 900 |
JWT access token lifetime in seconds (60-86400) |
IS_PROD |
No | true |
Enables production mode (SMTP required when true) |
CAN_REGISTER |
No | false |
Enable public self-registration |
SHARE_VALIDITY_DAYS |
No | 3 |
Share expiry in days (1-30) |
MAX_DEVICES_PER_USER |
No | 99 |
Max devices per user (0-10000) |
SSE_HEARTBEAT_SECONDS |
No | 30 |
SSE heartbeat interval in seconds (5-300) |
BIND_HOST |
No | 127.0.0.1 |
Bind address (0.0.0.0 for external access) |
BIND_PORT |
No | 3000 |
Bind port |
RUST_LOG |
No | debug (dev), info (prod) |
Log filter |
LOG_FOLDER |
No | logs |
Log directory |
DAILY_DATABASE_BACKUP |
No | false |
Enable daily SQLite backup task |
BACKUP_FOLDER |
No | backups |
Backup output directory |
SMTP_HOST |
Yes if IS_PROD=true |
- | SMTP host |
SMTP_LOGIN |
Yes if IS_PROD=true |
- | SMTP username/login |
SMTP_PASSWORD |
Yes if IS_PROD=true |
- | SMTP password |
SMTP_PORT |
No | 587 |
SMTP port |
DATABASE_URL=sqlite:./data/fulgurant.db
JWT_SECRET='replace_with_at_least_32_characters'
IS_PROD=true
CAN_REGISTER=true-
Download docker-compose.yml
-
Edit docker-compose.yml with your configuration:
environment: - SMTP_HOST=your-smtp-server.com - SMTP_LOGIN=your-email@example.com - SMTP_PASSWORD=your-password - CAN_REGISTER=false # Set to true to allow user registration
-
Create the data directory:
mkdir -p data
-
Start the container:
docker-compose up -d
-
Create the first admin user:
- Navigate to
http://localhost:3000/setup - Follow the setup wizard
- Navigate to
-
View logs:
docker-compose logs -f fulgurant
| Variable | Description | Example |
|---|---|---|
SMTP_HOST |
SMTP server hostname | smtp.mail.ovh.net |
SMTP_PORT |
SMTP server port | 587 |
SMTP_LOGIN |
SMTP username | mail@example.com |
SMTP_PASSWORD |
SMTP password | your_password |
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite:data/database.db |
Database connection string (SQLite or PostgreSQL) |
BIND_HOST |
0.0.0.0 |
Bind address (0.0.0.0 for all interfaces) |
BIND_PORT |
3000 |
Port to listen on |
IS_PROD |
true |
Production mode (true/false) |
CAN_REGISTER |
false |
Allow user registration |
MAX_DEVICES_PER_USER |
99 |
Maximum devices per user |
SHARE_VALIDITY_DAYS |
3 |
Days until shares expire |
SSE_HEARTBEAT_SECONDS |
30 |
SSE keep-alive interval |
RUST_LOG |
debug |
Log level (trace, debug, info, warn, error) |
LOG_FOLDER |
logs |
Log file directory |
PUID |
1000 |
User ID for file permissions |
PGID |
1000 |
Group ID for file permissions |
SQLite requires no external setup. Set DATABASE_URL=sqlite:data/database.db (or omit for the default).
PostgreSQL is auto-detected when DATABASE_URL starts with postgres:// or postgresql://. No migration from SQLite is supported — PostgreSQL is intended for new deployments.
Local development with Docker:
docker compose -f docker-compose.pg.yml up -dThen set in .env:
DATABASE_URL=postgresql://fulgurant:fulgurant@localhost:5432/fulgurantNotes:
- Built-in database backup (
DAILY_DATABASE_BACKUP) is SQLite only. For PostgreSQL, usepg_dump. - All timestamps are stored as Unix epoch integers (
BIGINT) in both backends for consistency.
Migrations run automatically on server startup.
- SQLite migration files:
data/migrations/ - PostgreSQL migration files:
data/migrations_postgres/
The server runs the following background tasks:
- Share cleanup: Runs every hour, removes expired shares
- Verification code cleanup: Runs every minute, removes expired verification codes
- Database backup: Runs every 24 hours when enabled via
DAILY_DATABASE_BACKUP=true, creates timestamped backup files using SQLite's VACUUM INTO command (SQLite only)
Development mode (IS_PROD=false):
- Verification codes printed to console instead of emailed
- Useful for testing without SMTP configuration
Production mode (IS_PROD=true):
- Emails sent via SMTP (requires email settings)
- Secure session cookies (expects HTTPS via reverse proxy)
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

