Compare commits
10 commits
d11e68a85b
...
0d9801b200
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d9801b200 | |||
| 08a21fd63d | |||
| 827a892568 | |||
| 8ce7a5e7eb | |||
| e43b7f3550 | |||
| 2bd0a2db20 | |||
| f1992596bc | |||
| 281eca0bb0 | |||
| 2e4270657c | |||
| f813682d33 |
7 changed files with 38 additions and 55 deletions
|
|
@ -1,10 +1,12 @@
|
|||
FROM python:3.11-rc-alpine
|
||||
|
||||
ENV cloud_name raincloud
|
||||
ENV num_workers 5
|
||||
ENV worker_timeout 300
|
||||
|
||||
COPY . /tmp/raincloud
|
||||
|
||||
RUN apk add redis
|
||||
RUN python -m venv /opt/venv
|
||||
RUN . /opt/venv/bin/activate && cd /tmp/raincloud && python -m pip install .
|
||||
RUN . /opt/venv/bin/activate && python -m pip install gunicorn
|
||||
|
|
@ -13,4 +15,4 @@ RUN rm -rf /tmp/raincloud
|
|||
|
||||
EXPOSE 8000/tcp
|
||||
|
||||
ENTRYPOINT . /opt/venv/bin/activate && gunicorn --timeout ${worker_timeout} --bind=0.0.0.0:8000 "raincloud:create_app(base_path='/var/www/raincloud',cloud_name='${cloud_name}')"
|
||||
ENTRYPOINT redis-server & echo $RANDOM$RANDOM | base64 > /var/raincloud_secret_key && . /opt/venv/bin/activate && gunicorn --bind=0.0.0.0:8000 --workers ${num_workers} --timeout ${worker_timeout} "raincloud:create_app(base_path='/var/www/raincloud', secret_key_path='/var/raincloud_secret_key', cloud_name='${cloud_name}')"
|
||||
49
README.org
49
README.org
|
|
@ -11,7 +11,7 @@
|
|||
*Features*
|
||||
|
||||
- No users, just password protectable dynamic HTTP routes
|
||||
- No database backend, just a flat directory structure
|
||||
- Routes are defined by a flat directory structure
|
||||
- Permissions per route individually configurable via plain-text files
|
||||
|
||||
** Example
|
||||
|
|
@ -50,47 +50,39 @@
|
|||
First set up a [[https://redis.io/][Redis]] server which will be used for server-side session caching.
|
||||
Then a WSGI server like [[https://gunicorn.org/][Gunicorn]] can be used to serve /raincloud/ for example like this:
|
||||
|
||||
: $ gunicorn "raincloud:create_app(base_path='public', secret_key='i_am_a_key', redis_url='redis://127.0.0.1:6379/0')"
|
||||
: $ gunicorn "raincloud:create_app(base_path='public', secret_key_path='secret_key', redis_url='redis://127.0.0.1:6379/0')"
|
||||
|
||||
*** NixOS
|
||||
|
||||
This repository is also a [[https://nixos.wiki/wiki/Flakes][Nix Flake]] which provides a [[https://nixos.org/][NixOS]] module.
|
||||
It requres a running instance of a [[https://search.nixos.org/options?query=services.redis.servers][Redis server]].
|
||||
It requires a running instance of a [[https://search.nixos.org/options?query=services.redis.servers][Redis server]].
|
||||
A minimal /raincloud/ instance can be setup for example like this:
|
||||
|
||||
#+begin_src nix
|
||||
raincloud.nixosModule {
|
||||
# Redis
|
||||
services.redis.servers."raincloud" = {
|
||||
enable = true;
|
||||
databases = 1;
|
||||
user="raincloud";
|
||||
};
|
||||
|
||||
# Raincloud
|
||||
services.raincloud = {
|
||||
enable = true;
|
||||
basePath = "/var/lib/raincloud";
|
||||
secretKey = "i_am_a_key";
|
||||
redisUrl = "unix:/run/redis-raincloud/redis.sock";
|
||||
secretKeyPath = "/var/lib/raincloud/secret_key";
|
||||
redisUrl = "unix:/run/redis-raincloud/redis.sock?db=0";
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
||||
All configuration options are:
|
||||
|
||||
| Option | Description | Type | Default value | Example |
|
||||
|-----------------+---------------------------------------------------------------+-------+----------------------------+-------------------------------|
|
||||
| =address= | Bind address of the server | =str= | =127.0.0.1= | =0.0.0.0= |
|
||||
| =port= | Port on which the server listens | =int= | =8000= | =5000= |
|
||||
| =user= | User under which the server runs | =str= | =raincloud= | =alice= |
|
||||
| =group= | Group under which the server runs | =str= | =raincloud= | =users= |
|
||||
| =cloudName= | Name of the raincloud | =str= | =raincloud= | =bobsCloud= |
|
||||
| =basePath= | Base path of the raincloud | =str= | | =/var/lib/raincloud= |
|
||||
| =secretKey= | Flask secret key | =str= | | =i_am_a_key= |
|
||||
| =redisUrl= | URL of Redis database | =str= | =redis://127.0.0.1:6379/0= | =redis://my_db_server:6379/0= |
|
||||
| =numWorkers= | Number of Gunicorn workers (recommendation is: 2 x #CPUs + 1) | =int= | =5= | =17= |
|
||||
| =workerTimeout= | Gunicorn worker timeout | =int= | =300= | =360= |
|
||||
| Option | Description | Type | Default value | Example |
|
||||
|-----------------+---------------------------------------------------------------+-------+----------------------------+----------------------------------------|
|
||||
| =address= | Bind address of the server | =str= | =127.0.0.1= | =0.0.0.0= |
|
||||
| =port= | Port on which the server listens | =int= | =8000= | =5000= |
|
||||
| =user= | User under which the server runs | =str= | =raincloud= | =alice= |
|
||||
| =group= | Group under which the server runs | =str= | =raincloud= | =users= |
|
||||
| =cloudName= | Name of the raincloud | =str= | =raincloud= | =bobsCloud= |
|
||||
| =basePath= | Base path of the raincloud | =str= | | =/var/lib/raincloud= |
|
||||
| =secretKeyPath= | Path to file containing Flask secret key | =str= | | =/var/lib/raincloud/secret_key= |
|
||||
| =redisUrl= | URL of Redis database | =str= | =redis://127.0.0.1:6379/0= | =unix:/run/redis-raincloud/redis.sock?db=0= |
|
||||
| =numWorkers= | Number of Gunicorn workers (recommendation is: 2 x #CPUs + 1) | =int= | =5= | =17= |
|
||||
| =workerTimeout= | Gunicorn worker timeout | =int= | =300= | =360= |
|
||||
|
||||
*** Docker
|
||||
|
||||
|
|
@ -108,20 +100,19 @@
|
|||
|
||||
: $ docker run -p <local_port>:8000 -v <path_to_local_base_directory>:/var/www/raincloud -e "cloud_name=podcloud" raincloud:latest
|
||||
|
||||
Similarly the environment variable =worker_timeout= can be set to increase the Gunicorn worker timeout in seconds.
|
||||
It's default value is =300=.
|
||||
The environment variables =num_workers= (default: =5=) and =worker_timeout= (default: =300=) can be set in the same way to set the number of Gunicorn workers and their timeout in seconds.
|
||||
|
||||
** Configuration
|
||||
|
||||
/raincloud/ provides four configuration options which can be passed to =raincloud.create_app()=:
|
||||
|
||||
- =base_path= :: Base path of the raincloud
|
||||
- =secret_key= :: Flask secret key
|
||||
- =secret_key_path= :: Path to file containing Flask secret key
|
||||
- =redis_url= :: URL of redis database (default: =redis://127.0.0.1:6379/0=)
|
||||
- =cloud_name= :: Cloud name (default: =raincloud=)
|
||||
|
||||
Set them for example like this:
|
||||
: >>> app = raincloud.create_app(base_path='/home/alice/public', secret_key='i_am_a_key', redis_url='redis://127.0.0.1:6379/0', cloud_name='raincloud')
|
||||
: >>> app = raincloud.create_app(base_path='/home/alice/public', secret_key_path='/var/lib/raincloud/secret_key', redis_url='redis://127.0.0.1:6379/0', cloud_name='raincloud')
|
||||
|
||||
*** =rc.conf=
|
||||
:properties:
|
||||
|
|
|
|||
13
flake.nix
13
flake.nix
|
|
@ -59,17 +59,20 @@
|
|||
|
||||
basePath = mkOption {
|
||||
type = types.str;
|
||||
example = "/var/lib/raincloud";
|
||||
description = "Base path of the raincloud";
|
||||
};
|
||||
|
||||
secretKey = mkOption {
|
||||
secretKeyPath = mkOption {
|
||||
type = types.str;
|
||||
description = "Flask secret key";
|
||||
example = "/var/lib/raincloud/secret_key";
|
||||
description = "Path to file containing Flask secret key";
|
||||
};
|
||||
|
||||
redisUrl = mkOption {
|
||||
type = types.str;
|
||||
default = "redis://127.0.0.1:6379/0";
|
||||
example = "unix:/run/redis-raincloud/redis.sock";
|
||||
description = "URL of Redis database";
|
||||
};
|
||||
|
||||
|
|
@ -115,10 +118,10 @@
|
|||
PermissionsStartOnly = true;
|
||||
|
||||
ExecStart = ''
|
||||
${gunicorn}/bin/gunicorn "raincloud:create_app('${cfg.basePath}', '${cfg.secretKey}', '${cfg.redisUrl}', '${cfg.cloudName}')" \
|
||||
${gunicorn}/bin/gunicorn "raincloud:create_app('${cfg.basePath}', '${cfg.secretKeyPath}', '${cfg.redisUrl}', '${cfg.cloudName}')" \
|
||||
--bind=${cfg.address}:${toString cfg.port} \
|
||||
--workers ${toString cfg.numWorkers} \
|
||||
--timeout ${toString cfg.workerTimeout} \
|
||||
--bind=${cfg.address}:${toString cfg.port}
|
||||
--timeout ${toString cfg.workerTimeout}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,12 +18,16 @@ import werkzeug
|
|||
|
||||
|
||||
def create_app(
|
||||
base_path, secret_key, redis_url="redis://127.0.0.1:6379/0", cloud_name="raincloud"
|
||||
base_path,
|
||||
secret_key_path,
|
||||
redis_url="redis://127.0.0.1:6379/0",
|
||||
cloud_name="raincloud",
|
||||
):
|
||||
|
||||
# Create app
|
||||
app = Flask(__name__)
|
||||
app.config["SECRET_KEY"] = secret_key
|
||||
with open(secret_key_path, "r") as secret_key_file:
|
||||
app.config["SECRET_KEY"] = secret_key_file.readline()
|
||||
|
||||
# Create handlers
|
||||
dh = DirectoryHandler(base_path)
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#1a1a1a">
|
||||
<circle cx="64.541" cy="98.952" r="12.752"/>
|
||||
<circle cx="82.328" cy="93.285" r="18.419"/>
|
||||
<circle cx="99.921" cy="96.465" r="15.238"/>
|
||||
<rect x="64.541" y="107.76" width="35.38" height="3.9457"/>
|
||||
<g transform="translate(1.3938 -8.511)">
|
||||
<rect transform="rotate(30)" x="119.65" y="72.299" width="4.5931" height="22.966" rx="1.2522" ry="1.2522"/>
|
||||
<rect transform="rotate(30)" x="129.01" y="66.893" width="4.5931" height="22.966" rx="1.2522" ry="1.2522"/>
|
||||
<rect transform="rotate(30)" x="138.38" y="61.487" width="4.5931" height="22.966" rx="1.2522" ry="1.2522"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 822 B |
|
|
@ -1,2 +0,0 @@
|
|||
flask
|
||||
redis
|
||||
2
setup.py
2
setup.py
|
|
@ -6,5 +6,5 @@ setup(
|
|||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=["flask"],
|
||||
install_requires=["flask", "redis"],
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue