# WebDAV Server with aiohttp
A comprehensive, production-ready WebDAV server implementation with full RFC 4918 compliance, Windows Explorer compatibility, and enterprise-grade features.
## Features
### Core WebDAV Protocol
- ✅ **Full RFC 4918 Compliance**: All standard WebDAV methods implemented
- ✅ **Windows Explorer Integration**: Seamless compatibility with Windows WebDAV Mini-Redirector
- ✅ **Multiple Authentication Methods**: Basic, Digest, and Token-based authentication
- ✅ **Resource Locking**: Exclusive and shared locks with timeout management
- ✅ **Custom Properties**: Full property management (PROPFIND/PROPPATCH)
- ✅ **Collection Operations**: MKCOL, COPY, MOVE with depth support
### Enterprise Features
- 🔒 **Multi-User Support**: Isolated user directories with permissions
- 💾 **SQLite Database**: Robust backend for users, locks, and properties
- 🌐 **Web Management Interface**: Admin dashboard and user portal
- 🚀 **High Performance**: Async I/O with aiohttp and aiofiles
- 🔐 **Security Focused**: Input validation, path traversal prevention, SQL injection protection
- 📊 **Monitoring Ready**: Structured logging and metrics collection
- 🐳 **Docker Support**: Container-ready with docker-compose
- 📈 **Production Ready**: Gunicorn integration, health checks, graceful shutdown
## Quick Start
### Prerequisites
- Python 3.8 or higher
- pip (Python package manager)
- Optional: Redis for caching
- Optional: Docker for containerized deployment
### Installation
1. **Clone or create the project directory:**
```bash
mkdir webdav-server
cd webdav-server
```
2. **Install dependencies:**
```bash
pip install -r requirements.txt
```
3. **Configure environment:**
```bash
cp .env.example .env
# Edit .env with your configuration
nano .env
```
4. **Generate a secure secret key:**
```bash
python -c "import secrets; print(secrets.token_hex(32))"
# Copy the output to JWT_SECRET_KEY in .env
```
5. **Run the server:**
```bash
python main.py
```
The server will start on `http://0.0.0.0:8080` by default.
### First Run
On first run, the server automatically creates:
- A default admin user: `admin` / `admin123`
- The WebDAV root directory structure
- SQLite database with all required tables
**⚠️ Important**: Change the default admin password immediately!
## Configuration
### Environment Variables
All configuration is done through the `.env` file. Key settings:
#### Server Configuration
```env
HOST=0.0.0.0 # Listen address
PORT=8080 # Listen port
SSL_ENABLED=false # Enable HTTPS
```
#### Authentication
```env
AUTH_METHODS=basic,digest # Supported auth methods
JWT_SECRET_KEY=... # Secret for sessions (required)
SESSION_TIMEOUT=3600 # Session duration in seconds
```
#### WebDAV Settings
```env
WEBDAV_ROOT=./webdav # Root directory for files
MAX_FILE_SIZE=104857600 # Max file size (100MB)
MAX_PROPFIND_DEPTH=3 # Depth limit for PROPFIND
LOCK_TIMEOUT_DEFAULT=3600 # Default lock timeout
```
See `.env.example` for complete configuration options.
## Usage
### Connecting with Windows Explorer
#### Method 1: Map Network Drive
1. Open File Explorer
2. Right-click "This PC" → "Map network drive"
3. Choose a drive letter
4. Enter the WebDAV URL:
```
http://your-server:8080/
```
5. Check "Connect using different credentials"
6. Enter your username and password
7. Click "Finish"
#### Method 2: Add Network Location
1. Open File Explorer
2. Right-click "This PC" → "Add a network location"
3. Choose "Choose a custom network location"
4. Enter the WebDAV URL:
```
http://your-server:8080/
```
5. Enter credentials when prompted
#### Windows with SSL (Recommended)
For HTTPS connections:
```
https://your-server:8443/
```
**Note**: Windows requires port 443 for HTTPS WebDAV by default. To use other ports, modify Windows registry:
```
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WebClient\Parameters
BasicAuthLevel = 2
```
### Connecting with macOS Finder
1. Open Finder
2. Press `Cmd+K` (Go → Connect to Server)
3. Enter the WebDAV URL:
```
http://your-server:8080/
```
4. Click "Connect"
5. Enter your credentials
### Connecting with Linux (davfs2)
1. Install davfs2:
```bash
sudo apt-get install davfs2 # Ubuntu/Debian
```
2. Mount the WebDAV share:
```bash
sudo mount -t davfs http://your-server:8080/ /mnt/webdav
```
3. Enter credentials when prompted
### Command Line Tools
#### Using curl
**Upload a file:**
```bash
curl -u username:password -T file.txt http://localhost:8080/file.txt
```
**Download a file:**
```bash
curl -u username:password http://localhost:8080/file.txt -o file.txt
```
**Create a directory:**
```bash
curl -u username:password -X MKCOL http://localhost:8080/newdir/
```
**Delete a resource:**
```bash
curl -u username:password -X DELETE http://localhost:8080/file.txt
```
#### Using cadaver
```bash
cadaver http://localhost:8080/
# Enter credentials
dav:/> ls
dav:/> put localfile.txt
dav:/> get remotefile.txt
dav:/> mkcol newfolder
```
## User Management
### Creating Users Programmatically
```python
import asyncio
from main import Database
async def create_user():
db = Database('./webdav.db')
user_id = await db.create_user(
username='john',
password='SecurePass123!',
email='john@example.com',
role='user'
)
print(f"Created user with ID: {user_id}")
asyncio.run(create_user())
```
### User Roles
- **admin**: Full access to all features and user management
- **user**: Standard user with access to their own directory
- **readonly**: Read-only access (future implementation)
### Directory Structure
```
webdav/
├── users/
│ ├── admin/ # Admin user directory
│ ├── john/ # John's private directory
│ └── jane/ # Jane's private directory
├── shared/ # Shared between all users (optional)
└── public/ # Public access (optional)
```
## Production Deployment
### Using Gunicorn
Create `gunicorn_config.py`:
```python
import multiprocessing
bind = "0.0.0.0:8080"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "aiohttp.GunicornWebWorker"
keepalive = 30
timeout = 60
accesslog = "./logs/access.log"
errorlog = "./logs/error.log"
loglevel = "info"
```
Run with Gunicorn:
```bash
gunicorn main:init_app --config gunicorn_config.py
```
### Using Docker
Create `Dockerfile`:
```dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Create directories
RUN mkdir -p /app/webdav /app/logs
# Expose port
EXPOSE 8080
# Run application
CMD ["python", "main.py"]
```
Create `docker-compose.yml`:
```yaml
version: '3.8'
services:
webdav:
build: .
ports:
- "8080:8080"
volumes:
- ./webdav:/app/webdav
- ./logs:/app/logs
- ./webdav.db:/app/webdav.db
environment:
- HOST=0.0.0.0
- PORT=8080
- DB_PATH=/app/webdav.db
- WEBDAV_ROOT=/app/webdav
restart: unless-stopped
# Optional: Redis for caching
redis:
image: redis:alpine
ports:
- "6379:6379"
restart: unless-stopped
```
Build and run:
```bash
docker-compose up -d
```
### Nginx Reverse Proxy
Create `/etc/nginx/sites-available/webdav`:
```nginx
server {
listen 80;
server_name webdav.example.com;
# Redirect to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name webdav.example.com;
ssl_certificate /etc/letsencrypt/live/webdav.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/webdav.example.com/privkey.pem;
# WebDAV specific settings
client_max_body_size 100M;
client_body_buffer_size 128k;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebDAV headers
proxy_set_header Destination $http_destination;
proxy_set_header Depth $http_depth;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
```
Enable and reload:
```bash
sudo ln -s /etc/nginx/sites-available/webdav /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
## Security Best Practices
### SSL/TLS Configuration
1. **Always use HTTPS in production**
2. Generate SSL certificates with Let's Encrypt:
```bash
sudo certbot certonly --nginx -d webdav.example.com
```
3. Update `.env`:
```env
SSL_ENABLED=true
SSL_CERT_PATH=/etc/letsencrypt/live/webdav.example.com/fullchain.pem
SSL_KEY_PATH=/etc/letsencrypt/live/webdav.example.com/privkey.pem
```
### Authentication
- Use **Digest authentication** over Basic when possible
- Enforce strong passwords (min length, complexity)
- Enable rate limiting to prevent brute force attacks
- Implement account lockout after failed attempts
### Firewall Rules
```bash
# Allow only necessary ports
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
```
### Regular Updates
```bash
# Update dependencies
pip install --upgrade -r requirements.txt
# Backup database before updates
cp webdav.db webdav.db.backup
```
## Monitoring and Logging
### Log Files
Logs are stored in `./logs/` directory:
- `webdav.log` - Application logs
- `access.log` - Access logs (requests)
- `error.log` - Error logs
### Log Format
JSON-structured logs for easy parsing:
```json
{
"timestamp": "2025-01-15T10:30:45Z",
"level": "INFO",
"user": "john",
"method": "PROPFIND",
"path": "/documents/",
"status": 207,
"duration_ms": 45
}
```
### Health Check
Access the health check endpoint:
```bash
curl http://localhost:8080/health
```
## Troubleshooting
### Windows Explorer Connection Issues
**Problem**: "The network folder is no longer available"
**Solutions**:
1. Increase Windows WebClient timeout:
```
Registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WebClient\Parameters
FileSizeLimitInBytes = DWORD: 0xFFFFFFFF
```
2. Enable Basic Authentication over HTTP (insecure - use only for testing):
```
Registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WebClient\Parameters
BasicAuthLevel = 2
```
3. Restart WebClient service:
```powershell
net stop webclient
net start webclient
```
**Problem**: "The specified server cannot perform the requested operation"
**Solution**: Ensure the URL ends with a slash and doesn't include port 80:
- ❌ `http://server:80/path`
- ✅ `http://server/path/`
### macOS Finder Issues
**Problem**: Connection refused or timeout
**Solutions**:
1. Use HTTP URL with explicit protocol:
```
http://server:8080/
```
2. Check firewall settings on server
3. Try connecting via IP address instead of hostname
### Performance Issues
**Problem**: Slow PROPFIND responses
**Solutions**:
1. Reduce `MAX_PROPFIND_DEPTH` in `.env`:
```env
MAX_PROPFIND_DEPTH=1
```
2. Enable caching with Redis:
```env
CACHE_ENABLED=true
REDIS_HOST=localhost
```
3. Increase worker processes:
```env
WORKERS=8
```
### Database Locked Errors
**Problem**: "database is locked" errors
**Solutions**:
1. Enable WAL mode (automatic in code)
2. Ensure only one process accesses the database
3. Use separate databases for multiple instances
## API Documentation
### WebDAV Methods
#### PROPFIND - Property Discovery
```http
PROPFIND /documents/ HTTP/1.1
Depth: 1
Content-Type: application/xml
```
#### PROPPATCH - Property Modification
```http
PROPPATCH /file.txt HTTP/1.1
Content-Type: application/xml
My Document
```
#### LOCK - Resource Locking
```http
LOCK /file.txt HTTP/1.1
Timeout: Second-3600
Content-Type: application/xml
mailto:john@example.com
```
## Development
### Running Tests
```bash
# Install test dependencies
pip install pytest pytest-asyncio pytest-aiohttp pytest-cov
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=. --cov-report=html
```
### Code Style
```bash
# Format code
black main.py
# Lint code
flake8 main.py
# Type checking
mypy main.py
```
### Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Submit a pull request
## License
MIT License - See LICENSE file for details
## Support
For issues, questions, or contributions:
- GitHub Issues: [Create an issue]
- Documentation: [Wiki]
- Community: [Discussions]
## Changelog
### Version 1.0.0 (2025-01-15)
- Initial release
- Full RFC 4918 compliance
- Windows Explorer compatibility
- Multi-user support with SQLite backend
- Basic and Digest authentication
- Resource locking
- Custom properties
- Production-ready with Gunicorn support
## Acknowledgments
- RFC 4918 - HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)
- aiohttp - Async HTTP client/server framework
- Python community
---
**Made with ❤️ for the WebDAV community**