FastAPI firmware file server with upload UI and syslog receiver
Project description
FWServe
A FastAPI-based firmware file server that automatically serves .bin files from a configured directory, with a web upload UI and integrated syslog receiver.
Features
- Automatic detection of new
.binfiles - RESTful API for listing and downloading files
- Web UI for uploading
.binfiles - Integrated syslog server (UDP + TCP)
- Real-time syslog viewer with filtering
- CLI for easy installation as a systemd service
- Runs as a Linux systemd service with dedicated user
Installation
From PyPI (Recommended)
# Install using pipx (recommended for CLI tools)
pipx install fwserve
# Or install using pip
pip install fwserve
From Source
# Clone the repository
git clone https://github.com/liptonj/workflows2025.git
cd workflows2025/fwserve
# Install with pip
pip install .
# Or install with development dependencies
pip install -e ".[dev]"
Quick Start
Run in Development Mode
# Run with default settings (port 8080, current directory)
fwserve run
# Run with custom settings
fwserve run --port 8080 --directory /path/to/files --reload
Install as a Production Service (Linux)
The install command sets up everything needed to run fwserve as a systemd service:
- Creates a dedicated
fwserveuser and group - Creates
/opt/fwservedirectory structure - Creates a Python virtual environment with fwserve installed
- Installs and configures the systemd service
# Install with default settings (requires root)
# Uses port 80 for HTTP and port 514 for syslog (standard syslog port)
sudo ~/.local/bin/fwserve install
# Install with custom settings
sudo ~/.local/bin/fwserve install --port 8080 --syslog-port 1514
# Start the service
sudo systemctl start fwserve
# Enable on boot
sudo systemctl enable fwserve
# Check service status
fwserve status
Upgrading
To upgrade an existing installation:
# Upgrade the CLI tool
pipx upgrade fwserve
# Reinstall the service (preserves data in files/ and logs/)
sudo ~/.local/bin/fwserve install --force
# Restart the service
sudo systemctl restart fwserve
Uninstalling
# Uninstall the systemd service
sudo fwserve uninstall
# Optionally remove the data directory
sudo rm -rf /opt/fwserve
Directory Structure After Install
/opt/fwserve/
├── venv/ # Python virtual environment with fwserve
├── files/ # Directory for .bin files (served/uploaded)
└── logs/
└── syslog.log # Persisted syslog messages
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Landing page with links to all features |
/health |
GET | Health check |
/files |
GET | List available .bin files |
/files/{filename} |
GET | Download a specific file |
/upload |
GET | Upload form UI |
/upload |
POST | Upload a .bin file |
/syslog |
GET | Real-time syslog viewer UI |
/syslog/history |
GET | Get recent syslog entries |
/syslog/stream |
GET | SSE stream of syslog entries |
CLI Commands
# Show help
fwserve --help
# Run the server (development)
fwserve run --host 0.0.0.0 --port 8080 --directory ./files
# Install as systemd service (requires root)
sudo fwserve install --port 80 --syslog-port 1514
# Check service status
fwserve status
# Uninstall service (requires root)
sudo fwserve uninstall
Install Command Options
| Option | Default | Description |
|---|---|---|
--install-dir |
/opt/fwserve |
Installation directory |
--user |
fwserve |
Service user |
--group |
fwserve |
Service group |
--port |
80 |
HTTP port |
--syslog-port |
514 |
Syslog UDP/TCP port (standard) |
--no-service |
false |
Skip systemd service installation |
--force |
false |
Force reinstall without prompts |
Configuration
Configuration is done via environment variables (set in the systemd service file):
Server Settings
| Variable | Default | Description |
|---|---|---|
FWSERVE_HOST |
0.0.0.0 |
Host to bind to |
FWSERVE_PORT |
8080 |
HTTP port to listen on |
FWSERVE_DIRECTORY |
. |
Directory to serve files from |
FWSERVE_LOG_LEVEL |
INFO |
Logging level |
FWSERVE_TIMEZONE |
America/New_York |
Timezone for timestamps |
Upload Settings
| Variable | Default | Description |
|---|---|---|
FWSERVE_UPLOAD_MAX_BYTES |
104857600 |
Maximum upload size (100MB) |
Syslog Settings
| Variable | Default | Description |
|---|---|---|
SYSLOG_ENABLE_UDP |
true |
Enable UDP syslog listener |
SYSLOG_ENABLE_TCP |
true |
Enable TCP syslog listener |
SYSLOG_UDP_PORT |
514 |
UDP port for syslog |
SYSLOG_TCP_PORT |
514 |
TCP port for syslog |
SYSLOG_LOG_FILE |
<directory>/syslog.log |
Path to syslog storage file |
SYSLOG_TAIL_SIZE |
5000 |
Number of entries to keep in memory |
SYSLOG_HISTORY_LIMIT |
500 |
Max entries returned by history endpoint |
Usage Examples
List available files
curl http://localhost/files
Response:
{
"files": ["firmware_v1.0.bin", "update_v2.1.bin"]
}
Download a file
curl -O http://localhost/files/firmware_v1.0.bin
Upload a file
curl -X POST -F "file=@firmware.bin" http://localhost/upload
Send syslog messages
# UDP
echo "<14>Test message from host1" | nc -u localhost 514
# TCP
echo "<14>Test message from host1" | nc localhost 514
View syslog messages
Open http://localhost/syslog in a browser for the real-time viewer, or use the API:
# Get all entries
curl http://localhost/syslog/history
# Filter by host
curl "http://localhost/syslog/history?host=router1"
# Filter by severity and message
curl "http://localhost/syslog/history?severity=err&q=failed"
Service Management
After installing with fwserve install:
# Start service
sudo systemctl start fwserve
# Stop service
sudo systemctl stop fwserve
# Restart service
sudo systemctl restart fwserve
# View status
sudo systemctl status fwserve
# View logs
sudo journalctl -u fwserve -f
Migration from Legacy Installation
If you previously installed using the old install.sh script, running fwserve install will:
- Detect the legacy installation
- Prompt for migration (or use
--forceto skip) - Remove old Python files (main.py, config.py, etc.)
- Preserve your data directories (
files/andlogs/) - Install the new venv-based setup
Security Notes
- Only
.binfiles are served/uploaded - Path traversal attacks are blocked
- Service runs as dedicated non-root user (
fwserve) - Systemd security hardening is enabled (ProtectSystem, PrivateTmp, etc.)
- Files directory has restricted write access
Troubleshooting
Service fails to start
Check the logs:
sudo journalctl -u fwserve -n 50
Permission denied errors
Ensure the fwserve user owns the directories:
sudo chown -R fwserve:fwserve /opt/fwserve/files /opt/fwserve/logs
Port already in use
Check what's using the port:
sudo ss -tlnp | grep :80
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run type checking
mypy src/fwserve/
# Run linter
ruff check src/
# Format code
ruff format src/
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fwserve-1.0.9.tar.gz.
File metadata
- Download URL: fwserve-1.0.9.tar.gz
- Upload date:
- Size: 24.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8dc8a632e1e7909113c5923fedd1b63ca70694047e22fd0185691f936e8627d5
|
|
| MD5 |
4e77d37856e2514fd3526c2047cb1a5c
|
|
| BLAKE2b-256 |
ada7d00740c374f41497ca03ef713d718f90a12592295888127b211219828a06
|
Provenance
The following attestation bundles were made for fwserve-1.0.9.tar.gz:
Publisher:
ci.yml on liptonj/workflows2025
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fwserve-1.0.9.tar.gz -
Subject digest:
8dc8a632e1e7909113c5923fedd1b63ca70694047e22fd0185691f936e8627d5 - Sigstore transparency entry: 845853093
- Sigstore integration time:
-
Permalink:
liptonj/workflows2025@9472e28190f8136046d9bf617e88435cadb201e6 -
Branch / Tag:
refs/tags/v1.0.9 - Owner: https://github.com/liptonj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9472e28190f8136046d9bf617e88435cadb201e6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fwserve-1.0.9-py3-none-any.whl.
File metadata
- Download URL: fwserve-1.0.9-py3-none-any.whl
- Upload date:
- Size: 31.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59ff5e71ab3beadeaa206da6ba8474f5f4ed6da8d071c6d56c416db9fb87eccc
|
|
| MD5 |
da9707bb85f9965b98253d229aa2edb5
|
|
| BLAKE2b-256 |
f2f4e81f6b2eb930b0f0ee5b343a7523a4c9a5ac7bff5a88dc596c50d369c9d2
|
Provenance
The following attestation bundles were made for fwserve-1.0.9-py3-none-any.whl:
Publisher:
ci.yml on liptonj/workflows2025
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fwserve-1.0.9-py3-none-any.whl -
Subject digest:
59ff5e71ab3beadeaa206da6ba8474f5f4ed6da8d071c6d56c416db9fb87eccc - Sigstore transparency entry: 845853098
- Sigstore integration time:
-
Permalink:
liptonj/workflows2025@9472e28190f8136046d9bf617e88435cadb201e6 -
Branch / Tag:
refs/tags/v1.0.9 - Owner: https://github.com/liptonj
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9472e28190f8136046d9bf617e88435cadb201e6 -
Trigger Event:
push
-
Statement type: