Install on FreeBSD using packages as well as Gunicorn, supervisord and nginx
We have to install some stuff.
pkg install py38-Flask
pkg install py38-Flask-Flatpages
pkg install py38-Flask-sqlalchemy
pkg install py38-Flask-migrate
pkg install py38-Flask-WTF
to run ResearchNotes. We also need to serve it using Gunicorn, supervisor and nginix
pkg install py38-gunicron
pkg install py38-supervisor
pkg install nginx
Remember, you need your database engine binding. Sqlite3 might already be around but the ones for other stuff might missing (see SQLAlchemy). It depends also, what else is running on the same system.
pkg install py38-sqlite3
After installing nginix, thw user www and grpoup www should exist. We should use it for also installing ResearchNotes. This is the only packages, we want to install by pip. In this way, all common packages will be updated by the package manager and we do not have to take care of the local environment. There are some pro and cons to this - e.g. the python environments mix. But if we have a dedicated server, this should not be a problem because not much other stuff will run in parallel (best chance are things like fail2ban and/or a samba server).
pkg install py38-pip
Now, we need to install the app. But we do not want to run it in root context. So, we should create a user researchnotes (or similar).
adduser
we change into the user contest and install Researchnotes.
su researchnotes
pip install ResearchNotes-1.x.x-py3-none-any.whl --user
This will install the package into the local user directory. We will have to make it accessable later for nginix. It also will need to include as a path for setting up the Gunicorn app.
We can use a Gunicorn app as follow
import sys
sys.path.append('/home/researchnotes/.local/lib/python3.8/site-packages/')
from werkzeug.middleware.proxy_fix import ProxyFix
from ResearchNotes import create_app
app_wsgi = create_app("/usr/local/www/researchnotes/config.py")
app = ProxyFix(app_wsgi, x_for=1, x_host=1)
if __name__ == "__main__":
app.run(host='0.0.0.0')
Test run the app
python3.8 wsgi.py
If work, test run with Gunicorn
gunicorn -b <your_net_workInterface> wsgi:app
Finally, we set up supervisord with it .conf:
; Sample supervisor config file.
[supervisord]
logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
pidfile=/var/run/supervisor/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
[program:researchnotes]
environment= PYTHONPATH=/root/.local/lib/python3.8/site-packages/ResearchNotes/
command=/usr/local/bin/gunicorn w=4 --preload -b localhost:8000 wsgi:app
directory=/usr/local/www/researchnotes
user=researchnotes
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
One has to include the paramter –preload. Otherwise, the app has different session keys and cannot switch between workers. ALso, sqlite3 access shown some problems (at least under Linux).
Finally, we have to do a chmod go=+r+w+x for the home directory of researchnotes. Otherwise, nginx cannot deliver the static files. We start everything with setting up nginx.
user www;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
# listen on port 443 (https)
listen 80;
server_name wintermute.ifi.unicamp.br;
# location of the self-signed SSL certificate
#ssl_certificate /home/ubuntu/microblog/certs/cert.pem;
#ssl_certificate_key /home/ubuntu/microblog/certs/key.pem;
# write access and error logs to /var/log
access_log /var/log/nginx/researchnotes_access.log;
error_log /var/log/nginx/researchnotes_error.log;
#Increase uplaod size to 100 MB as we have to get measurements uploaded.
client_max_body_size 100M;
# Use secure headers to avoid XSS and many other things
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "no-referrer";
add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' 'unsafe-eval'; frame-src 'self'; object-src 'self'";
location / {
# forward application requests to the gunicorn server
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ^~ /static {
# handle static files directly, without forwarding to the application
alias /home/researchnotes/.local/lib/python3.8/site-packages/ResearchNotes/static;
expires 30d;
}
}
}
You will have to adapt settings in your firewall to let the outside talk to nginx. On the other hand, you want to block access to the Gunicorn socket (which should anyway be localhost) or your database.