Skip to content

Ambiente de Produção proposto por Franca São Paulo

Leandro Roberto Silva edited this page Mar 1, 2019 · 1 revision

Instalação em servidor de Produção

Atualizado em: 01/03/2019


Trata-se de um exemplo para configuração de um servidor de produção para o SAPL.

Requisitos de Hardware

Este exemplo roda em uma maquina virtual instalada em um cluster Proxmox com os seguintes recursos:

  • 4GB memória RAM
  • 4x CPU
  • 64GB de Armazenamento

Sistema operacional

O sistema operacional utilizado para esse exemplo foi Ubuntu 18.04.1 LTS.

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.1 LTS
Release:        18.04
Codename:       bionic

Configuração do sistema

Atualização

Após a instalação do SO e a configuração da rede, atualize o sistema.

sudo apt update
sudo apt upgrade

Editor de texto

Para melhorar as condições de trabalho quando houver necessidade de editar arquivos de texto no servidor, instale o editor de textos vim.

sudo apt install vim

Para tornar o vim o editor padrão do sistema execute o comando abaixo e em seguida escolha a opção referente ao vim.

sudo update-alternatives --config editor

Por último, configure o vim para exibir o número das linhas por padrão.

sudo vim /etc/vim/vimrc

Adicione as linhas abaixo no final do arquivo.

" Line number
set number

Unzip

O utilitário unzip deve ser instalado para realizar a extração de pacotes .zip se necessário.

sudo apt install unzip

HTOP

Instale o htop para monitorar sistema operacioal, seus processos, etc.

sudo apt install htop
htop

Timezone

A Timezone padrão do servidor deve ser modificada para a região em que estamos.

sudo dpkg-reconfigure tzdata

No menu escolha, por exemplo, America e posteriormente Sao_Paulo.

O arquivo /etc/timezone exibe o fuzo horário escolhido com o comando anterior.

cat /etc/timezone
America/Sao_Paulo

Locale

Adicionado o idioma Português do Brasil e instale os pacotes de idiomas em português.

sudo dpkg-reconfigure locales

No menu, selecione as opções:

en_US.ISO-8859-1
en_US.UTF-8
pt_BR.ISO-8859-1
pt_BR.UTF-8

Escolha pt_BR.UTF-8 como opção padrão. O comando abaixo exibe a configuração:

locale -a
C
C.UTF-8
en_US
en_US.iso88591
en_US.utf8
POSIX
pt_BR
pt_BR.iso88591
pt_BR.utf8

Ntpdate

Para que o servidor sincronize o seu horário, instale o utilitário ntpdate e crie um script no diretório /etc/cron.hourly/ chamado ntp-time-sync.

sudo apt install ntpdate
sudo vim /etc/cron.hourly/ntp-time-sync

O conteúdo do arquivo é exibido na saída do comando cat.

cat /etc/cron.hourly/ntp-time-sync
#! /bin/sh
#
ntp=$(which ntpdate)
#
$ntp -s a.ntp.br

Conceda a permissão de execução para o script.

sudo chmod +x /etc/cron.hourly/ntp-time-sync

Para efeitos de teste você pode executar o script. A saída do script pode ser vista no log padrão do sistema em /var/log/syslog.

sudo /etc/cron.hourly/ntp-time-sync
sudo tail -f /var/log/syslog

Segurança

Fail2ban

Para implementar um nível de segurança contra ataques de força bruta instale o software fail2ban.

sudo apt install fail2ban

O arquivo de configuração /etc/fail2ban/jail.conf deve copiado para outro arquivo, para que as configurações locais possam ser aplicadas, e, para não se perderem após a atualizações do sistema. Atualizações do sistema geralmente sobrescrevem aquivos de configuração do fail2ban.

cd /etc/fail2ban
sudo cp jail.conf jail.d/local.conf

Por padrão o fail2ban bloqueia tentativas de ataque de força bruta no servidor SSH.

Mais informações: https://www.fail2ban.org/wiki/index.php/Main_Page

Firewall

Configure um firewall utilizando o ufw, para implementar um pouco de segurança ao servidor.

