<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Gianluca Pacchiella (Posts about sysadmin)</title><link>https://ktln2.org/</link><description></description><atom:link href="https://ktln2.org/categories/sysadmin.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2025 &lt;a href="mailto:gp@ktln2.org"&gt;Gianluca Pacchiella&lt;/a&gt; </copyright><lastBuildDate>Wed, 31 Dec 2025 10:36:34 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Let's encrypt</title><link>https://ktln2.org/2016/01/16/letsencrypt/</link><dc:creator>Gianluca Pacchiella</dc:creator><description>&lt;p&gt;&lt;a href="https://letsencrypt.org"&gt;Let's encrypt&lt;/a&gt; is the new thing in town: allows a seamless procedure
for obtaining &lt;code&gt;TLS&lt;/code&gt; certificates; and it's free ;)&lt;/p&gt;
&lt;p&gt;Roughly speaking, it's a certification authority, capable of generating certificates accepted from any major browser;
it has appositely created an (&lt;a href="https://github.com/letsencrypt/letsencrypt"&gt;open source&lt;/a&gt;) client 
to do that &lt;em&gt;without human intervention&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The protocol used by the client is &lt;a href="https://letsencrypt.github.io/acme-spec/"&gt;ACME&lt;/a&gt;
(stands for &lt;em&gt;Automatic Certificate Management Environment&lt;/em&gt;);&lt;/p&gt;
&lt;p&gt;First of all, install the client (in the future will exist a maintained package)
in the server (all the operations must be done as root, I know, sucks)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# git clone https://github.com/letsencrypt/letsencrypt &amp;amp;&amp;amp; cd letsencrypt
# ./letsencrypt-auto
[... installing packages...]
Creating virtual environment...
Updating letsencrypt and virtual environment dependencies.......
Running with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt
No installers seem to be present and working on your system; fix that or try running letsencrypt with the "certonly" command
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates in the &lt;code&gt;$HOME/.local/share/letsencrypt&lt;/code&gt; a virtualenv with the client, &lt;code&gt;letsencrypt-auto&lt;/code&gt; should
be a wrapper to the main executable named &lt;code&gt;letsencrypt&lt;/code&gt;, that checks everytime if updates are available.
If you want to use &lt;code&gt;letsencrypt&lt;/code&gt; directly you have to activate the virtualenv.&lt;/p&gt;
&lt;p&gt;There are several different ways to obtain a certificate and to deploy it,
I choose a manual method, since I usually I have nginx that is not officially supported.
If you have &lt;code&gt;apache&lt;/code&gt; all should be completely automated. Exist also other methods,
if you want to improve your knowledge, read the &lt;a href="https://letsencrypt.readthedocs.org/en/latest/"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;From &lt;a href="https://community.letsencrypt.org/t/using-the-webroot-domain-verification-method/1445/7"&gt;this post&lt;/a&gt; I stole
the configuration for &lt;code&gt;nginx&lt;/code&gt; (to place in &lt;code&gt;/etc/nginx/snippets/letsencryptauth.conf&lt;/code&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-nginx"&gt;location /.well-known/acme-challenge {
    alias /etc/letsencrypt/webrootauth/.well-known/acme-challenge;
    location ~ /.well-known/acme-challenge/(.*) {
        add_header Content-Type application/jose+json;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then in the &lt;code&gt;server&lt;/code&gt; block
serving the domain for which you want to issue the certificate you can include this snippet&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-nginx"&gt;server {

        # the include must be placed before any location directive
        include snippets/letsencryptauth.conf;

        # other location directives
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally we have to create the authentication directory&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# mkdir /etc/letsencrypt/webrootauth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and execute the last step&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ./letsencrypt-auto  \
    --webroot-path /etc/letsencrypt/webrootauth \
    --domain yourdomain.com  \
    -a webroot certonly
[... wait a little bit ...]
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/yourdomain.com/fullchain.pem. Your cert will expire
   on 2016-03-03. To obtain a new version of the certificate in the
   future, simply run Let's Encrypt again.
 - If like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember that the certificate generated will expire after just three months.&lt;/p&gt;
&lt;h3&gt;Security&lt;/h3&gt;
&lt;p&gt;All is working but someone has (rightly) rised some concerns about security since
all the scripts are autoupdating and running as root. An alternative way is to &lt;a href="https://letsencrypt.readthedocs.org/en/latest/using.html#running-with-docker"&gt;install and run it
 using docker&lt;/a&gt;
with the following steps: first of all, pull the image&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker pull quay.io/letsencrypt/letsencrypt:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then run it, mounting the path used to store configuration and certificates by letsencrypt&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker run \
    -v "/etc/letsencrypt:/etc/letsencrypt" \
    -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
    --entrypoint=/bin/bash \
    -it quay.io/letsencrypt/letsencrypt
root@d24cd7b4b487:/opt/letsencrypt#
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I warn you that &lt;a href="https://docker.io"&gt;docker&lt;/a&gt; works only on 64bit machines.&lt;/p&gt;</description><category>cryptography</category><category>sysadmin</category><guid>https://ktln2.org/2016/01/16/letsencrypt/</guid><pubDate>Sat, 16 Jan 2016 00:00:00 GMT</pubDate></item><item><title>Restore backup and move mail server</title><link>https://ktln2.org/2016/01/10/restore-backup-move-mail-server/</link><dc:creator>Gianluca Pacchiella</dc:creator><description>&lt;p&gt;We all know that backup are essential, but your backup procedure
is tested? I mean, you have ever tried to restore a service?&lt;/p&gt;
&lt;p&gt;In this post I try to explain the procedure that I used to restore
and move my mail service to another server: it's a pretty basic setup,
consisting of &lt;code&gt;postfix&lt;/code&gt; as service &lt;code&gt;SMTP&lt;/code&gt;, &lt;code&gt;dovecot&lt;/code&gt; as &lt;code&gt;IMAPS&lt;/code&gt;
service and having as pool directory the path &lt;code&gt;/var/mail/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The backup is done using &lt;code&gt;rsnapshot&lt;/code&gt; via my &lt;a href="https://github.com/gipi/Easy-backup"&gt;easy-backup&lt;/a&gt; package:
from the snapshot I created a &lt;code&gt;tar&lt;/code&gt; archive with the configuration files for the
services of interest in the &lt;code&gt;/etc&lt;/code&gt; directory and the mail pool.&lt;/p&gt;
&lt;h3&gt;Restore&lt;/h3&gt;
&lt;p&gt;First of all install the necessary packages: to obtain the list of packages
installed with the actual version on the src server you can use&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ /usr/bin/aptitude -q -F "%?p=%?V %M" --disable-columns search \~i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(this is already generated if you install my package ;)); now, depending
how different is the destination system, you have to
check if the versions that it finds make sense or a major version
change happened (like &lt;code&gt;dovecot&lt;/code&gt; &lt;a href="http://wiki2.dovecot.org/Upgrading/2.0"&gt;in my
case&lt;/a&gt;) and in such case google for
problems.&lt;/p&gt;
&lt;p&gt;In any case, if something goes wrong you can &lt;code&gt;apt-get remove --purge &amp;lt;packages&amp;gt;&lt;/code&gt;
and restart from beginning.&lt;/p&gt;
&lt;p&gt;After that you can copy the backuped data into the new machine: from
the machine where you have the backup, create an archive containing
all the needed&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ tar \
    -c \
    -C &amp;lt;root path of the backup&amp;gt; \
    etc/dovecot etc/postfix etc/aliases etc/aliases.db var/mail /home/gipi/mail/ \
    &amp;gt; archive-`date --iso`.tar
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As double check, look at the configuration files and try to find some reference to files in
&lt;code&gt;/etc&lt;/code&gt; that can be needed (for example, in my case, some certificates). Also,
remember that is possible that the two systems can have the &lt;code&gt;uid&lt;/code&gt; and &lt;code&gt;gid&lt;/code&gt;
of the corresponding users not equal causing permission issues ( I would like to
extend &lt;code&gt;easy-backup&lt;/code&gt; to handle these cases).&lt;/p&gt;
&lt;p&gt;Finally, compress the archive and unarchive to the final server&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat archive-2016-01-01.tar | gzip -9 | ssh dest tar -C / -xzv
etc/postfix/
etc/postfix/postfix-script
etc/postfix/main.cf
etc/postfix/sasl/
etc/postfix/master.cf
etc/postfix/virtual
etc/postfix/post-install
etc/postfix/postfix-files
etc/postfix/dynamicmaps.cf
etc/postfix/virtual.db
etc/dovecot/
etc/dovecot/dovecot-sql.conf
etc/dovecot/dovecot.conf
etc/dovecot/dovecot-ldap.conf
etc/dovecot/dovecot-db-example.conf
etc/dovecot/dovecot.conf.bak
etc/dovecot/dovecot-dict-sql-example.conf
etc/aliases
etc/aliases.db
var/mail/
var/mail/postgres
var/mail/gipi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This step can be time expensive (in my case the archive was like 80MB).&lt;/p&gt;
&lt;p&gt;After all, restart the services and &lt;code&gt;tail -f /var/log/syslog&lt;/code&gt; to watch
any problem that can arise.&lt;/p&gt;
&lt;h3&gt;Test&lt;/h3&gt;
&lt;p&gt;After all the procedure we can test if the new installation is working correctly,
but since this want to be a test, without interrupting the normal mail server,
we can use &lt;a href="https://www.debian-administration.org/article/633/Testing_SMTP_servers_with_SWAKS"&gt;SWAKS&lt;/a&gt;
and its option &lt;code&gt;--server&lt;/code&gt; to direct the connections to the new server,
otherwise it looks for the &lt;code&gt;MX&lt;/code&gt; DNS's entry of the recipient (i.e. the email address
indicated in the &lt;em&gt;to&lt;/em&gt; field); in the following example I used as the
domain  &lt;code&gt;yourdomain.com&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ swaks \
    --server mail.yourdomain.com \
    --to user@yourdomain.com \
    --from test@example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Meanwhile you can look at the &lt;code&gt;syslog&lt;/code&gt; on the server: in my case
