CLI tool
Upload/Up1 avatar
Upload/Up1

Up1: Client-side Encrypted Image Hosting Where the Server Reads Nothing

Client-side encrypted image host web server

838 stars102 forksJavaScriptMIT

At a glance

What is it?
Up1 is a MIT licensed image host that encrypts uploads in the browser and stores bytes the server cannot interpret. It suits people who need to share images and short files over a host they run themselves, and it leaves two sharp edges: downloads are not streamed, and the cipher mode is slow.
Who is it for?
Up1 fits teams that run their own host and need uploads to be unreadable to the operator, for example a shared image drop over a machine you control. It is the wrong choice for large files, since decryption is not streamed and a big download has to fit in browser memory.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 148 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A host that stores bytes it cannot interpret

Up1 is a small web server whose central design decision is that encryption happens on the client. The project describes itself as a simple host that client-side encrypts images, text and other data and stores them, with the server knowing nothing about the contents. What the server holds is a blob and an identifier. The original filename and mime type travel inside the encrypted payload, so a visitor sees the right content even though the server never parsed it. That is the appeal for anyone who wants to run a pastebin or image drop without trusting the machine it sits on. Uploads can be viewed as images, as text with syntax highlighting, as short videos, or as arbitrary binary downloads, so the same host covers several everyday sharing needs without a separate service for each file type.

One seed becomes an AES key, a CCM IV and a file identifier

The crypto design is where Up1 is most specific, and the documentation is unusually clear about it. Before an upload, a seed is generated. The seed can be any length because the server can never tell, but by default it is 25 characters. That seed is run through SHA512, and the output is sliced into three parts: bytes 0-256 are the AES key, bytes 256-384 are the CCM IV, and bytes 384-512 are the server's file identifier. The payload is then encrypted with AES-CCM using SJCL, and it is sent to the server together with that identifier. Inside the encryption a JSON object is prepended holding metadata, currently the filename and the mime type. The decrypted blob starts with 2 bytes giving the JSON character length, then the JSON, then the file data at the end. Deletion rides on a different primitive: the server computes HMAC-SHA256(static_delete_key, identifier), and a client that holds the delete token can trigger removal without ever knowing the file contents.

Running a server from a cloned checkout

The quick start in the project documentation installs Node on the host, clones the repository, copies both example configuration files, installs the npm dependencies inside the server directory and starts the process. The `cp` steps matter, because the server and the web client read their settings from `server.conf` and `client/config.js`, and both files exist in the repository only as `.example` versions.

bash
    apt install nodejs
    git clone https://github.com/Upload/Up1
    cd Up1
    cp server/server.conf.example server/server.conf
    cp client/config.js.example client/config.js
    cd server
    npm install
    node server.js

After that the process listens on the address given in `server.conf`. The `listen` value is an `address:port` string where either half is optional, so the documented examples range from `":9000"` for any interface on port 9000, to `"127.0.0.1"` for localhost on port 80, to `"1.1.1.1:8080"` for a specific address, and even `""` for any interface on port 80. The `api_key` must also be copied into the client configuration, since the two sides have to agree on it.

Keys, size limits and the Cloudflare cache section

The server configuration carries four settings worth understanding before you expose the service. `api_key` is described as a very basic security measure that requires any client making an upload to know the key, and the documentation itself calls it weak and suggests replacing it with HTTP authentication. `delete_key` is the secret the server uses to secure deletion keys, so it should be something only the server knows. `maximum_file_size` caps the largest upload in bytes, with the default being a decimal 50MB. Beyond those, the configuration file has `http`, `https` and `cloudflare-cache-invalidate` sections, of which at least one of the first two must be enabled. The `cloudflare-cache-invalidate` section is disabled by default and matters only if you run the host behind Cloudflare: enabling it makes an API call when an upload is deleted, so the edge does not keep serving copies of content you removed.

Downloads are not streamed, so file size becomes a real constraint

The caveats section states plainly that encryption and decryption are not streamed or chunked. That has a direct consequence for users: any download must fit fully in memory or the browser may crash. The documentation is relaxed about images under 10MB and blunt about longer content, noting that sharing a long gameplay video or recorded meeting minutes may be a problem. This is the clearest boundary in the project and it is a property of the format, not of the server tuning. The `maximum_file_size` setting and the in-memory decryption requirement point in the same direction, so raising the limit does not remove the ceiling, it just moves it to the client. The maintainers ask for help on this point and are open to contributions even if those break backwards compatibility.