sudo apt install ufw

Configure o firewall para impedir qualquer tentativa de conexão de entrada e permitir todas as conexões de saída como padrão.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw status verbose

Em seguida, libere as portas para permitir conexões SSH, HTTP e HTTPS.

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Por último habilite o firewall. Tenha certeza ter liberado as portas antes de habilitar o firewall.

sudo ufw status verbose

Tudo certo? Então habilite o firewall.

sudo ufw enable

SAPL

Usuário

Crie o usuário sob o qual irá rodar o servidor de aplicação:

sudo groupadd --system webapps
sudo useradd --system --gid webapps --shell /bin/bash --home /var/interlegis gunicorn

Git

Instale o git:

sudo apt install git

Configure as opções globais do git:

git config --global user.name "Seu Nome"
git config --global user.email "seu@e-mail.sp.leg.br"

Para ver as configurações:

git config --list

Outras Dependências

Instalação:

sudo apt install pkg-config software-properties-common build-essential libxml2-dev libjpeg-dev libssl-dev libffi-dev libxslt1-dev curl poppler-utils antiword default-jre libpq-dev graphviz-dev graphviz python3-dev python-psycopg2 python3-setuptools python3-pip python3-venv

PostgreSQL

Instalação:

sudo apt install postgresql postgresql-contrib

Depois de instalado, altere a senha do administrador do postgresql com o utilitário psql.

sudo su postgres
psql

