diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a7430779..27c6cbd8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,10 +17,12 @@ Changed ======= - Logged admin can see any project (#262) +- Better install doc (#275) Added ===== +- ``ihatemoney generate-config`` to give working examples of config files (#275) - Statistics tab (#257) - Python3.6 support (#259) - ALLOW_PUBLIC_PROJECT_CREATION setting (#262) diff --git a/conf/apache-vhost.conf b/conf/apache-vhost.conf deleted file mode 100644 index 1a84e7f7..00000000 --- a/conf/apache-vhost.conf +++ /dev/null @@ -1,18 +0,0 @@ - - ServerAdmin admin@example.com - ServerName ihatemoney.example.com - # Uncomment the python-home option if you use a virtualenv - WSGIDaemonProcess ihatemoney user=www-data group=www-data threads=5 python-path=/path/to/ihatemoney/ihatemoney # python-home=/path/to/your/venv - WSGIScriptAlias / /path/to/ihatemoney/ihatemoney/wsgi.py - ErrorLog /var/log/apache2/ihatemoney.example.com_error.log - CustomLog /var/log/apache2/ihatemoney.example.com_access.log combined - - WSGIProcessGroup ihatemoney - WSGIApplicationGroup %{GLOBAL} - Order deny,allow - Allow from all - -# Alias value may be some messy path, within python libs. -# You may want to use "find $VIRTUAL_ENV -path */ihatemoney*/static" to find it. -Alias /static/ /path/to/ihatemoney/ihatemoney/static/ - diff --git a/conf/gunicorn.conf.py b/conf/gunicorn.conf.py deleted file mode 100644 index 017a6709..00000000 --- a/conf/gunicorn.conf.py +++ /dev/null @@ -1,7 +0,0 @@ -backlog = 2048 -daemon = False -debug = True -workers = 3 -logfile = "/path/to/your/app/ihatemoney.gunicorn.log" -loglevel = "info" -bind = "unix:/path/to/your/app/ihatemoney.gunicorn.sock" diff --git a/conf/supervisord.conf b/conf/supervisord.conf deleted file mode 100644 index 8d3ac70e..00000000 --- a/conf/supervisord.conf +++ /dev/null @@ -1,6 +0,0 @@ -[program:ihatemoney] -command=/path/to/your/app/venv/bin/gunicorn -c /etc/ihatemoney/gunicorn.conf.py ihatemoney.wsgi:application -user=www -autostart=true -autorestart=true -redirect_stderr=True diff --git a/docs/installation.rst b/docs/installation.rst index 3f2c6534..9fd96b77 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -18,6 +18,8 @@ it will work without if you prefer. If wondering about the backend, SQLite is the simplest and will work fine for most small to medium setups. +.. note:: If curious, source config templates can be found in the `project git repository `_. + Prepare virtualenv (recommended) ================================ @@ -57,28 +59,56 @@ Now, if you want to deploy it on your own server, you have many options. Two of them are documented at the moment. *Of course, if you want to contribute another configuration, feel free to open a -pull-request against this repository!*. +pull-request against this repository!* + + +Whatever your installation option is… +-------------------------------------- + +1. Initialize the ihatemoney directories:: + + mkdir /etc/ihatemoney /var/lib/ihatemoney + +2. Generate settings:: + + ihatemoney generate-config ihatemoney.cfg > /etc/ihatemoney/ihatemoney.cfg + chmod 740 /etc/ihatemoney/ihatemoney.cfg + +You probably want to adjust `/etc/ihatemoney/ihatemoney.cfg` contents, you may +do it later, see `Configuration`_. + With Apache and mod_wsgi ------------------------ -1. Install Apache and mod_wsgi - libapache2-mod-wsgi(-py3) for Debian based and mod_wsgi for RedHat based distributions - -2. Create an Apache virtual host based on the sample configuration file in `conf/apache-vhost.conf` -3. Adapt it to your paths and specify your virtualenv path if you use one +1. Fix permissions (considering `www-data` is the user running apache):: + + chgrp www-data /etc/ihatemoney/ihatemoney.cfg + chown www-data /var/lib/ihatemoney + +2. Install Apache and mod_wsgi - libapache2-mod-wsgi(-py3) for Debian based and mod_wsgi for RedHat based distributions - +3. Create an Apache virtual host, the command ``ihatemoney generate-config apache-vhost.conf`` will output a good starting point (read and adapt it) 4. Activate the virtual host if needed and restart Apache With Nginx, Gunicorn and Supervisord ------------------------------------ -.. note:: For the 3 configuration files mentioned below, you will need to fix - the paths to reflect yours. +1. Create a dedicated unix user (here called `ihatemoney`), required dirs, and fix permissions:: -1. Copy *conf/gunicorn.conf.py* to */etc/ihatemoney/gunicorn.conf.py* -2. Copy *conf/supervisord.conf* to */etc/supervisor/conf.d/ihatemoney.conf* -3. Copy *conf/nginx.conf* with your nginx vhosts [#nginx-vhosts]_ -4. Reload both nginx and supervisord. It should be working ;) + useradd ihatemoney + chown ihatemoney /var/lib/ihatemoney/ + chgrp ihatemoney /etc/ihatemoney/ihatemoney.cfg -Don't forget to set the right permission for your files ! +2. Create gunicorn config file :: + + ihatemoney generate-config gunicorn.conf.py > /etc/ihatemoney/gunicorn.conf.py + +3. Create supervisor config file :: + + ihatemoney generate-config supervisord.conf > /etc/supervisor/conf.d/ihatemoney.conf + +4. Copy (and adapt) output of ``ihatemoney generate-config conf/nginx.conf`` with your nginx vhosts [#nginx-vhosts]_ +5. Reload both nginx and supervisord. It should be working ;) .. [#nginx-vhosts] typically, */etc/nginx/conf.d/* or */etc/nginx/sites-available*, depending on your distribution. @@ -90,48 +120,47 @@ ihatemoney relies on a configuration file. If you run the application for the first time, you will need to take a few moments to configure the application properly. -.. warning:: You **must** customize the ``SECRET_KEY`` on a production installation. +Defaults given here, are those for development mode. To know defaults on your +deployed instance, simply look at your *ihatemoney.cfg*. -+-------------------------------+---------------------------------+----------------------------------------------------------------------------------+ -| Setting name | Default | What does it do? | -+===============================+=================================+==================================================================================+ -| SQLALCHEMY_DATABASE_URI | ``sqlite:///tmp/ihatemoney.db`` | Specifies the type of backend to use and its location. More information | -| | | on the format used can be found on `the SQLAlchemy documentation | -| | | `_. | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -| SECRET_KEY | ``tralala`` | The secret key used to encrypt the cookies. **This needs to be changed**. | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -| MAIL_DEFAULT_SENDER | ``("Budget manager", | A python tuple describing the name and email adress to use when sending | -| | "budget@notmyidea.org")`` | emails. | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -| ACTIVATE_DEMO_PROJECT | ``True`` | If set to `True`, a demo project will be available on the frontpage. | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -| | | Hashed password to access protected endpoints. If left empty, all administrative | -| ADMIN_PASSWORD | ``""`` | tasks are disabled. | -| | | To generate the proper password HASH, use ``ihatemoney generate_password_hash`` | -| | | and copy the output into the value of *ADMIN_PASSWORD*. | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -| ALLOW_PUBLIC_PROJECT_CREATION | ``True`` | If set to `True`, everyone can create a project without entering the admin password | -| | | If set to `False`, the password needs to be entered (and as such, defined in the | -| | | settings). | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -| ACTIVATE_ADMIN_DASHBOARD | ``False`` | If set to `True`, the dashboard will become accessible entering the admin password | -| | | If set to `True`, a non empty ADMIN_PASSWORD needs to be set | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -| APPLICATION_ROOT | ``""`` | If empty, ihatemoney will be served at domain root (e.g: *http://domain.tld*), if set | -| | | to ``"foo"``, it will be served from a "folder" (e.g: *http://domain.tld/foo*) | -+-------------------------------+---------------------------+----------------------------------------------------------------------------------------+ -In a production environment ---------------------------- ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| Setting name | Default | What does it do? | ++===============================+=================================+========================================================================================+ +| SQLALCHEMY_DATABASE_URI | ``sqlite:///tmp/ihatemoney.db`` | Specifies the type of backend to use and its location. More information on the | +| | | format used can be found on `the SQLAlchemy documentation`_. | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| SECRET_KEY | ``tralala`` | The secret key used to encrypt the cookies. `ihatemoney conf-example ihatemoney.cfg` | +| | | sets it to something random, which is good. | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| MAIL_DEFAULT_SENDER | ``("Budget manager", | A python tuple describing the name and email adress to use when sending | +| | "budget@notmyidea.org")`` | emails. | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| ACTIVATE_DEMO_PROJECT | ``True`` | If set to `True`, a demo project will be available on the frontpage. | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| | | Hashed password to access protected endpoints. If left empty, all administrative | +| ADMIN_PASSWORD | ``""`` | tasks are disabled. | +| | | To generate the proper password HASH, use ``ihatemoney generate_password_hash`` | +| | | and copy the output into the value of *ADMIN_PASSWORD*. | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| ALLOW_PUBLIC_PROJECT_CREATION | ``True`` | If set to `True`, everyone can create a project without entering the admin password | +| | | If set to `False`, the password needs to be entered (and as such, defined in the | +| | | settings). | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| ACTIVATE_ADMIN_DASHBOARD | ``False`` | If set to `True`, the dashboard will become accessible entering the admin password | +| | | If set to `True`, a non empty ADMIN_PASSWORD needs to be set | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ +| APPLICATION_ROOT | ``""`` | If empty, ihatemoney will be served at domain root (e.g: *http://domain.tld*), if set | +| | | to ``"foo"``, it will be served from a "folder" (e.g: *http://domain.tld/foo*) | ++-------------------------------+---------------------------------+----------------------------------------------------------------------------------------+ -Make a copy of ``ihatemoney/default_settings.py`` and name it ``ihatemoney.cfg``. -Then adjust the settings to your needs and move this file to -``/etc/ihatemoney/ihatemoney.cfg``. +.. _the SQLAlchemy documentation: http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls -This is the default path of the settings but you can also place it -elsewhere and pass the configuration file path to the application using -the IHATEMONEY_SETTINGS_FILE_PATH environment variable. +Using an alternate settings path +-------------------------------- + +You can put your settings file where you want, and pass its path to the +application using the ``IHATEMONEY_SETTINGS_FILE_PATH`` environment variable. e.g.:: diff --git a/ihatemoney/conf-templates/apache-vhost.conf.j2 b/ihatemoney/conf-templates/apache-vhost.conf.j2 new file mode 100644 index 00000000..cb0167f5 --- /dev/null +++ b/ihatemoney/conf-templates/apache-vhost.conf.j2 @@ -0,0 +1,19 @@ + + ServerAdmin admin@example.com # CUSTOMIZE + ServerName ihatemoney.example.com # CUSTOMIZE + + WSGIDaemonProcess ihatemoney user=www-data group=www-data threads=5 python-path={{ pkg_path }} {% if venv_path %}python-home={{ venv_path }}{% endif %} + WSGIScriptAlias / {{ pkg_path }}/wsgi.py + + ErrorLog /var/log/apache2/ihatemoney.example.com_error.log + CustomLog /var/log/apache2/ihatemoney.example.com_access.log combined + + + WSGIProcessGroup ihatemoney + WSGIApplicationGroup %{GLOBAL} + Order deny,allow + Allow from all + + + Alias /static/ {{ pkg_path }}/static/ + diff --git a/ihatemoney/conf-templates/gunicorn.conf.py.j2 b/ihatemoney/conf-templates/gunicorn.conf.py.j2 new file mode 100644 index 00000000..2c4492de --- /dev/null +++ b/ihatemoney/conf-templates/gunicorn.conf.py.j2 @@ -0,0 +1,8 @@ +backlog = 2048 +daemon = False +debug = True +workers = 3 +# log to stdout, +logfile = "-" # Is the default setting for gunicorn>=20 +loglevel = "info" +bind = "unix:/tmp/ihatemoney.gunicorn.sock" diff --git a/ihatemoney/conf-templates/ihatemoney.cfg.j2 b/ihatemoney/conf-templates/ihatemoney.cfg.j2 new file mode 100644 index 00000000..5dfb9d47 --- /dev/null +++ b/ihatemoney/conf-templates/ihatemoney.cfg.j2 @@ -0,0 +1,36 @@ +# You can find more information about what these settings mean in the +# documentation, available online at +# http://ihatemoney.readthedocs.io/en/latest/installation.html#configuration + +# Turn this on if you want to have more output on what's happening under the +# hood. DO NOT TURN IT ON IN PRODUCTION. +DEBUG = False + +# The database URI, reprensenting the type of database and how to connect to it. +# Enter an absolute path here. +SQLALCHEMY_DATABASE_URI = 'sqlite:///var/lib/ihatemoney/ihatemoney.sqlite' +SQLACHEMY_ECHO = DEBUG + +# Will likely become the default value in flask-sqlalchemy >=3 ; could be removed +# then: +SQLALCHEMY_TRACK_MODIFICATIONS = False + +# This secret key is random and auto-generated, it protects cookies and user sessions +SECRET_KEY = "{{ secret_key }}" + +# A python tuple describing the name and email adress of the sender of the mails. +MAIL_DEFAULT_SENDER = ("Budget manager", "budget@notmyidea.org") # CUSTOMIZE + +# If set to True, a demonstration project will be activated. +ACTIVATE_DEMO_PROJECT = True + +# If not empty, the specified password must be entered to create new projects. +# DO NOT enter the password in cleartext. Generate a password hash with +# "ihatemoney generate_password_hash" instead. +ADMIN_PASSWORD = "" + +# If set to True (default value) anyone can create a new project. +ALLOW_PUBLIC_PROJECT_CREATION = True + +# If set to True, an administration dashboard is available. +ACTIVATE_ADMIN_DASHBOARD = False diff --git a/conf/nginx.conf b/ihatemoney/conf-templates/nginx.conf.j2 similarity index 67% rename from conf/nginx.conf rename to ihatemoney/conf-templates/nginx.conf.j2 index 0fe26f02..42b45fc0 100644 --- a/conf/nginx.conf +++ b/ihatemoney/conf-templates/nginx.conf.j2 @@ -1,11 +1,9 @@ server { - server_name yourur; + server_name ihatemoney.example.com; # CUSTOMIZE keepalive_timeout 5; location /static/ { - # Alias value may be some messy path, within python libs. - # You may want to use "find $VIRTUAL_ENV -path */ihatemoney*/static" to find it. - alias /path/to/app/ihatemoney/static/; + alias {{ pkg_path }}/static/; } location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -26,5 +24,5 @@ server { } upstream ihatemoney_backend { - server unix:/path/to/app/ihatemoney.gunicorn.sock; + server unix:/tmp/ihatemoney.gunicorn.sock; } diff --git a/ihatemoney/conf-templates/supervisord.conf.j2 b/ihatemoney/conf-templates/supervisord.conf.j2 new file mode 100644 index 00000000..fa16c0cf --- /dev/null +++ b/ihatemoney/conf-templates/supervisord.conf.j2 @@ -0,0 +1,6 @@ +[program:ihatemoney] +command={{ venv_path }}/bin/gunicorn -c /etc/ihatemoney/gunicorn.conf.py ihatemoney.wsgi:application +user=ihatemoney +autostart=true +autorestart=true +redirect_stderr=true diff --git a/ihatemoney/default_settings.py b/ihatemoney/default_settings.py index c7ce2973..6033d0ab 100644 --- a/ihatemoney/default_settings.py +++ b/ihatemoney/default_settings.py @@ -1,37 +1,10 @@ -# You can find more information about what these settings mean in the -# documentation, available online at -# http://ihatemoney.readthedocs.io/en/latest/installation.html#configuration - -# Turn this on if you want to have more output on what's happening under the -# hood. -DEBUG = False - -# The database URI, reprensenting the type of database and how to connect to it. -# Enter an absolute path here. +# Verbose and documented settings are in conf-templates/ihatemoney.cfg.j2 +DEBUG = SQLACHEMY_ECHO = False SQLALCHEMY_DATABASE_URI = 'sqlite:////tmp/ihatemoney.db' -SQLACHEMY_ECHO = DEBUG - -# Will likely become the default value in flask-sqlalchemy >=3 ; could be removed -# then: SQLALCHEMY_TRACK_MODIFICATIONS = False - -# You need to change this secret key, otherwise bad things might happen to your -# users. SECRET_KEY = "tralala" - -# A python tuple describing the name and email adress of the sender of the mails. MAIL_DEFAULT_SENDER = ("Budget manager", "budget@notmyidea.org") - -# If set to True, a demonstration project will be activated. ACTIVATE_DEMO_PROJECT = True - -# If not empty, the specified password must be entered to create new projects. -# DO NOT enter the password in cleartext. Generate a password hash with -# "ihatemoney generate_password_hash" instead. ADMIN_PASSWORD = "" - -# If set to True (default value) anyone can create a new project. ALLOW_PUBLIC_PROJECT_CREATION = True - -# If set to True, an administration dashboard is available. ACTIVATE_ADMIN_DASHBOARD = False diff --git a/ihatemoney/manage.py b/ihatemoney/manage.py index 6f63a98c..c1821c59 100755 --- a/ihatemoney/manage.py +++ b/ihatemoney/manage.py @@ -1,8 +1,13 @@ #!/usr/bin/env python +import os +import pkgutil +import random from getpass import getpass -from flask_script import Manager, Command + +from flask_script import Manager, Command, Option from flask_migrate import Migrate, MigrateCommand +from jinja2 import Template from werkzeug.security import generate_password_hash from ihatemoney.run import create_app @@ -18,6 +23,38 @@ class GeneratePasswordHash(Command): print(generate_password_hash(password)) +class ConfigTemplate(Command): + def get_options(self): + return [ + Option('config_file', choices=[ + 'ihatemoney.cfg', + 'apache-vhost.conf', + 'gunicorn.conf.py', + 'supervisord.conf', + 'nginx.conf', + ]), + ] + + @staticmethod + def gen_secret_key(): + return ''.join([ + random.SystemRandom().choice( + 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') + for i in range(50)]) + + def run(self, config_file): + template_content = pkgutil.get_data( + 'ihatemoney', + os.path.join('conf-templates/', config_file) + '.j2' + ).decode('utf-8') + + print(Template(template_content).render( + pkg_path=os.path.abspath(os.path.dirname(__file__)), + venv_path=os.environ.get('VIRTUAL_ENV'), + secret_key=self.gen_secret_key(), + )) + + def main(): app = create_app() Migrate(app, db) @@ -25,6 +62,7 @@ def main(): manager = Manager(app) manager.add_command('db', MigrateCommand) manager.add_command('generate_password_hash', GeneratePasswordHash) + manager.add_command('generate-config', ConfigTemplate) manager.run()