Pingvin Share: Self-Hosted File Sharing Platform
Deploy Pingvin Share for secure, temporary file sharing with expiring links, password protection, and a beautiful interface. The privacy-focused alternative to WeTransfer.
Overview
Pingvin Share is a beautiful, self-hosted file sharing solution that makes it incredibly easy to share files with anyone, even people outside your network. Think of it as your personal WeTransfer or Firefox Send - but completely under your control, with no file size limits, no subscription fees, and complete privacy.
Built with modern web technologies (Next.js and NestJS), Pingvin Share offers an elegant, responsive interface that works flawlessly on any device. Whether you need to send a large video file to a client, share project assets with your team, or provide temporary download links to family members, Pingvin Share handles it all with style and security.
What sets Pingvin Share apart is its focus on temporary, secure file sharing. Files automatically expire after a set time, links can be password-protected, and you control exactly how many times a file can be downloaded. It’s perfect for sensitive documents, one-time transfers, or any scenario where you don’t want files floating around forever.
What You’ll Learn:
- Deploy Pingvin Share using Docker Compose with PostgreSQL
- Configure file upload limits and storage quotas
- Create expiring share links with custom lifetimes
- Implement password protection and download limits
- Set up email notifications for share activity
- Configure reverse proxy for secure remote access
- Customize branding and appearance
- Implement automated cleanup of expired files
- Monitor storage usage and share statistics
Why Choose Pingvin Share?
Unlike permanent file storage solutions like FileBrowser or Nextcloud, Pingvin Share is purpose-built for temporary sharing. It’s the perfect complement to your file management stack - use it when you need to quickly send files to someone without creating accounts, managing permissions, or worrying about cleanup. Files automatically disappear when they expire, keeping your storage clean and your data secure.
Prerequisites
Before starting, ensure you have:
Required:
- Docker and Docker Compose installed
- Basic understanding of Docker networking
- 512 MB RAM minimum (1 GB recommended)
- Network ports 3000 available (or your chosen port)
- Storage space for uploaded files (plan for 10-50 GB minimum)
Optional but Recommended:
- Reverse proxy (Traefik, Nginx Proxy Manager, Caddy)
- Domain name for public sharing
- SMTP server for email notifications
- PostgreSQL knowledge (basic)
Pre-Deployment Checklist:
- Docker environment is functional
- PostgreSQL or Docker PostgreSQL ready
- Port 3000 is available (or alternative chosen)
- Storage location with adequate space identified
- Domain name configured (if using HTTPS)
- SMTP credentials prepared (if using email)
Understanding Pingvin Share
Core Features
Share Management:
- Upload single files or multiple files per share
- Set expiration time (hours, days, weeks)
- Limit number of downloads per share
- Password protection for sensitive files
- Custom share descriptions and messages
- One-click link copying and QR codes
Security:
- Automatic file deletion after expiration
- Optional password protection
- Download limit enforcement
- No account required for recipients
- Configurable maximum file sizes
- Rate limiting to prevent abuse
User Experience:
- Clean, modern web interface
- Mobile-responsive design
- Drag-and-drop file uploads
- Upload progress indicators
- Direct download links (no forced landing pages)
- QR code generation for mobile sharing
Administration:
- Admin dashboard for monitoring
- User management (optional)
- Storage quota configuration
- System statistics and analytics
- Configurable retention policies
- Manual share cleanup
Architecture Overview
User Browser
↓
Nginx/Reverse Proxy (HTTPS)
↓
Pingvin Share Frontend (Next.js) - Port 3000
↓
Pingvin Share Backend (NestJS)
↓
PostgreSQL Database
↓
File Storage (Docker Volume or Host Mount) Components:
- Frontend: Next.js application serving the web UI
- Backend: NestJS API handling uploads, shares, and logic
- Database: PostgreSQL storing share metadata, settings
- Storage: File system or S3-compatible storage for uploaded files
How It Works
Creating a share:
- User uploads files via web interface
- Files stored on server with random IDs
- Share link generated with unique token
- Metadata saved to database (expiration, password, limits)
- Link shared with recipients
Accessing a share:
- Recipient clicks share link
- Pingvin Share validates token and checks expiration
- Password prompt shown (if protected)
- Download counter incremented
- Files served directly or via download page
Expiration and cleanup:
- Background job runs periodically
- Checks for expired shares
- Deletes associated files from storage
- Removes database records
- Storage reclaimed automatically
Installation and Deployment
Method 1: Docker Compose with PostgreSQL (Recommended)
The complete, production-ready deployment.
Create directory structure:
# Create Pingvin Share directory
mkdir -p /opt/pingvin-share/{data,database}
cd /opt/pingvin-share Create docker-compose.yml:
version: '3.8'
services:
pingvin-share:
image: stonith404/pingvin-share:latest
container_name: pingvin-share
restart: unless-stopped
# Environment variables
environment:
# Database connection
- DATABASE_URL=postgresql://pingvin:secure_db_password@postgres:5432/pingvin
# Backend configuration
- BACKEND_URL=http://localhost:3000
- FRONTEND_URL=http://localhost:3000
# File upload limits (in bytes)
# 10 GB max file size
- MAX_FILE_SIZE=10737418240
# Share defaults
- DEFAULT_EXPIRATION=7d
- MAX_EXPIRATION=30d
# Email configuration (optional)
- SMTP_HOST=smtp.gmail.com
- SMTP_PORT=587
- SMTP_USER=your-[email protected]
- SMTP_PASSWORD=your-app-password
- SMTP_FROM=Pingvin Share <[email protected]>
# Security
- ALLOW_REGISTRATION=false
- ALLOW_UNAUTHENTICATED_SHARES=true
# Port mapping
ports:
- "3000:3000"
# Volume mounts
volumes:
# Upload storage
- ./data:/opt/app/backend/data
# Optional: Config persistence
- ./config:/opt/app/backend/config
# Dependencies
depends_on:
postgres:
condition: service_healthy
# Security options
security_opt:
- no-new-privileges:true
# Resource limits
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
networks:
- pingvin-net
postgres:
image: postgres:16-alpine
container_name: pingvin-postgres
restart: unless-stopped
environment:
- POSTGRES_DB=pingvin
- POSTGRES_USER=pingvin
- POSTGRES_PASSWORD=secure_db_password
volumes:
- ./database:/var/lib/postgresql/data
# Health check
healthcheck:
test: ["CMD-SHELL", "pg_isready -U pingvin"]
interval: 10s
timeout: 5s
retries: 5
networks:
- pingvin-net
networks:
pingvin-net:
driver: bridge Important: Change secure_db_password to a strong, unique password!
Deploy Pingvin Share:
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f pingvin-share
# Check status
docker-compose ps
# Verify database connection
docker-compose logs postgres | grep "ready to accept connections" Access Pingvin Share:
Open your browser to http://YOUR-SERVER-IP:3000
Method 2: Docker Compose with SQLite (Simpler)
For testing or low-traffic deployments:
version: '3.8'
services:
pingvin-share:
image: stonith404/pingvin-share:latest
container_name: pingvin-share
restart: unless-stopped
environment:
# SQLite database (file-based)
- DATABASE_URL=file:./data/pingvin.db
- BACKEND_URL=http://localhost:3000
- FRONTEND_URL=http://localhost:3000
- MAX_FILE_SIZE=5368709120 # 5 GB
ports:
- "3000:3000"
volumes:
- ./data:/opt/app/backend/data
networks:
- pingvin-net
networks:
pingvin-net:
driver: bridge Deploy:
docker-compose up -d Note: SQLite is simpler but less performant for high traffic.
Initial Setup
Create admin account:
- Open
http://YOUR-SERVER-IP:3000 - Click Sign Up (if registration enabled)
- Create your admin account
- Log in
If registration is disabled:
# Create admin user via CLI
docker exec -it pingvin-share npm run user:create
# Follow prompts to create admin user Configuration
Environment Variables
Core settings:
# Database
DATABASE_URL: PostgreSQL or SQLite connection string
# URLs (important for reverse proxy)
BACKEND_URL: Backend API URL (internal or external)
FRONTEND_URL: Frontend URL (what users see)
# File limits
MAX_FILE_SIZE: Maximum file size in bytes (default: 1 GB)
# Share defaults
DEFAULT_EXPIRATION: Default expiration time (e.g., "7d", "24h")
MAX_EXPIRATION: Maximum allowed expiration (e.g., "30d") File size examples:
# 500 MB
MAX_FILE_SIZE=524288000
# 1 GB
MAX_FILE_SIZE=1073741824
# 5 GB
MAX_FILE_SIZE=5368709120
# 10 GB
MAX_FILE_SIZE=10737418240
# 50 GB (requires lots of RAM and disk space)
MAX_FILE_SIZE=53687091200 Expiration format:
# Hours
DEFAULT_EXPIRATION=24h
DEFAULT_EXPIRATION=72h
# Days
DEFAULT_EXPIRATION=7d
DEFAULT_EXPIRATION=30d
# Weeks
DEFAULT_EXPIRATION=2w
DEFAULT_EXPIRATION=4w User Registration Settings
Disable public registration:
ALLOW_REGISTRATION=false Users must be created by admin.
Enable public registration:
ALLOW_REGISTRATION=true Anyone can create an account.
Anonymous shares:
# Allow unauthenticated users to create shares
ALLOW_UNAUTHENTICATED_SHARES=true
# Require login to create shares
ALLOW_UNAUTHENTICATED_SHARES=false Email Configuration
Gmail example:
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-[email protected]
SMTP_PASSWORD=your-app-password
SMTP_FROM=Pingvin Share <[email protected]> Custom SMTP server:
SMTP_HOST=mail.yourdomain.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=smtp_password
SMTP_FROM=File Sharing <[email protected]>
SMTP_SECURE=true # Use TLS Email notifications include:
- Share creation confirmation
- Share download notifications (optional)
- Share expiration warnings
Creating and Managing Shares
Creating a Share
Via Web Interface:
- Log in (if required)
- Click Create Share or New Share
- Upload files:
- Drag and drop into upload area
- Or click to browse files
- Multiple files supported
- Configure share settings:
- Expiration: When share expires
- Max Downloads: Limit number of downloads (optional)
- Password: Protect with password (optional)
- Description: Add message for recipients
- Click Create Share
- Copy share link or QR code
Share link format:
https://share.yourdomain.com/s/UNIQUE-TOKEN-HERE Share Settings Explained
Expiration:
- Never: Share never expires (not recommended)
- 1 hour: For very temporary shares
- 6 hours: Same-day sharing
- 24 hours: One-day access
- 7 days: One-week access (default)
- 30 days: Long-term sharing
- Custom: Set specific date/time
Max Downloads:
- Unlimited: Anyone can download any number of times
- 1 download: One-time access (link becomes invalid after)
- 5 downloads: Limited sharing
- Custom: Set specific number
Password Protection:
- None: No password required
- Custom password: Recipients must enter password
Best practice combinations:
Sensitive documents:
Expiration: 24 hours
Max Downloads: 1
Password: Yes Team file sharing:
Expiration: 7 days
Max Downloads: 10
Password: Yes (shared with team) Public downloads:
Expiration: 30 days
Max Downloads: Unlimited
Password: No One-time transfer:
Expiration: 1 hour
Max Downloads: 1
Password: Optional Managing Your Shares
View active shares:
- Log in to Pingvin Share
- Go to My Shares or Dashboard
- See all your active shares
For each share, you can:
- View share details (views, downloads, expiration)
- Copy share link
- Download QR code
- Delete share early
- Extend expiration (if allowed)
- Change password
Delete a share:
- Find share in My Shares
- Click Delete or trash icon
- Confirm deletion
- Files immediately deleted from server
Sharing Links
Copy link:
Click the copy icon next to the share link.
QR Code:
Click the QR code icon to generate a scannable code:
- Perfect for mobile transfers
- Share via screenshot or print
- No typing required
Email link:
Use the email button to send share link via configured SMTP.
Reverse Proxy Configuration
Why HTTPS is Essential
For Pingvin Share to work properly over the internet:
- Security: Encrypt file transfers
- Browser compatibility: Modern browsers require HTTPS for many features
- Professional appearance: No security warnings
- Trust: Recipients more likely to download from HTTPS sites
Traefik Configuration
Update docker-compose.yml:
version: '3.8'
services:
pingvin-share:
image: stonith404/pingvin-share:latest
container_name: pingvin-share
restart: unless-stopped
environment:
- DATABASE_URL=postgresql://pingvin:secure_db_password@postgres:5432/pingvin
# Important: Set to your public URL
- BACKEND_URL=https://share.yourdomain.com
- FRONTEND_URL=https://share.yourdomain.com
- MAX_FILE_SIZE=10737418240
volumes:
- ./data:/opt/app/backend/data
depends_on:
- postgres
networks:
- traefik
- pingvin-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.pingvin.rule=Host(`share.yourdomain.com`)"
- "traefik.http.routers.pingvin.entrypoints=websecure"
- "traefik.http.routers.pingvin.tls.certresolver=letsencrypt"
- "traefik.http.services.pingvin.loadbalancer.server.port=3000"
# Increase upload size limit
- "traefik.http.middlewares.pingvin-buffering.buffering.maxRequestBodyBytes=10737418240"
- "traefik.http.routers.pingvin.middlewares=pingvin-buffering"
postgres:
# ... (same as before)
networks:
- pingvin-net
networks:
traefik:
external: true
pingvin-net:
driver: bridge Deploy:
docker-compose up -d Access at: https://share.yourdomain.com
Nginx Proxy Manager
- Log into Nginx Proxy Manager
- Add Proxy Host:
- Domain Names:
share.yourdomain.com - Scheme:
http - Forward Hostname/IP:
pingvin-share(or container IP) - Forward Port:
3000
- Domain Names:
- Custom locations (for upload limits):
- Location:
/ - Advanced config:
client_max_body_size 10G; proxy_request_buffering off;
- Location:
- SSL tab: Request Let’s Encrypt certificate
- Enable Force SSL
Caddy Configuration
Caddyfile:
share.yourdomain.com {
reverse_proxy pingvin-share:3000
# Increase upload size limit
request_body {
max_size 10GB
}
# Increase timeout for large uploads
timeouts {
read_body 1h
write 1h
}
} Nginx Standalone
nginx.conf:
server {
listen 443 ssl http2;
server_name share.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/share.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/share.yourdomain.com/privkey.pem;
# Large file upload support
client_max_body_size 10G;
client_body_timeout 300s;
location / {
proxy_pass http://pingvin-share:3000;
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;
# Upload streaming
proxy_request_buffering off;
proxy_buffering off;
# Timeouts for large uploads
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
} Storage Management
File Storage Location
Default location:
volumes:
- ./data:/opt/app/backend/data Files stored in: /opt/pingvin-share/data/uploads/
Custom storage location:
volumes:
- /mnt/large-storage/pingvin-uploads:/opt/app/backend/data Ensure proper permissions:
# Set ownership (UID 1000 in container)
sudo chown -R 1000:1000 /opt/pingvin-share/data
# Set permissions
sudo chmod -R 755 /opt/pingvin-share/data Storage Quotas
Global storage limit:
Set via environment variable:
environment:
- MAX_TOTAL_STORAGE=107374182400 # 100 GB total Per-user quotas:
Configure in admin dashboard after login.
Monitoring Storage Usage
Check disk usage:
# Check data directory size
du -sh /opt/pingvin-share/data
# Detailed breakdown
du -h --max-depth=1 /opt/pingvin-share/data
# Check container disk usage
docker system df -v Automated monitoring script:
#!/bin/bash
# /opt/scripts/pingvin-storage-check.sh
DATA_DIR="/opt/pingvin-share/data"
THRESHOLD=80 # Alert at 80% usage
USAGE=$(df -h "$DATA_DIR" | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
echo "WARNING: Pingvin Share storage at ${USAGE}%"
# Add notification (email, webhook, etc.)
fi
echo "Storage usage: ${USAGE}%" Cleanup Policies
Automatic expiration:
Pingvin Share automatically deletes expired shares based on configured expiration times.
Manual cleanup:
# Stop Pingvin Share
docker-compose stop pingvin-share
# Remove old files (example: older than 30 days)
find /opt/pingvin-share/data/uploads -type f -mtime +30 -delete
# Remove empty directories
find /opt/pingvin-share/data/uploads -type d -empty -delete
# Restart
docker-compose start pingvin-share Cleanup script with database sync:
#!/bin/bash
# /opt/scripts/pingvin-cleanup.sh
# Trigger internal cleanup via API (if available)
# Or use database queries to identify orphaned files
docker exec pingvin-share node /opt/app/backend/dist/cleanup.js
echo "Cleanup completed: $(date)" Security Hardening
Password Strength
Enforce strong passwords for shares:
Educate users to use:
- At least 12 characters
- Mix of letters, numbers, symbols
- Generated passwords (password manager)
Example secure passwords:
xK9#mP2$vL7@qR4!
TigerElephant$92Cloud
2025-Secure-Share-Pass! Rate Limiting
Prevent abuse with rate limiting:
Nginx rate limiting:
limit_req_zone $binary_remote_addr zone=upload:10m rate=5r/m;
location /api/upload {
limit_req zone=upload burst=10 nodelay;
proxy_pass http://pingvin-share:3000;
} Cloudflare rate limiting:
Use Cloudflare’s Rate Limiting rules to protect upload endpoints.
File Type Restrictions
Block dangerous file types (optional):
Configure via reverse proxy:
location ~ .(exe|bat|cmd|sh|dll|msi)$ {
return 403 "File type not allowed";
} Better approach: Scan with ClamAV or similar:
services:
clamav:
image: clamav/clamav:latest
container_name: clamav
volumes:
- ./clamav:/var/lib/clamav
networks:
- pingvin-net Integrate ClamAV scanning with upload pipeline (requires custom code).
HTTPS Only
Force HTTPS:
server {
listen 80;
server_name share.yourdomain.com;
return 301 https://$server_name$request_uri;
} Strict Transport Security (HSTS):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; Database Security
Secure PostgreSQL:
postgres:
environment:
# Strong password
- POSTGRES_PASSWORD=VERY-LONG-RANDOM-PASSWORD-HERE
# Disable remote connections (use Docker network only)
networks:
- pingvin-net # Internal only, no external network Backup database regularly:
# Backup PostgreSQL
docker exec pingvin-postgres pg_dump -U pingvin pingvin > pingvin-backup-$(date +%Y%m%d).sql Backup and Restore
What to Backup
- Database: All share metadata
- Uploaded files:
/opt/pingvin-share/data - Configuration:
docker-compose.ymland.env
Automated Backup Script
#!/bin/bash
# /opt/scripts/backup-pingvin.sh
BACKUP_DIR="/mnt/backups/pingvin"
DATE=$(date +%Y%m%d_%H%M%S)
DATA_DIR="/opt/pingvin-share/data"
# Create backup directory
mkdir -p "$BACKUP_DIR"
# Backup database
docker exec pingvin-postgres pg_dump -U pingvin pingvin | gzip > "$BACKUP_DIR/database-$DATE.sql.gz"
# Backup files
tar -czf "$BACKUP_DIR/files-$DATE.tar.gz" -C "$DATA_DIR" .
# Backup config
cp /opt/pingvin-share/docker-compose.yml "$BACKUP_DIR/docker-compose-$DATE.yml"
# Keep only last 14 days
find "$BACKUP_DIR" -name "database-*.sql.gz" -mtime +14 -delete
find "$BACKUP_DIR" -name "files-*.tar.gz" -mtime +14 -delete
echo "Backup completed: $DATE" Automate with cron:
# Edit crontab
crontab -e
# Add daily backup at 2 AM
0 2 * * * /opt/scripts/backup-pingvin.sh >> /var/log/pingvin-backup.log 2>&1 Restore from Backup
# Stop Pingvin Share
docker-compose down
# Restore database
gunzip < /mnt/backups/pingvin/database-20250115_020000.sql.gz | docker exec -i pingvin-postgres psql -U pingvin pingvin
# Restore files
tar -xzf /mnt/backups/pingvin/files-20250115_020000.tar.gz -C /opt/pingvin-share/data
# Set permissions
chown -R 1000:1000 /opt/pingvin-share/data
# Start Pingvin Share
docker-compose up -d Troubleshooting
Issue 1: Upload Fails for Large Files
Symptoms:
- Small files upload fine
- Large files (100+ MB) fail or timeout
Solutions:
1. Increase reverse proxy limits:
See reverse proxy configuration section above.
2. Increase MAX_FILE_SIZE:
environment:
- MAX_FILE_SIZE=10737418240 # 10 GB 3. Check disk space:
df -h /opt/pingvin-share/data 4. Increase timeouts:
proxy_read_timeout 600s;
proxy_send_timeout 600s;
client_body_timeout 600s; Issue 2: Database Connection Failed
Symptoms:
- Pingvin Share won’t start
- Error: “Connection to database failed”
Diagnostics:
# Check PostgreSQL logs
docker logs pingvin-postgres
# Test database connection
docker exec pingvin-postgres psql -U pingvin -d pingvin -c "SELECT 1;" Solutions:
1. Verify DATABASE_URL:
DATABASE_URL=postgresql://pingvin:PASSWORD@postgres:5432/pingvin Ensure password matches PostgreSQL environment variable.
2. Wait for PostgreSQL:
Add healthcheck dependency:
depends_on:
postgres:
condition: service_healthy 3. Database doesn’t exist:
# Create database manually
docker exec -it pingvin-postgres psql -U pingvin -c "CREATE DATABASE pingvin;" Issue 3: Shares Not Expiring
Symptoms:
- Expired shares still accessible
- Files not cleaned up
Solutions:
1. Check cleanup job:
Pingvin Share should run automatic cleanup. Check logs:
docker logs pingvin-share | grep cleanup 2. Manual cleanup:
# Trigger cleanup manually (if API exists)
docker exec pingvin-share npm run cleanup
# Or restart container
docker-compose restart pingvin-share 3. Database clock:
Ensure server time is correct:
date
timedatectl Issue 4: Can’t Access Pingvin Share
Symptoms:
- Connection refused
- Page won’t load
Diagnostics:
# Check container status
docker ps | grep pingvin
# Check logs
docker logs pingvin-share
# Test locally
curl http://localhost:3000 Solutions:
Container not running:
docker-compose up -d Port conflict:
# Change port in docker-compose.yml
ports:
- "3001:3000" Firewall blocking:
sudo ufw allow 3000/tcp Issue 5: Email Notifications Not Working
Symptoms:
- No emails sent
- SMTP errors in logs
Diagnostics:
# Check logs for SMTP errors
docker logs pingvin-share | grep -i smtp
docker logs pingvin-share | grep -i email Solutions:
1. Gmail: Use App Password
Don’t use regular password. Generate App Password:
- Google Account → Security → 2-Step Verification → App Passwords
2. Test SMTP settings:
# Test SMTP from container
docker exec -it pingvin-share node -e "
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
auth: {
user: '[email protected]',
pass: 'your-app-password'
}
});
transporter.sendMail({
from: '[email protected]',
to: '[email protected]',
subject: 'Test',
text: 'Test email'
}, console.log);
" 3. Check SMTP port:
Some ISPs block port 25. Use 587 (submission) or 465 (SSL).
Advanced Features
Custom Branding
Logo and colors:
Pingvin Share supports custom branding via admin panel:
- Log in as admin
- Go to Settings → Appearance
- Upload custom logo
- Set primary color
- Set accent color
- Save changes
API Usage
Pingvin Share provides REST API for automation:
Create share via API:
# Authenticate
TOKEN=$(curl -X POST http://localhost:3000/api/auth/login -H "Content-Type: application/json" -d '{"email":"[email protected]","password":"password"}' | jq -r '.token')
# Upload file
curl -X POST http://localhost:3000/api/shares -H "Authorization: Bearer $TOKEN" -F "file=@/path/to/file.pdf" -F "expiration=7d" -F "maxDownloads=5" List shares:
curl -X GET http://localhost:3000/api/shares -H "Authorization: Bearer $TOKEN" S3-Compatible Storage
Use S3 or MinIO instead of local filesystem:
environment:
- STORAGE_TYPE=s3
- S3_ENDPOINT=https://s3.amazonaws.com
- S3_BUCKET=pingvin-shares
- S3_REGION=us-east-1
- S3_ACCESS_KEY=YOUR-ACCESS-KEY
- S3_SECRET_KEY=YOUR-SECRET-KEY Benefits:
- Unlimited scalable storage
- Geographic redundancy
- Cost-effective for large datasets
Integration with Other Services
Uptime monitoring:
Add HTTP monitor in Uptime Kuma pointing to Pingvin Share.
Notifications:
Use webhooks to notify other services when shares are created/downloaded.
Alternatives and Comparisons
Pingvin Share vs. WeTransfer
| Feature | Pingvin Share | WeTransfer |
|---|---|---|
| Self-Hosted | ✅ Yes | ❌ No |
| File Size Limit | Your storage | 2 GB (free), 200 GB (paid) |
| Cost | Free (hosting cost only) | Free/Paid subscription |
| Privacy | Complete | Third-party access |
| Customization | Full control | Limited |
| Expiration | Configurable | Fixed (7 days free, 30 days paid) |
Pingvin Share vs. Firefox Send
Firefox Send (discontinued):
- Mozilla project (no longer maintained)
- End-to-end encryption
- Simple interface
Pingvin Share (active):
- Active development
- More features (admin panel, user management)
- PostgreSQL backend
Send alternative: Use Pingvin Share or Lufi for Firefox Send replacement.
Pingvin Share vs. FileBrowser
Different use cases:
FileBrowser: Permanent file storage and management Pingvin Share: Temporary file sharing with links
Use both together:
- FileBrowser for internal file management
- Pingvin Share for external file sharing
Conclusion
You now have a fully functional Pingvin Share deployment enabling secure, temporary file sharing.
Key Takeaways:
- Self-Hosted: Complete control over your file sharing
- Secure: Password protection, expiring links, download limits
- Simple: Easy to use for both senders and recipients
- Flexible: Configure expiration, limits, and notifications
- Clean: Automatic cleanup of expired files
Next Steps:
- Set up HTTPS via reverse proxy for secure sharing
- Configure email notifications for share activity
- Set appropriate file size and expiration limits
- Create backup automation for database and files
- Share with your team or family
Related Guides:
- FileBrowser: Web-Based File Manager
- PairDrop: Local Network File Sharing
- MinIO: S3-Compatible Object Storage
Welcome to secure, self-hosted file sharing!
Guide Version: 1.0 Last Updated: January 15, 2025 Tested With: Pingvin Share v0.20.x Estimated Read Time: 30-35 minutes Estimated Implementation Time: 35 minutes
Part of the homelabbing.io File Sharing & Transfer series