Why the project stayed on CCM instead of GCM or OCB

Up1 documents its cipher choice at length, which is unusual and useful. AES-CCM is acknowledged as one of the slower authenticated encryption modes, slightly slower than GCM and almost twice as slow as OCB, and it is not parallelizable. The stated reasons for staying with it are practical rather than performance driven. CCM is the most audited, oldest and most commonly used algorithm contained in SJCL, and since this data is viewed rather than written once, the authors argue security matters more than speed. They also note that the other two algorithms in SJCL were actually slower than CCM, and that while alternatives such as asmcrypto.js may be faster, the project prefers SJCL for familiarity and would revisit that with an audit from a trusted party. On the browser side, entropy comes from the WebCrypto APIs and the encryption runs inside a Web Worker.

A Go server, a CLI client and a demo host that is gone

Two implementation choices widen the options around the core service. The server is written in Node, and the project also ships a Go server that uses no dependencies outside the standard library, with its only cryptography being HMAC and SHA256 in the built-in packages for generating deletion keys. The command-line client lives in a separate repository: upclient sends files or data to Up1 servers, either through a unix pipe or as an argument, and prints the resulting URL on stdout.

bash
ps aux | up
bash
up image.png

Upclient runs on Node and uses SJCL for the crypto, so it can encrypt without a browser. The wider ecosystem has thinned out, though. There was a public free server at up1.ca, and the documentation states that this demo instance is no longer available or maintained, with several public hosts still running the software. ShareX support for Up1 has been removed since the demo server shut down, which leaves upclient as the main remaining utility for scripted uploads.

A decade between releases and a modest licence

The maintenance picture needs reading carefully. The repository is not archived, and the last push was on 2026-05-28, but the published releases are old: v0.3.1 on 2016-02-02 and a v1.0 stability release on 2016-02-28. The project is therefore better described as rarely released than as frequently updated, and any deployment should assume you are running the current source rather than a tagged release. The repository top level holds `client/`, `server/` and `i/`, which reflects the split between the browser code, the Node and Go servers, and what appears to be image assets. The licence is MIT, which is permissive for self-hosting and for redistribution, though the copyleft of the SJCL dependency is separate from the licence of the surrounding code. The pinned SJCL copy in the repository comes from a specific upstream commit and is built with a fixed configure command.

Editorial conclusion

Up1 fits teams that run their own host and need uploads to be unreadable to the operator, for example a shared image drop over a machine you control. It is the wrong choice for large files, since decryption is not streamed and a big download has to fit in browser memory. Before adopting it, copy server.conf.example to server.conf, set a delete_key that only the server knows, and check that the api_key in client/config.js matches the one in the server configuration.

Frequently asked questions

Can the Up1 server read the images and files uploaded to it?

No. Encryption happens in the browser before upload, and the server stores the encrypted blob together with an identifier, so it holds no usable copy of the contents. The filename and mime type are carried inside the encrypted payload.

How do I install and start an Up1 server?

The quick start clones the repository, copies server/server.conf.example and client/config.js.example into place, installs dependencies with npm install inside the server directory and starts the process with node server.js. The server listens on the address given by the listen setting in server.conf.

Is there a command-line tool for uploading to Up1?

Yes, upclient is a separate CLI that sends files or data to Up1 servers via a unix pipe or as an argument and returns the URL on stdout. It runs on Node and uses SJCL for the crypto.

What are the limits on file size for Up1 uploads?

The maximum_file_size setting caps uploads in bytes and defaults to a decimal 50MB. Encryption and decryption are also not streamed, so a download must fit fully in memory in the browser, which the documentation flags as a problem for longer videos.

How do I delete an image hosted on Up1?

A delete token is returned when an upload happens, and sending it back to the server deletes the image. On the server side, HMAC-SHA256(static_delete_key, identifier) is used, with the key held as a secret on the server.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. Upload/Up1 on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/upload-up1.svg)](https://hysenlabs.com/projects/upload-up1)

Was this useful?