No shell do cliente do postgresql (postgres=#), rode o seguinte comando para alterar a senha do usuário postgres:

postgres=# alter user postgres with password 'senha-do-postgresql';

Sair do psql:

postges=# \q

Na sequência, altere o arquivo /etc/postgresql/10/main/pg_hba.conf para permitir o uso do psql por outros usuário além do usuário postgres do sistema.

sudo vim /etc/postgresql/10/main/pg_hba.conf

A linha 85 do arquivo foi alterada.

local   all             postgres                                password

O serviço foi reiniciado.

sudo systemctl restart postgresql.service

Base de Dados

Rode os seguintes comandos para criar a Base de Dados do SAPL:

sudo -u postgres psql -c "CREATE ROLE sapl LOGIN ENCRYPTED PASSWORD 'uma-senha' NOSUPERUSER INHERIT CREATEDB NOCREATEROLE NOREPLICATION;"
sudo -u postgres psql -c "ALTER ROLE sapl VALID UNTIL 'infinity';"
sudo -u postgres psql -c "CREATE DATABASE sapl WITH OWNER = sapl ENCODING = 'UTF8' TABLESPACE = pg_default LC_COLLATE = 'pt_BR.UTF-8' LC_CTYPE = 'pt_BR.UTF-8' CONNECTION LIMIT = -1 TEMPLATE template0;"

Utilize a senha-do-postgresql criada anteriormente.

Virtualenvwrapper

Instalação:

sudo pip3 install virtualenvwrapper

Diretório:

sudo mkdir -p /var/interlegis/.virtualenvs
sudo chown -R gunicorn:webapps /var/interlegis

Configuração:

sudo vim /etc/bash.bashrc
# Virtualenvwrapper
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export WORKON_HOME=/var/interlegis/.virtualenvs
export PROJECT_HOME=/var/interlegis/
export VIRTUALENVWRAPPER_SCRIPT=/usr/local/bin/virtualenvwrapper.sh
source /usr/local/bin/virtualenvwrapper.sh

Projeto

Logar com o usuário gunicorn:

sudo su - gunicorn

Checar o diretório atual

pwd
/var/interlegis

Clonar o repositório do SAPL:

git clone -b 3.1.x --single-branch git@github.com:interlegis/sapl.git sapl

Ambiente Virtual

Criar o ambiente virtual e instalar as dependecias da aplicação:

mkvirtualenv -a /var/intelegis/sapl -p python3 -r requirements/requirements.txt sapl

Configuração do SAPL

Criar o arquivo sapl/.env:

vim sapl/.env

Inserir o seguinte conteúdo (Atenção na segunda linha SECRTE_KEY):

DATABASE_URL = postgresql://sapl:uma-senha@localhost:5432/sapl
SECRET_KEY = '&*&*&-chave-gerada-com-o-comando-abaixo-*&*&*&*&*&'
DEBUG = False 
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST = 'smtp.interlegis.leg.br'
EMAIL_HOST_USER = 'sapl@cidade.uf.leg.br'
EMAIL_SEND_USER = 'sapl@cidade.uf.leg.br'
EMAIL_HOST_PASSWORD = 'uma-senha'

Gerar a chave secreta e substituir no arquivo sapl/.env:

python manage.py generate_secret_key

Gerar a base de dados:

./manage.py migrate

Gerar arquivos estáticos:

./manage.py collectstatic --no-input --clear

Copiar o arquivo que servirá para inicialização do sistema:

cp gunicorn-start.sh ../gunicorn-start.sh

A cópia desse arquivo é opcional. Dependendo que como você prefere iniciar o SAPL, será preciso promover ajustes nesse aquivo. Abaixo segue o arquivo com as mundanças necessárias para inicialização do SAPL nesse exemplo:

#!/bin/bash

# As seen in http://tutos.readthedocs.org/en/latest/source/ndg.html

SAPL_DIR="/var/interlegis/sapl"

# Seta um novo diretório foi passado como raiz para o SAPL
# caso esse tenha sido passado como parâmetro
if [ "$1" ]
then
    SAPL_DIR="$1"
fi

NAME="SAPL"                                              # Name of the application (*)
DJANGODIR=/var/interlegis/sapl/                          # Django project directory (*)
SOCKFILE=/var/interlegis/sapl/run/gunicorn.sock          # we will communicate using this unix socket (*)
USER=gunicorn                                            # the user to run as (*)
GROUP=webapps                                            # the group to run as (*)
NUM_WORKERS=9                                            # how many worker processes should Gunicorn spawn (*)
                                                         # NUM_WORKERS = 2 * CPUS + 1
TIMEOUT=60
MAX_REQUESTS=100                                         # number of requests before restarting worker
DJANGO_SETTINGS_MODULE=sapl.settings                     # which settings file should Django use (*)
DJANGO_WSGI_MODULE=sapl.wsgi                             # WSGI module name (*)

echo "Starting $NAME as gunicorn on base dir $SAPL_DIR"

# parameter can be passed to run without virtualenv
if [[ "$@" != "no-venv" ]]; then
    # Activate the virtual environment
    cd $DJANGODIR
    source /var/interlegis/.virtualenvs/sapl/bin/activate
    export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
    export PYTHONPATH=$DJANGODIR:$PYTHONPATH
fi

# Create the run directory if it doesn't exist
RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

# Start your Django Unicorn
# Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon)
exec gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --log-level debug \
  --timeout $TIMEOUT \
  --workers $NUM_WORKERS \
  --max-requests $MAX_REQUESTS \
  --user $USER \
  --access-logfile /var/log/gunicorn/sapl-access.log \
  --error-logfile /var/log/gunicorn/sapl-error.log \
  --bind=unix:$SOCKFILE

Criar o diretório para os logs:

sudo mkdir -p /var/log/gunicorn/
sudo chown -R gunicorn\: /var/log/gunicorn/

SOLR

Essa parte é opcional, mas vale a pena.

Baixar e executar o SOLR:

cd /var/intelegis/sapl
curl -LO https://archive.apache.org/dist/lucene/solr/7.4.0/solr-7.4.0.tgz
tar xvzf solr-7.4.0.tgz
cd solr-7.4.0
./bin/solr start -c

O comando ./bin/solr start -c deve ser executado novamente caso o servidor seja reiniciado.

Inserir as seguintes linhas no final do arquivo sapl/.env.

USE_SOLR = True
SOLR_COLLECTION = 'sapl'
SOLR_URL = 'http://localhost:8983'

Criar a coleção sapl no servidor solr

python solr_api.py -u http://localhost:8983 -c sapl -s 1 -rf 1 -ms 1

Criar o indice:

./manage.py rebuild_index

Let's Encrypt

As páginas servidas pelo nginx funcionam com o protocolo HTTPS, utilizando certificados emitidos pelo serviço de "CA", Autoridade Certificadora, Let's Encrypt. Para que o processo de obtenção dos certificados funcione, antes de configurar os subdomínios é preciso instalar o certbot, que é recomendado na documentação de uso do Let's Encrypt https://letsencrypt.org/getting-started/.

sudo apt install certbot
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

O comando para renovar os certificados, que expiram a cada 3 meses, deve ser inserido no crontab.

sudo crontab -e
45 3 * * * certbot renew --quiet

Nginx

Para instalar o Nginx no sistema operacional Ubuntu Server 18.04 foi utilizado o repositório padrão da distribuição, portanto:

sudo apt install nginx

VHost padrão

Aproveitamos a funcionalidade de "VirtualHosts".

O arquivo default localizado no diretório /etc/nginx/sites-available, reposnável pelo "VirtualHosts" padrão do servidor nginx deve ser alterado conforme segue:

cd /etc/nginx/sites-available
sudo cp default default.dist
sudo vim default
#
### default - server configuration
#

server {

    ### HTTP ###

    ##################################################################
    # Port that the web server will listen on.
    ###
    listen 80 default_server;
    listen [::]:80 default_server;
    ###

    ##################################################################
    # Host that will serve this project.
    ###
    server_name _;
    ###

    ##################################################################
    # The location of our projects public directory.
    ###
    root /var/www/html;
    ###

    ##################################################################
    # Point index to the app front controller.
    ###
    index index.html index.htm index.nginx-debian.html;
    ###

    ##################################################################
    # Useful logfor debug.
    ###
    access_log /var/log/nginx/default.access.log;
    error_log /var/log/nginx/default.error.log;
    rewrite_log on;
    ###

    ##################################################################
    # Redirect to sapl.municipio.uf.leg.br
    ###
    return 301 https://sapl.municipio.uf.leg.br;
    ###

}

VHost sapl

Copiar o diretório DocumentRoot do Vhost padrão do nginx:

sudo cp /var/www/html /var/www/sapl
sudo chown -R www-data\: /var/www/sapl

Criar o arquivo de configuração:

cd /etc/nginx/sites-available
sudo vim sapl.municipio.uf.leg.br.conf

Inicialmente o arquivo de configuração deve ser criado com o seguinte conteúdo:

#
## sapl.municipio.uf.leg.br - server configuration
#

server {

    ### HTTP ###

    ##################################################################
    # Port that the web server will listen on.
    ###
    listen 80;
    listen [::]:80;
    ###

    ##################################################################
    # Host that will serve this project.
    ###
    server_name sapl.municipio.uf.leg.br;
    ###

    ##################################################################
    # The location of our projects public directory.
    ###
    root /var/www/sapl;
    ###

    ##################################################################
    # Point index to the app front controller.
    ###
    index index.html index.htm index.nginx-debian.html;
    ###

    ##################################################################
    # Useful logs for debug.
    ###
    access_log /var/log/nginx/sapl.municipio.uf.leg.br.access.log;
    error_log /var/log/nginx/sapl.municipio.uf.leg.br.error.log;
    rewrite_log on;
    ###

}

Assim, pode-se habilitar o Vhost sapl.municipio.uf.leg.br:

sudo ln -s /etc/nginx/sites-available/sapl.municipio.uf.leg.br.conf /etc/nginx/sites-enabled/sapl.municipio.uf.leg.br.conf

Na sequência, após checar se está tudo certo com a configuração dos Vhosts no nginx,

sudo nginx -t

o serviço deve ser reiniciado:

sudo systemctl restart nginx.service

Para obter o Certificado Let's Encrypt, rode o seguinte comando:

sudo certbot certonly --webroot -w /var/www/sapl -d sapl.municipio.uf.leg.br

Após a obtenção do certificado, altere a configuração do aquivo /etc/nginx/sites-available/sapl.municipio.uf.leg.br.conf, para o seguinte conteúdo:

sudo vim /etc/nginx/sites-available/vim sapl.municipio.uf.leg.br.conf
#
## sapl.municipio.uf.leg.br - server configuration
#

upstream sapl.municipio.uf.leg.br {
    server unix:/var/interlegis/sapl/run/gunicorn.sock fail_timeout=0;
}

server {

    ### HTTP ###

    ##################################################################
    # Port that the web server will listen on.
    ###
    listen 80;
    listen [::]:80;
    ###

    ##################################################################
    # Host that will serve this project.
    ###
    server_name sapl.municipio.uf.leg.br;
    ###

    ##################################################################
    # The location of our projects public directory.
    ###
    root /var/www/sapl;
    ###

    ##################################################################
    # Point index to the app front controller.
    ###
    index index.html index.htm index.nginx-debian.html;
    ###

    ##################################################################
    # Redirect to HTTPS
    ###
    return 301 https://$server_name$request_uri;
    ###

    ##################################################################
    # Useful logs for debug.
    ###
    access_log /var/log/nginx/sapl.municipio.uf.leg.br.access.log;
    error_log /var/log/nginx/sapl.municipio.uf.leg.br.error.log;
    rewrite_log on;
    ###

}

server {

    ### HTTPS ###

    ##################################################################
    # Port that the web server will listen on.
    ###
    listen 443 ssl;
    listen [::]:443 ssl;
    ###

    ##################################################################
    # SSL configuration
    ###
    ssl_certificate /etc/letsencrypt/live/sapl.municipio.uf.leg.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sapl.municipio.uf.leg.br/privkey.pem;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ###

    ##################################################################
    # Host that will serve this project.
    ###
    server_name sapl.municipio.uf.leg.br;
    ###

    ##################################################################
    # Redirect server error pages to the static page /50x.html
    ###
    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /var/interlegis/sapl/sapl/static/;
    }
    ###

    ##################################################################
    # Point index to the app static files.
    ###
    location /static/ {
        alias /var/interlegis/sapl/sapl/collected_static/;
    }
    ###

    ##################################################################
    # Point index to the app media files.
    ###
    location /media/ {
        alias /var/interlegis/sapl/sapl/media/;
    }
    ###

    ##################################################################
    # URLs to attempt, including pretty ones.
    ###
    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://sapl.municipio.uf.leg.br;
            break;
        }
    }
    ###

    ##################################################################
    # Max upload file size.
    ###
    client_max_body_size 4M;
    ###

    ##################################################################
    # Set header expirations
    ###
    add_header Strict-Transport-Security "max-age=63072000";
    ###

    ##################################################################
    # Security
    ###
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;    
    ###

    ##################################################################
    # Useful logfor debug.
    ###
    access_log /var/log/nginx/sapl.municipio.uf.leg.br.access.log;
    error_log /var/log/nginx/sapl.municipio.uf.leg.br.error.log;
    rewrite_log on;
    ###

    ##################################################################
    # Compressing.
    ###
    gzip on;
    gzip_comp_level    5;
    gzip_min_length    256;
    gzip_proxied       any;
    gzip_vary          on;

    gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttservidores.legislativo
    application/x-web-appservidores.legislativoanifest+json
    application/xhtml+xmlservidores.legislativo
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;
    ###

}

Por fim, cheque se está tudo certo com a configuração dos Vhosts no nginx,

sudo nginx -t

e reinicie o servidor:

sudo systemctl restart nginx.service

Supervisor

O supervisor fará com que o gunicorn seja executado de maneira automatica no servidor, mantendo o SAPL no ar mesmo que ocorram reinicializações do sistema operacional.

sudo apt install supervisor
cd /etc/supervisor/conf.d
sudo vim gunicorn.conf
[program:gunicorn]
command = /var/interlegis/gunicorn-start.sh
process_name=%(program_name)s
directory = /var/interlegis/sapl
user = gunicorn
stdout_logfile = /var/log/gunicorn/sapl-std.log
stderr_logfile = /var/log/gunicorn/sapl-err.log

Reinicie o Supervisor

sudo systemctl restart supervisor.service

Autoria: Getulio Vinicius Teixeira da Silva Câmara Municipal de Franca - São Paulo.