Self-Hosting Pingvin Share: WeTransfer Alternative with Docker

You need to send a large file to someone. WeTransfer caps free transfers at 2 GB. Google Drive wants your firstborn child’s data. Dropbox links expire at inconvenient times. And you’re already running a home server — so why not host your own file sharing platform?

Pingvin Share is a self-hosted, open-source file sharing platform that does exactly what WeTransfer does, but on your hardware, with your rules, and no file size limits beyond your disk space.

Why Pingvin Share

The self-hosted file sharing space has a few options — FileBrowser, ProjectSend, Nextcloud’s sharing feature. Here’s what makes Pingvin Share stand out:

  • Dead simple — One container, one volume mount. You’re up in under a minute.
  • No file size limits — Share as much as your disk can hold. No arbitrary caps.
  • Expiration dates — Set shares to auto-expire after hours, days, or weeks.
  • Password protection — Lock shares behind passwords for sensitive files.
  • Visitor limits — Restrict how many times a share link can be accessed.
  • Reverse shares — Let others upload files to you through a secure link — perfect for collecting documents.
  • Email notifications — Automatically email recipients when a share is ready.
  • ClamAV integration — Scan uploaded files for malware automatically.
  • S3 storage — Store files on S3-compatible storage (MinIO, Backblaze B2, AWS) instead of local disk.
  • OIDC and LDAP — Integrate with your existing authentication stack (Authentik, Authelia, Keycloak).
  • Clean UI — Modern, responsive interface that doesn’t look like it was built in 2008.

The trade-off: Pingvin Share is focused purely on temporary file sharing. If you need permanent file storage, collaboration, or document editing, look at Nextcloud. But for “send this file to that person” workflows, Pingvin Share is lighter and simpler.

Note on project status: The original developer has shifted focus to Pocket ID and is no longer actively maintaining Pingvin Share. The project is stable, functional, and open to community forks. For a file sharing tool, stability matters more than frequent updates — the core functionality works well as-is.

Prerequisites

  • A Linux server with Docker and Docker Compose installed
  • At least 512 MB of free RAM
  • Sufficient disk space for your shared files
  • A domain name if you want external access with HTTPS

Step 1: Create the Project Directory

mkdir -p ~/docker/pingvin-share && cd ~/docker/pingvin-share

Step 2: Create the Docker Compose File

Create a docker-compose.yml file:

services:
  pingvin-share:
    image: stonith404/pingvin-share
    container_name: pingvin-share
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - TRUST_PROXY=false
    volumes:
      - "./data:/opt/app/backend/data"
      - "./data/images:/opt/app/frontend/public/img"

That’s it. Seriously. One service, two volume mounts.

Step 3: Start Pingvin Share

docker compose up -d

Wait a few seconds, then open http://your-server-ip:3000 in your browser.

The default admin credentials are:

Change these immediately — go to the admin panel and update the email and password.

Step 4: Configure Basic Settings

Navigate to /admin/config in the web UI. Key settings to configure right away:

