# FreeBSD + Postgres + nginx + gunicorn + Python/Django



## Boomba (Jun 15, 2016)

Hello everyone.

I am about to deploy a Django app of mine and it will be hosted on my (KVM(dedicated core)) virtual server.
Let's get right to the point:

1. Why FreeBSD?
a) So far I have used Linux a lot more than FreeBSD, but for my server I want maximum stability/security
b) For me FreeBSD also seems a bit easier. The location of config files seems to be more logical and I don't have to go to 100 different folders as I (quite often) have to do on my private Linux machine (that machine is focused on desktop use to be fair though)
c) I have a strong (personal) preference for having my systems as minimal as possible. Even more so, for a server where stability is key.
d) The FreeBSD Handbook seems to be very compatible with the way my brain works when learning a new system.

2. Requirements?
a) Most important: MINIMALISM! Install and maintain as few packages/services as possible
b) nginx + gunicorn (running Django on Python3 in virtualenv) - Installation and setup should not be a problem. Have done this a few times before on Linux
c) PostgreSQL server - Installation and setup should not be a problem. Have done this a few times before on Linux
d) I only want to use pkg(!) and not ports for installation as I don't see any advantages and I dont want to wait for hours until an update has been applied.

3. So what do you want?
There are a few (silly) questions I have that are rather FreeBSD specific:

A) I understand that FreeBSD does have no out of the box way of restarting crashed services/daemons. Is that really correct? I'm used to running gunicorn via supervisord on Linux. Will I have to do the same for FreeBSD or is there a FreeBSD way of solving this? (Which I would prefer)

B) I wanted to try Python3 and there are several ways for installing it. Install pkg "python3" which seems to just install "python34" or install pkg "python35" directly. However what's the better FreeBSD way? Will the python3 (meta)package be updated to python35 at some point or will this remain python34? Same thing with Apache2. In Linux I just install Apache2 and I get the most recent version of A2. So let's say in a year from now A2.6 comes out, the A2 Linux Package will get me A2.6. In FreeBSD however there is a Apache24 package. So if I hypothetically wanted to upgrade to A2.6 in the future I would need to uninstall apache24 and install apache26 manually? Or is there a FreeBSD way to upgrade from one package to another? (Which would surprise me)

C) Jails. I wanna keep things as simple as possible. Would jails add sufficient value in terms of added security for the additional amount of work? As far as I can tell jails is certainly helpful, but not quite the super-security measures it is sometimes hyped up to. However if I am wrong, please correct me!

That's it for now. Thanks so much for your help in advance. If there's any additional information you need, please let me know!


----------



## leebrown66 (Jun 16, 2016)

A) daemon(8) *-r* sounds like what you need.

B) Yes, as a general rule, python3 will install the latest python3 stable, wheras python35 will only install v3.5.  The same goes for all ports I believe.  You must handle any port upgrade manually, unless otherwise stated.  /usr/ports/UPDATING should always be read before performing an upgrade and impacts are detailed there.  In the case there are no impacts, uninstalling old and installing new works, or use pkg-upgrade(8).

C) Hard to say, jails are like chroot on steroids, not a full-blown VM.  They are trivial to spin up though and do provide a nice separation from the host OS.  If it were me, I would put all your components into a single jail.  One reason is you can easily copy that jail structure to another host (or the same one) and play with it separately so you can have production/staging.  Anybody gaining root access to your jailed processes is going to have to be very good to break into the host.  At a later date, if you decide to start a separate web service, you can move nginx out to the host to delegate traffic.


----------



## SirDice (Jun 16, 2016)

A) Have a look at sysutils/daemontools or, more inline with FreeBSD, sysutils/fsc.

B) The defaults are set in /usr/ports/Mk/bsd.default-versions.mk. If you want to deviate from the default you'll have to build from ports. But if you stick to whatever is the default pkg(8) can usually figure out it needs to upgrade Perl from 5.18 to 5.20 for example. There's rarely anything special that needs to be done. 

c) That depends really. For just one site (your own) I probably wouldn't bother. But if you host multiple sites (maintained by others for example) it can definitely help separate the risks.


----------



## storvi_net (Jun 16, 2016)

I would suggest: Put the "Internet-Faced" Services in jails and run the Database directly on the host. PostgreSQL in Jail is possible, but you need to configure some settings which lower the security of the jails...

Regards
Markus


----------



## usuapala (Dec 28, 2016)

I found an updated guide on how to setup nginx and django, this guide is not for freebsd...but if you get to the point to have nginx working the guide could help a lot (if you don't know any pytohn like me).

hope it helps!


----------



## phylax (Mar 4, 2017)

I know, this thread is a little old. But since i was in the same situation like OP i would like to contribute what i did:

From my time with linux i knew runit. To me its like modernised daemontools and i was very happy to see it exists in FreeBSD.

So my suggestion:

A) runit

C) not a suggestion, but i did it inside a jail. One jail for all django sites.


Here is how i set it up:


```
# pwd
/var/service/django-site
# tree
.
├── log
│   ├── main
│   │   ├── current
│   │   └── lock
│   ├── run
│   └── supervise
│       ├── control
│       ├── lock
│       ├── ok
│       ├── pid
│       ├── stat
│       └── status
├── run
└── supervise
    ├── control
    ├── lock
    ├── ok
    ├── pid
    ├── stat
    └── status

4 directories, 16 files
```

The supervise directories are maintained (and created) by runit.

Most important:


```
# cat run
#!/bin/sh
exec 2>&1

ROOT=/django/django-site/
CONF=${ROOT}/gunicorn.conf.py
GUNICORN=/virtualenvs/django-site/bin/gunicorn
APP=django-site.wsgi:application

cd $ROOT
exec chpst -u django:django $GUNICORN -c $CONF $APP
```


----------