the first time I've done this I forgot to add &lt;code&gt;/etc/aliases.db&lt;/code&gt;
into the backup and this below is what the server told me&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jan  3 12:30:13 miao postfix/smtpd[7337]: error: open database /etc/aliases.db: No such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Obviously, we care to have the &lt;code&gt;TLS&lt;/code&gt; available, so we can test that also
with autentication&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ swaks \
    --server mail.yourdomain.com \
    -tls --tls-verify --tls-protocol tlsv1_2 \
    --auth plain \
    --from user@yourdomain.com \
    --to uptoyou@example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point you can also use some online tool to check you mail
server, like &lt;a href="https://starttls.info"&gt;starttls&lt;/a&gt;. It's also possible to
check for &lt;a href="https://mxtoolbox.com/blacklists.aspx"&gt;blacklist&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;If all it's ok, you are ready to switch your mail server:
my procedure was to add a &lt;a href="https://en.wikipedia.org/wiki/MX_record"&gt;MX record&lt;/a&gt; with lower precedence
to the one pre-existing, but lowering the &lt;a href="https://en.wikipedia.org/wiki/Time_to_live"&gt;time-to-live&lt;/a&gt;
of both the entries, so to have less time to wait in order to adjust the values. Once
the new entry was available I swapped the precedence so to have the new entry to be used
and not the old one.&lt;/p&gt;
&lt;p&gt;At this point I tried the normal access with my email client so to assure the &lt;code&gt;IMAP&lt;/code&gt; worked
and all the folders was there.&lt;/p&gt;
&lt;p&gt;Finally, activated the backup for mail on the new server.&lt;/p&gt;
&lt;p&gt;I advise you to try this, or in general, backup procedures, as probably you are not
aware exactly of what you need to restore a system: myself I missed for years
the backup of the mail folders in the home of my user.&lt;/p&gt;</description><category>backup</category><category>postfix</category><category>sysadmin</category><guid>https://ktln2.org/2016/01/10/restore-backup-move-mail-server/</guid><pubDate>Sun, 10 Jan 2016 00:00:00 GMT</pubDate></item><item><title>Manage processes in a web application</title><link>https://ktln2.org/2015/12/30/manage-processes/</link><dc:creator>Gianluca Pacchiella</dc:creator><description>&lt;p&gt;Suppose we have the following architecture for our web application:
a standard python web application (can be anything, Django, Flask or a
custom &lt;code&gt;WSGI&lt;/code&gt; code) where &lt;code&gt;nginx&lt;/code&gt; communicates with
it using an unix socket by the &lt;code&gt;uwsgi&lt;/code&gt; protocol as indicated
in the diagram below&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                      socket
browser &amp;lt;---&amp;gt; nginx &amp;lt;----------&amp;gt; uwsgi &amp;lt;---&amp;gt; django/flask/kebab
                                |           |__ database
                                |__ celery
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a pretty standard way to deploy python web applications, but I haven't
found any complete description on how manage this configuration.&lt;/p&gt;
&lt;p&gt;I want&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;each web application must be isolated from any other service on the server&lt;/li&gt;
&lt;li&gt;obviously the code must run with the minimal permissions possible&lt;/li&gt;
&lt;li&gt;the developer don't have to be a system administrator, must have the same permission
    of the running web application&lt;/li&gt;