General

  • App Name — Change “Pingvin Share” to your custom brand name.
  • App URL — Set this to your public URL (e.g., https://share.yourdomain.com). This is critical for share links to work correctly.

Share Settings

  • Max share size — Default is unlimited. Set a reasonable limit if you’re concerned about disk usage (e.g., 10737418240 for 10 GB).
  • Default expiration — How long shares last by default. 7 days is a sensible default.
  • Max expiration — The maximum time a share can remain active.
  • Zip download — Enable to let recipients download all files in a share as a single ZIP.

Email (SMTP)

Configure SMTP to enable email notifications for share recipients:

  • SMTP Host — Your mail server (e.g., smtp.gmail.com, smtp.fastmail.com, or your self-hosted Mailcow/Stalwart instance).
  • SMTP Port — Usually 587 for STARTTLS.
  • SMTP Username/Password — Your email credentials or app password.
  • Sender email — The “from” address on notification emails.

Step 5: Set Up a Reverse Proxy

For HTTPS access, put Pingvin Share behind a reverse proxy. Here’s configurations for the most common options:

s}harer.eyvoeurrsdeo_mparionx.ycopmin{gvin-share:3000

Nginx

server {
    listen 443 ssl;
    server_name share.yourdomain.com;

    ssl_certificate /etc/ssl/certs/yourdomain.crt;
    ssl_certificate_key /etc/ssl/private/yourdomain.key;

    client_max_body_size 10G;

    location / {
        proxy_pass http://localhost: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;
    }
}

Important: When using a reverse proxy, set TRUST_PROXY=true in your Docker Compose environment so Pingvin Share correctly reads the X-Forwarded-For header for rate limiting and logging.

Also note the client_max_body_size 10G directive in Nginx — without this, Nginx will reject large uploads with a 413 Request Entity Too Large error. Adjust the value to match your max share size. Caddy has no default upload limit.

Nginx Proxy Manager

Add a new proxy host pointing to pingvin-share on port 3000. Under the “Advanced” tab, add:

client_max_body_size10G;

Step 6: Set User ID Permissions (Optional)

If you run Docker rootless or need specific file ownership, set PUID and PGID:

services:
  pingvin-share:
    image: stonith404/pingvin-share
    environment:
      - TRUST_PROXY=true
      - PUID=1000
      - PGID=1000
    volumes:
      - "./data:/opt/app/backend/data"
      - "./data/images:/opt/app/frontend/public/img"

Find your user’s IDs with id on the host machine.

Step 7: Add ClamAV for Malware Scanning (Optional)

If other people will upload files to your instance (via reverse shares or public access), adding ClamAV is a smart move:

services:
  pingvin-share:
    image: stonith404/pingvin-share
    container_name: pingvin-share
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - TRUST_PROXY=true
    volumes:
      - "./data:/opt/app/backend/data"
      - "./data/images:/opt/app/frontend/public/img"
    depends_on:
      clamav:
        condition: service_healthy

  clamav:
    image: clamav/clamav
    container_name: pingvin-clamav
    restart: unless-stopped

ClamAV takes 1-2 minutes to start while it loads virus definitions. Pingvin Share will wait for the health check to pass before starting. The logs should show “ClamAV is active” once everything is ready.

Resource warning: ClamAV uses approximately 1 GB of RAM for its virus signature database. If you’re running on a low-memory server (2 GB or less), skip this and rely on other security measures.

Step 8: Configure S3 Storage (Optional)

Instead of storing files on local disk, you can use S3-compatible storage. This is useful for offloading large files to cheap object storage like Backblaze B2 or MinIO.

In the admin panel (/admin/config), under the storage section:

  • Storage provider — Select “S3”
  • S3 Endpoint — Your S3 endpoint (e.g., s3.us-west-002.backblazeb2.com)
  • S3 Region — The region of your bucket
  • S3 Bucket — Your bucket name
  • S3 Access Key / Secret Key — Your S3 credentials

Files will now be stored in your S3 bucket instead of the local ./data directory.

Step 9: Set Up Authentication (Optional)

Pingvin Share supports OIDC and LDAP for single sign-on. If you’re already running Authentik, Authelia, or Keycloak, you can let users log in through your existing identity provider.

Configure this in the admin panel under /admin/config → Social Login / OIDC settings. You’ll need:

  • Issuer URL — Your OIDC provider’s discovery URL
  • Client ID — Created in your OIDC provider
  • Client Secret — Created in your OIDC provider

Using Pingvin Share

Creating a Share

  1. Click Create Share on the dashboard.
  2. Drag and drop files or click to browse.
  3. Set optional parameters: expiration, password, visitor limit, description.
  4. Click Share to generate a link.
  5. Copy the link or email it directly to recipients.

Reverse Shares

Reverse shares flip the flow — instead of you sending files, others send files to you. This is great for:

  • Collecting documents from clients
  • Receiving homework submissions
  • Gathering photos from event attendees

Create a reverse share from the dashboard, set constraints (max file size, max files, expiration), and send the link. Uploads land in your Pingvin Share instance.

User Management

The admin panel lets you create additional user accounts, each with their own shares and storage. You can also disable registration to keep your instance private.

Backup Strategy

Pingvin Share stores everything in the ./data directory:

#!/bin/bash
# backup-pingvin.sh
BACKUP_DIR="/path/to/backups"
SOURCE_DIR="$HOME/docker/pingvin-share/data"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Stop container for consistent backup
docker compose -f ~/docker/pingvin-share/docker-compose.yml stop

# Create backup
tar -czf "$BACKUP_DIR/pingvin-share-$TIMESTAMP.tar.gz" -C "$SOURCE_DIR" .

# Restart
docker compose -f ~/docker/pingvin-share/docker-compose.yml up -d

echo "Backup complete: pingvin-share-$TIMESTAMP.tar.gz"

The data directory contains the SQLite database and all uploaded files. For S3 storage, you only need to back up the SQLite database (at ./data/pingvin-share.db).

Configuration via YAML

If you prefer configuration-as-code over the web UI, mount a config.yaml file:

services:
  pingvin-share:
    image: stonith404/pingvin-share
    volumes:
      - "./data:/opt/app/backend/data"
      - "./data/images:/opt/app/frontend/public/img"
      - "./config.yaml:/opt/app/config.yaml"

Create your config.yaml based on the example in the repository. Note that when using YAML configuration, the web UI settings page becomes read-only.

Troubleshooting

Large uploads fail with timeout

If large file uploads fail, check:

  1. Reverse proxy limits — Nginx’s client_max_body_size must be large enough. Caddy has no limit by default.
  2. Proxy timeouts — Add proxy_read_timeout 3600s; and proxy_send_timeout 3600s; to your Nginx config.
  3. PHP limits — Not applicable here (Pingvin Share is Node.js-based), but worth noting if you’re used to PHP apps.

Set the App URL in admin settings to your public-facing URL. Without this, generated links use localhost:3000.

ClamAV fails to start

ClamAV needs to download virus definitions on first boot. Ensure your server has internet access and wait 2-3 minutes. Check logs with:

docker logs pingvin-clamav

Permission denied on data directory

Ensure the PUID/PGID environment variables match the owner of your ./data directory:

# Check current ownership
ls -la ./data

# Fix if needed
sudo chown -R 1000:1000 ./data

Pingvin Share vs Alternatives

FeaturePingvin ShareSend (Firefox)FileBrowserNextcloud
One-click sharing
Expiring links
Password protection
Reverse shares
No file size limit❌ (2.5 GB)
S3 storage
ClamAV scanning
Resource usageLowLowLowHigh
Setup complexityMinimalModerateMinimalComplex

Wrapping Up

Pingvin Share does one thing well: temporary file sharing. No bloat, no complicated setup, no surprise storage limits. If you’ve ever thought “I just need to send this file to someone,” this is the tool.

The setup is as simple as Docker gets — one container, two volumes, done. Add ClamAV if untrusted users will upload, add a reverse proxy for HTTPS, and you have a production-ready WeTransfer replacement running on your own hardware.