FileHive is a web file manager built on Express.js that enables autoindex of a specific directory. It comes with a lot of customization options, access management, and support for both memory and Redis storage for authentication and rate-limiting. It supports uploading, deleting files and directories, and serves files with nginx speed when configured for.
Please note the following limitations and considerations when using FileHive on a Windows system:
- Hidden files on Windows may not be properly supported, as FileHive only recognizes files starting with a dot as hidden. Other hidden files, such as
desktop.ini
or other Windows hidden system files, may not be identified as hidden by FileHive. - If you need to index a folder that requires changing permissions, it is important to note that this process can be significantly more complicated on Windows compared to Linux, where a simple
chmod
command can be used.
- Auto-index of a specific directory
- Support for both memory and Redis storage for authentication and rate-limiting
- Customizable route names, session cookie names, and more
- Access management
- File upload, deletion, directory creation and deletion
- Works with nginx for speedy file serving
- Configuration is reloaded in real-time, allowing for updates to permissions without restarting the app
To install FileHive, follow these steps:
-
Clone this repository by running
git clone https://github.com/Buco7854/filehive
-
navigate to the directory.
cd filehive
-
Install dependencies by running
npm install
-
Customize the configuration in
config.yaml.example
and rename it toconfig.yaml
. -
Run the server by running
npm start
or
node src/app.js
Below is a complete list of configurations for filehive and their descriptions.
The protocol to use, http or https. This is a required field for security purposes. If you are using a proxy with an existing https configuration, you do not need to specify https here. Otherwise, use https, or your credentials may be vulnerable. If you set up https, you must provide the private_key and certificate keys (end of file).
Type: string
Example:
protocol: https
The port on which filehive will listen.
Type: number
Example:
port: 80
The root directory to serve.
Type: string
Example:
dir: "/path/to/dir/to/index/"
A boolean that specifies whether to autoindex a route if it is not in the configuration file.
Type: boolean
Example:
autoindex: true
A boolean that specifies whether to allow uploads when the route is not in the configuration file.
Type: boolean
Example:
upload: true
show_hidden
A boolean that specifies whether to allow a user to view hidden files and directories when the route is not in the configuration file.
Default is false
.
Type: boolean
Example:
show_hidden: true
User configuration, the username is the key.
Type: object
Example:
users:
a_user:
password: "password"
The configuration for a route when an unauthenticated user accesses it. Please note that trailing slash or not are not needed but in the case you want to pass a wildcard then there must be a trailing slash in front. Default is an empty array.
Type: array of objects
Example:
routes_anonymous_access:
- path: "/public/*"
autoindex: true
upload: false
show_hidden: false
The configuration for a route.
If user and path match the entry, it will be used.
If no match is found, fallbacks to the routes_anonymous_access
setting. If no match is found again, then use general settings. The routes are sorted from the longest to the shorter and will stop at the first match.
Default is an empty array.
Type: array of objects
Example:
routes_user_access:
- path: "/user/"
autoindex: true
upload: true
show_hidden: true
user: "a_user"
The name of the store where the session tokens and ratelimits are stored. If redis is available, better use it for persistence between file restarts.
Default is "memory"
.
Type: string
Example:
store: "redis"
The prefix in front of the key in the stores.
Default is "filehive-store"
.
Type: string
Example:
store-prefix: "my-prefix"
The redis store. Everything in there is optional. Default is an empty object.
Type: object
Example:
redis:
host: "localhost"
port: 6379
password: "password"
username: "username"
database: 0
The address on which your app will listen to requests.
Default is "127.0.0.1"
.
Type: string
Example:
listen-address: "0.0.0.0"
If your app is behind one or multiple proxies such as nginx, set their IP here (prepended by a hyphen). It is important to not that if the request came from a trusted proxy, FileHive will not serve files and will instead return json so that the proxy auth request can be done as fast as possible. Default is an empty array.
Type: array of string
Example:
proxies:
- 127.0.0.1
The path for FileHive static files.
Do not name a directory the same as this path, for example if you have a 'test' subdirectory directly after dir
, just don't name the static_path
'test'.
This serves files under ./src/public
.
It is in no way related to the directory that filehive will serve (dir
).
Default is "/filehive-internal/static"
.
Type: string
Example:
static_path: "/static"
The path for the upload route. Same instruction as in static_path
.
Default is "/filehive-internal/upload"
.
Type: string
Example:
upload_path: "/upload"
The path for the upload route. Same instruction as in static_path
.
Default is "/filehive-internal/login"
.
Type: string
Example:
login_path: "/login"
The path for the upload route. Same instruction as in static_path
.
Default is "/filehive-internal/forms/login"
.
Type: string
Example:
login_form_path: "/login-form"
The path for the upload route. Same instruction as in static_path
.
Default is "/filehive-internal/logout"
.
Type: string
Example:
logout_path: "/this-is-logout"
The path for the upload route. Same instruction as in static_path
.
Default is "/filehive-internal/delete"
.
Type: string
Example:
delete_path: "/this-is-delete"
The path for the upload route. Same instruction as in static_path
.
Default is "/filehive-internal/create-folder"
.
Type: string
Example:
create_folder_path: "/this-is-create"
An OCTAL integer representing the permissions in Linux. For example, 0o770
, not 770
.
The permission wouldn't be the same, and you would have bad surprises.
Default is 0o775
.
Type: number
Example:
folder_creation_mode: 0o770
the key of the cookie used for the user sessions.
Default is "FILEHIVE-SESSION"
.
Type: string
Example:
cookie_key: "my-custom-cookie-key"
The date format of the country provided for the autoindex dates.
The default is en-US
.
Type: string
Example:
date_format: "FR"
Your SSL certificate private key file.
You must provide the private_key and certificate keys for an HTTPS configuration.
Default is undefined
.
Type: string
Example:
private_key: "/etc/letsencrypt/live/example.com/privkey.pem"
Your SSL certificate file.
You must provide the private_key and certificate keys for an HTTPS configuration.
Default is undefined
.
Type: string
Example:
certificate : "/etc/letsencrypt/live/example.com/fullchain.pem"
The maximum allowed file size for uploads, in bytes.
The default value is undefined
, which means that there is no size limit.
Type number
Example:
file_upload_size_limit: 32212254720
-
The app's configuration is updated in real-time, allowing changes to permissions and other settings without requiring a restart. However, it's important to keep in mind that certain configuration keys, such as the
port
or FileHive routes, may require an app restart in order for changes to take effect, as they are not accessed on every instance. -
A user can only delete a file when he has the permission to view it (
autoindex
, alsoshow_hidden
if the file is hidden), and when he can also upload to the folder the file is in (upload
). -
The user running FileHive need read and write permissions under the directory it is located and under the
dir
provided. I recommend running it as systemd service (see below), withwww-data
user inside a child directory of/var/www/
and setting thedir
inside a child of/var/www/
too (the user should have the permissions, if not just give them to him).
To run the file as a systemd service, please follow these steps:
- Copy the configuration code below into a new file with the extension
.service
. For example, you can name itfilehive.service
(it is also in the repo under the same name).[Unit] Description=FileHive After=network.target [Service] User=www-data WorkingDirectory=/path/to/filehive/src/ ExecStart=/usr/bin/node app.js Restart=always [Install] WantedBy=multi-user.target
- Move the
.service
file to the/etc/systemd/system/
directory by running the following command:sudo mv filehive.service /etc/systemd/system/
- Reload the systemd daemon to pick up the new service:
sudo systemctl daemon-reload
- Enable the service to start on boot:
sudo systemctl enable filehive.service
- Start the service:
sudo systemctl start filehive.service
You can check the status of the service by running:
sudo systemctl status filehive.service
And you can stop the service by running:
sudo systemctl stop filehive.service
To improve the performance of FileHive in delivering files, it is highly recommended to use it with nginx as a reverse proxy.
If you choose to do so, you can add the following configuration to serve files in place of FileHive.
You can find the necessary file at ./filehive_nginx.conf
.
map $status $status_title {
400 "Bad Request";
401 "Unauthorized";
403 "Forbidden";
404 "Not Found";
405 "Method Not Allowed";
406 "Not Acceptable";
407 "Proxy Authentication Required";
408 "Request Timeout";
409 "Conflict";
410 "Gone";
411 "Length Required";
412 "Precondition Failed";
413 "Payload Too Large";
414 "URI Too Long";
415 "Unsupported Media Type";
416 "Range Not Satisfiable";
417 "Expectation Failed";
418 "I'm a teapot";
421 "Misdirected Request";
422 "Unprocessable Entity";
423 "Locked";
425 "Too Early";
426 "Upgrade Required";
428 "Precondition Required";
429 "Too Many Requests";
431 "Request Header Fields Too Large";
451 "Unavailable For Legal Reasons";
500 "Internal Server Error";
501 "Not Implemented";
502 "Bad Gateway";
503 "Service Unavailable";
504 "Gateway Timeout";
505 "HTTP Version Not Supported";
506 "Variant Also Negotiates";
507 "Insufficient Storage";
508 "Loop Detected";
510 "Not Extended";
511 "Network Authentication Required";
default "Unknown Error";
}
map $status $status_message {
400 "The server cannot or will not process the request due to an apparent client error.";
401 "The client must authenticate itself to get the requested response.";
403 "The server understood the request, but is refusing to fulfill it. You probably are missing permissions.";
404 "The server cannot find the requested resource.";
405 "The method specified in the request is not allowed for the resource identified by the URI.";
406 "The resource identified by the request is only capable of generating response entities that have content characteristics not acceptable according to the accept headers sent in the request.";
407 "The client must first authenticate itself with the proxy.";
408 "The server timed out waiting for the request.";
409 "The request could not be completed due to a conflict with the current state of the resource.";
410 "The requested resource is no longer available and will not be available again.";
411 "The request did not specify the length of its content, which is required by the requested resource.";
412 "The server does not meet one of the preconditions that the requester put on the request.";
413 "The server cannot process the request because the request payload is too large.";
414 "The URI requested by the client is too long.";
415 "The server cannot process the request because the media type requested by the client is not supported.";
416 "The client has asked for a portion of the file (byte serving), but the server cannot supply that portion.";
417 "The server cannot meet the requirements of the Expect request-header field.";
418 "This code was defined in 1998 as one of the traditional IETF April Fools' jokes.";
421 "The request was directed at a server that is not able to produce a response.";
422 "The request was well-formed but was unable to be followed due to semantic errors.";
423 "The resource that is being accessed is locked.";
425 "The server is unwilling to risk processing a request that might be replayed.";
426 "The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header field.";
428 "The origin server requires the request to be conditional.";
429 "The user has sent too many requests in a given amount of time.";
431 "The server is unwilling to process the request because its header fields are too large.";
451 "The server is denying access to the resource as a consequence of a legal demand.";
500 "The server encountered an unexpected condition that prevented it from fulfilling the request.";
501 "The server does not support the functionality required to fulfill the request.";
502 "The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request.";
503 "The server is currently unable to handle the request due to a temporary overload or maintenance of the server.";
504 "The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI.";
505 "The server does not support the HTTP protocol version used in the request.";
506 "The server has an internal configuration error: the chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process.";
507 "The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request.";
508 "The server detected an infinite loop while processing the request.";
510 "The client needs to update to a newer version of the protocol to access the requested resource.";
511 "The client needs to authenticate to gain network access.";
default "Sorry, something weird hapened.";
}
server {
# Those variables are needed for the configuration, edit them to fit your config if edited.
# please note that you will need to replace your value of static_path (if edited) in the location block because nginx does not support variable in location block.
# DO NOT ADD A TRAILING SLASH.
set $static_path "/filehive-internal/static";
set $login_path "/filehive-internal/login";
set $filehive_ip "127.0.0.1";
set $filehive_port 80;
# 0 disable the check, pass it in MegaBytes, different from filehive that is is Bytes
set $filehive_max_upload_file_size 0;
# The directory where filehive files are located (no trailing slash)
set $filehive_installation_dir "/path/to/filehive";
# The path of the dir in your filehive config
set $filehive_dir "/path/to/dir/";
listen 443 ssl ;
listen [::]:443 ;
server_name example.com;
# Path to your ssl_certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
access_log /path/to/access.log;
error_log path/to/error.log;
root $filehive_dir;
client_max_body_size $filehive_max_upload_file_sizeM;
# Location block for the protected directory
location / {
if (-f $request_filename) {
rewrite ^ /__internal$uri last;
}
proxy_pass http://$filehive_ip:$filehive_port;
}
location /__internal {
rewrite ^/__internal(?<realurl>/.*)$ $realurl break;
auth_request /auth;
auth_request_set $auth_status $upstream_status;
try_files $uri =404;
}
error_page 400 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 /nginx-error-template.html;
error_page 401 /nginx-401-error-template.html;
location /nginx-401-error-template.html {
add_header Set-Cookie "lastVisited=$realurl;Path=/" always;
ssi on;
internal;
auth_basic off;
root $filehive_installation_dir/src/public/errors;
}
location /nginx-error-template.html {
ssi on;
internal;
auth_basic off;
root $filehive_installation_dir/src/public/errors;
}
location /filehive-internal/static {
alias $filehive_installation_dir/src/public;
}
# Location block for the auth endpoint
location = /auth {
# Define the authentication server
internal;
proxy_pass http://$filehive_ip:$filehive_port$request_uri;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header Host $http_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;
proxy_set_header If-Modified-Since "";
}
}
To use FileHive, simply navigate to the root URL of the server.
FileHive is licensed under the MIT License. See the LICENSE file for more information.