The filesharing service everyone either hates or loves
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Go to file
Volkor d8047d8b74
fix up metrics
1 year ago
QuadFile change times to unix time 1 year ago
ansible Add Metrics 1 year ago
quadfile-theme@ef4e40ec1c huh 1 year ago
theme Thanks AB49K 2 years ago
.gitignore Add Metrics 1 year ago
.gitlab-ci.yml add ssh keys to gitignore along with fixing ansible command 3 years ago
.gitmodules add git modules 3 years ago Updated to match 7 years ago Add Metrics 1 year ago Initial move from Hyozan 8 years ago fix 403 1 year ago
requirements.txt Add Metrics 1 year ago fix up metrics 1 year ago
schema.sql Add Metrics 1 year ago
statsschema.sql Add Metrics 1 year ago Add Gunicorn entry point 7 years ago

QuadFile Version 2

A temporary (or permanent, depending on configuration) file sharing service written in Flask.


  • Automatically remove files that aren't accessed often enough
  • Supports all filetypes, with options to filter by file extension
  • Prevents duplicate filenames
  • Works on all platforms (as long as they can use basic JavaScript)
  • Both easy to set up and use
  • Threaded for effective use of resources (Unless you're not on SSD, in which case, enjoy your I/O clogs m8)
  • Color-coded and real-time console log
  • Easy to use with most applications, such as ShareX


Ignore the submodules directory, this is for my instance.


  • Python 3
  • sqlite3 package for your OS (To create the database)
  • Install the python requirements with (pip install -r requirements.txt)
  • nginx or another reverse proxy.


  • nginx, great for proxy_pass
  • gunicorn, allows you to use QuadFile with multiple workers

Using the thing

When deletion keys are enabled, you must either use the curl-supported 'api' or use the web browser to delete files. (Notice: these have been barely tested. Use at your own risk!)
To get your deletion key, either upload through curl, or through the web browser, it's the 16 character long random string.

  • API: curl -F key=KEYINHERE https://QUADFILE.WEBSITE/delete
  • WEB: Browse to https://QUADFILE.WEBSITE/delete/KEYINHERE

Test deployment

  • Clone the repo somewhere
  • pip install -r requirements.txt
  • Do cp
  • Edit so that the information is correct
  • sqlite3 files.db < schema.sql
  • chmod +x and then ./
  • ???
  • PROFIT (Hopefully)

Production deployment

  • Clone the repo somewhere
  • Set up a virtual environment for QuadFile
  • pip install -r requirements.txt
  • Do cp
  • Edit so that the information is correct
  • sqlite3 files.db < schema.sql
  • gunicorn wsgi:app -w 4 --bind --log-file $HOME/quadfile.log (Use systemd service to run it on boot if needed)
  • Configure nginx and proxy_pass it to gunicorn
  • ???
  • PROFIT (Hopefully)
  • Edit the pages in templates/*.html to personalize

Ansible Production Deployment (debian derivatives only)

This deploys quadfile automatically, listening on 8282, localhost only so you can manually setup nginx youself.

This creates the systemd service, along with a new user quadfile. It is installed by default to /opt/quadfile

Ensure the correct key is listed in known_hosts (ssh in with fowarding yourself, using -A and ssh into your git)

  1. Duplicate this repo, or fork it.
  2. In gitlab, add a new private key to the SSH_PRIVATE_KEY environment variable
    1. Also add the other ansible variables
  3. locally, ssh-copy-id -i <new/id_rsa> <host> copy the public key to the server
  4. [OPTIONAL] Create a submodule for your theme (make it public for the love of god, if you still want private, read here and add the pubkey to the deploy key on gitlab)
  5. setup ci
  6. run pipeline

systemd service file

Make sure to replace user with whatever user you want to run quadfile with (I reccomend a seperate user)

Description=QuadFile + Gunicorn Server

PermissionsStartOnly = true
User = user
Group = user
WorkingDirectory = /home/user/prod/QuadFile/

ExecStart = /usr/bin/gunicorn3 wsgi:app -w 8 --bind --log-file /home/user/logs/quadfile/quadfile.log --capture-output --error-log /home/user/logs/quadfile.log
ExecReload = /bin/kill -s HUP $MAINPID
ExecStop = /bin/kill -s TERM $MAINPID

WantedBy =

nginx config files

To have dynamic domain support, you must pass through a few things ontop of 'just proxy_pass it to gunicorn'.
This example includes a permenant redirect to https.

# Global redirect for http --> https
server {
        listen 80;
        listen [::]:80;
        # for certbot autorenew webroot
        location '/.well-known/acme-challenge/' {
                root /var/www/acme/;
        # redirect
        location / {
                return 301 https://$host$request_uri;

server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name domain1 domain2;
        root /path/to/QuadFile;

        ## SSL/TLS
        include snippets/https.conf;
        ssl_certificate /etc/letsencrypt/live/domain/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem;

        ## Reverse Proxy
        location / {
                proxy_set_header Host host;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Accept-Encoding "";
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Host $http_host;

        location /static {
                autoindex on;