&lt;li&gt;Control&lt;/li&gt;
&lt;li&gt;a single point for controlling the status of the web application&lt;/li&gt;
&lt;li&gt;the web application can have more than one process, not directly web related (celery anyone)&lt;/li&gt;
&lt;li&gt;the developer can add processes&lt;/li&gt;
&lt;li&gt;when the processes die must be restarted in correct order&lt;/li&gt;
&lt;li&gt;updating must not cause sudden kill of processes (a long running celery task should finish)&lt;/li&gt;
&lt;li&gt;restarting on updating must be explicit&lt;/li&gt;
&lt;li&gt;the service must restart automagically at reboot&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bad enough, not all of these points will be addressed in the first revision of this post.&lt;/p&gt;
&lt;h3&gt;Security&lt;/h3&gt;
&lt;!--
In order to understand what's security, I need to define the so called **threat model**: i.e.
what my adversary is able to do; under my point of view also a developer can be

(I would like to discuss also the *most secure* file system permissions to set the application
with, but the inception is too deep).
--&gt;

&lt;p&gt;First of all, the channel of communication between &lt;code&gt;nginx&lt;/code&gt; and &lt;code&gt;uwsgi&lt;/code&gt; is an unix socket
(i.e. a particular type of file), this allows a more granular access control and is more
customizable (the alternative is to use an internet socket that can be only be customized as
port number, less human readable and not access controllable).&lt;/p&gt;
&lt;p&gt;In order to be functional (i.e. the user requesting the page would actually see
the page) the socket should be readable/writable by the &lt;code&gt;nginx&lt;/code&gt; process and
its own &lt;code&gt;uwsgi&lt;/code&gt; process; since I'm interested in securing the socket from
unwanted &lt;em&gt;interaction&lt;/em&gt;, I want it to be not readable from other possible
&lt;code&gt;uwsgi&lt;/code&gt; instances related to other projects (obviously a vulnerability in
&lt;code&gt;nginx&lt;/code&gt; could allow an attacker to access all of them but this is unavoidable
and I think less probable). Obviously I want to avoid access from random processes
as well.&lt;/p&gt;
&lt;p&gt;This means that we have to create a separate user for each project and that the
socket must be &lt;code&gt;chown&lt;/code&gt;ed to &lt;code&gt;www-data:user&lt;/code&gt; with permissions
&lt;code&gt;srw-rw----&lt;/code&gt; (i.e. &lt;code&gt;660&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The order of the owner seems weird but take into account that &lt;code&gt;chmod(2)&lt;/code&gt; can
change permission only by who owns the file, or quoting the documentation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The effective UID of the calling process must match the owner of the file, or the process must be privileged&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(i.e. the attacker could change the permissions' bits if owns the file)
so, at the end of the day, to avoid escalation we need to set the owner of the files of the web application
to not be the user of under which is running the web application.&lt;/p&gt;
&lt;p&gt;Since the socket is created by the &lt;code&gt;uwsgi&lt;/code&gt; instance and you cannot &lt;code&gt;chown&lt;/code&gt; to a group you don't belong,
&lt;code&gt;uwsgi&lt;/code&gt; must be started as superuser and then it must &lt;em&gt;downgrade&lt;/em&gt; its own capabilities (this is a standard
behaviour for daemon); in order to do so exist some flags&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--uid&lt;/code&gt;: the user id of the running process&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--gid&lt;/code&gt;: the group id of the running process&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--chmod-socket&lt;/code&gt;: the permissions on the socket, &lt;code&gt;660&lt;/code&gt; should be just fine (here we must use &lt;code&gt;=&lt;/code&gt; just after to avoid strange errors)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--chown-socket&lt;/code&gt;: who owns the socket, like &lt;code&gt;www-data:user&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I know that I missing a lot of stuffs in securing a web application, like
filesystem permission for the web root, but that will be argument of a future
post. Indeed if I want to make a configuration I need to determine
what secure means by the definition of a &lt;strong&gt;threat model&lt;/strong&gt; for the web application,
i.e. what your adversary is capable of and from what you want to defend
(for example: your developers are a possible threat? should be them allowed
to change configuration files?).&lt;/p&gt;
&lt;p&gt;In the following I assume that the developer can edit the &lt;code&gt;uwsgi.ini&lt;/code&gt; configuration
file and he/she can add processes.&lt;/p&gt;
&lt;h3&gt;Control&lt;/h3&gt;
&lt;p&gt;In my specific case, usually I deploy untarring the archive with the code in a new directory,
executing some operations (like database migrations, backup, etc...); the tricky thing is
to substitute the running processes in the way described in the list above.&lt;/p&gt;
&lt;p&gt;The entry point for the request at the web application is &lt;a href="https://uwsgi-docs.readthedocs.org/en/latest/"&gt;uwsgi&lt;/a&gt;
and the idea that I want to follow is that &lt;code&gt;uwsgi&lt;/code&gt; controls
the part after it, in this way if some process
is added we don't have to touch with sysadmin power the installation,
i.e. we want the developer to be able to add processes using the &lt;code&gt;uwsgi.ini&lt;/code&gt;
configuration file.&lt;/p&gt;
&lt;p&gt;Now I need a process supervisor for &lt;code&gt;uwsgi&lt;/code&gt;, that starts it and manages its
lifecycle. There are some choices available for process managers, like
&lt;a href="https://supervisord.readthedocs.org/en/latest/"&gt;supervisord&lt;/a&gt;, &lt;a href="http://upstart.ubuntu.com/"&gt;upstart&lt;/a&gt;
and many others (read this &lt;a href="http://blog.crocodoc.com/post/48703468992/process-managers-the-good-the-bad-and-the-ugly"&gt;post&lt;/a&gt;
about process managers for more informations).&lt;/p&gt;
&lt;p&gt;Could be possible to use stuffs like &lt;code&gt;Procfile&lt;/code&gt; (inspired from heroku) to manage
multiple processes, or another option could be using container-like technology (&lt;a href="https://docker.io"&gt;Docker&lt;/a&gt; or &lt;a href="https://linuxcontainers.org/"&gt;lxc&lt;/a&gt;)
but in my opinion are a little bit immature technologies.&lt;/p&gt;
&lt;p&gt;The choice is to use &lt;code&gt;supervisord&lt;/code&gt;, it will start the &lt;code&gt;uwsgi&lt;/code&gt; process;
since &lt;code&gt;supervisor&lt;/code&gt; need you to be a superuser in order to interat with,
I will configure &lt;code&gt;sudo&lt;/code&gt; in order to allow execution of commands like&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo /usr/bin/supervisorctl restart uwsgi_example
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way this kind of configuration with sudo can be used with
whatever process manager you want.&lt;/p&gt;
&lt;p&gt;The tricky step is to configure correctly &lt;code&gt;uwsgi&lt;/code&gt; to manage external
processes, generally the right way to do that is to avoid daemonizing them and
undertstand what signals kill/restart them; for example
&lt;a href="https://celery.readthedocs.org/en/latest/"&gt;celery&lt;/a&gt; uses the &lt;code&gt;TERM&lt;/code&gt; signal as
stated
&lt;a href="https://celery.readthedocs.org/en/latest/faq.html#how-can-i-safely-shut-down-the-worker"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;After all this, let see how to configure all the things: these are the parameters&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;webuser&lt;/code&gt; is the &lt;code&gt;UNIX&lt;/code&gt; user under which the web application run&lt;/li&gt;
&lt;li&gt;&lt;code&gt;www-data&lt;/code&gt; is the identity of the web server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var/www/&lt;/code&gt; is the webroot&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var/www/.virtualenv/&lt;/code&gt; is the virtualenv used&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Supervisor&lt;/h4&gt;
&lt;pre&gt;&lt;code class="language-ini"&gt;[program:uwsgi_example]
command=/var/www/.virtualenv/bin/uwsgi
    --ini /var/www/app/uwsgi.ini
    --processes 1
    --need-app
    --uid webuser
    --gid webuser
    --chown-socket www-data:webuser
    --chmod-socket=660
redirect_stderr=true
stdout_logfile=/var/www/logs/uwsgi.log
stderr_logfile=/var/www/logs/uwsgi_error.log
autostart=true
autorestart=true
stopsignal=QUIT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that if we use &lt;code&gt;--ini&lt;/code&gt; as the first option for the &lt;code&gt;supervisor&lt;/code&gt;'s &lt;code&gt;uwsgi&lt;/code&gt;
option, then any value will be overwritten by the flags passed (the main concern here
are the &lt;code&gt;uid&lt;/code&gt; and &lt;code&gt;gid&lt;/code&gt; flags); in this way the developer cannot override these values
from the &lt;code&gt;uwsgi.ini&lt;/code&gt; file.&lt;/p&gt;
&lt;h4&gt;Sudo&lt;/h4&gt;
&lt;p&gt;With the configuration below, the &lt;code&gt;webuser&lt;/code&gt; can issue command to the &lt;code&gt;uwsgi_example&lt;/code&gt;
configuration of the &lt;code&gt;supervisor&lt;/code&gt; daemon, without requiring a password&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;%webuser ALL = (root) NOPASSWD:/usr/bin/supervisorctl [a-z]\* uwsgi_example
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;UWSGI&lt;/h4&gt;
&lt;p&gt;Finally the &lt;code&gt;uwsgi.ini&lt;/code&gt; file can contain the following entries&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ini"&gt;[uwsgi]
module=.wsgi:application
chdir=/var/www/
socket=/tmp/uwsgi_example.sock
pidfile=/tmp/project-master_example.pid
vacuum=True
max-requests=5000
harakiri=30
stats=/tmp/stats_example.sock
# https://uwsgi-docs.readthedocs.org/en/latest/AttachingDaemons.html#examples
# smart-attach-daemon = /tmp/celery_example.pid .virtualenv/bin/celery -A app.tasks worker --pidfile=/tmp/celery_example.pid --loglevel=debug --logfile logs/celery.log
attach-daemon2 = stopsignal=15,reloadsignal=15,cmd=.virtualenv/bin/celery -A app.tasks worker --pidfile=/tmp/celery_example.pid --loglevel=debug --logfile logs/celery.log --concurrency=5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my model this file is versioned together with the code; in this specific
example is enabled the control of a celery's worker. For more information
there is a &lt;a href="https://uwsgi-docs.readthedocs.org/en/latest/AttachingDaemons.html"&gt;page&lt;/a&gt; in the celery's documentation.&lt;/p&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;p&gt;If seems to you that all of this is tricky to build you are right, but you are lucky: I prepared
a cookiecutter template for provisioning a web app project, with a script aimed to configure all the
necessary in order to test what I described here: simply do&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git clone https://github.com/gipi/cookiecutter-eep-provisioning.git
$ cd cookiecutter-eep-provisioning
$ ./tests/tests.sh

 now you are into the provisioning directory, you can use "sshme" to enter
 as the web application user.

 At the end remember to destroy the vagrant instance with "destroy_provision".

[/tmp/tmp.PjjmjCkjtC/provision] $
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to use the test script you need &lt;a href="https://www.vagrantup.com/"&gt;vagrant&lt;/a&gt; and &lt;a href="https://docs.ansible.com/index.html"&gt;ansible&lt;/a&gt;.
All it's tested for a linux system so be aware the in other OSes
may be not working correctly.&lt;/p&gt;
&lt;p&gt;For now it's all, let me know if all this seems reasonable to you.&lt;/p&gt;</description><category>deploy</category><category>sysadmin</category><category>webapp</category><guid>https://ktln2.org/2015/12/30/manage-processes/</guid><pubDate>Wed, 30 Dec 2015 00:00:00 GMT</pubDate></item></channel></rss>