--- orphan: true --- ### 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 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.