jamesvandyne / tanzawa

Tanzawa is a blogging system designed for the IndieWeb that focuses on sustainability.
Apache License 2.0
32 stars 2 forks source link

Use a production-grade web server #208

Closed MaybeThisIsRu closed 1 year ago

MaybeThisIsRu commented 2 years ago

So the readme just uses the development web server. I am not sure if that's what is supposed to be used on production as well since it is after all the docs for setup...

gunicorn is what I use for our Django project @ work and I suppose that's the de-facto WGSI web server in Python-land?

MaybeThisIsRu commented 2 years ago

Oh I see it is a dependency...

https://github.com/jamesvandyne/tanzawa/blob/main/requirements.txt#L9

Perhaps the docs need updating?

MaybeThisIsRu commented 2 years ago

I guess a better issue title is: separate docs for self-hosting Tanzawa on a VPS via Docker.

jamesvandyne commented 2 years ago

Yes - the readme just uses the development server.

I'm using Gunicorn myself for my blog, but I'm planning to move the project to uWSGI because it's more than just an application server, including things like queues, which will allow me to have async tasks without adding celery/redis etc...

There's some example configurations in the packer scripts...but it still needs some work as I figure out the best way to handle ENV files with docker-compose/django-environ and such.

MaybeThisIsRu commented 2 years ago

Ah dang. I'd love to see this. I think I'm ready to jump back into IndieWeb with Tanzawa. As long as my budget VPS handles it fine...

I did try to set it up the day that I opened all these issues (3-4 days ago?) but was lost on what to do once the development/configuration side of things is sorted out.

MaybeThisIsRu commented 2 years ago

Should this be closed in favour of #142 then?

jamesvandyne commented 2 years ago

Tanzawa should run on any budget VPS, I'd reckon. My site is using a $5 / month DO droplet. I feel like this is a separate issue than #142. This can be closed by some proper documentation / instructions for how to setup Tanzawa for production use. While the other one is more about automating all of it.

The main thing I need to figure out in order to write the docs is, I want both "bare metal" installs and Docker/Docker-compose installs to use the same .env file in, ideally, same location...so I've got to do some fiddling with that all to make sure it works as expected.

jamesvandyne commented 2 years ago

Pasting some of my config files that I'm using with Ubuntu / Gunicorn / Apache. In the future, Tanzawa instructions will be assuming nginx and won't be using Apache. I am only using Apache now because this server was originally setup using a 1-click Wordpress Droplet.

Apache Config

Serves staticfiles and forwards requests to Gunicorn socket running at /run/jvd.sock. Rewrite rules are from certbot. /etc/apache2/sites-enabled/default.conf is as below:

UseCanonicalName On

<VirtualHost *:80>
        ServerAdmin james@jamesvandyne.com
        ServerName jamesvandyne.com
        ServerAlias www.jamesvandyne.com

        ProxyPreserveHost On
    ProxyTimeout 360
        ProxyPass /static !
        Alias /static "/var/www/jvd/tanzawa/staticfiles"

        <Directory "/var/www/jvd/tanzawa/staticfiles">
            Options -Indexes
            Order deny,allow
            Require all granted
            Allow from all
        </Directory>
        RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
        RequestHeader set X-Forwarded-SSL expr=%{HTTPS}
        ProxyPass / unix:/run/jvd.sock|http://127.0.0.1/ disablereuse=On  connectiontimeout=360 timeout=360
        ProxyPassReverse / unix:/run/jvd.sock|http://127.0.0.1/

    ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
RewriteEngine on
RewriteCond %{SERVER_NAME} =jamesvandyne.com [OR]
RewriteCond %{SERVER_NAME} =www.jamesvandyne.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

Systemd

These are the service and socket config files that I use on my server. It allows me to start / stop Tanzawa (jvd) on my droplet with commands like systemctl restart jvd.service

# /etc/systemd/system/jvd.socket
[Unit]
Description=jvda gunicorn socket

[Socket]
ListenStream=/run/jvd.sock
# Our service won't need permissions for the socket, since it
# inherits the file descriptor by socket activation
# only the nginx daemon will need access to the socket
SocketUser=www-data
# Optionally restrict the socket permissions even more.
# SocketMode=600

[Install]
WantedBy=sockets.target

The .service file is what actually executes gunicorn / the app server with a fullpath to the venv gunicorn binary. Minimum 4 workers is required (the -w 4 option), but should work fine with more.

# /etc/systemd/system/jvd.service
[Unit]
Description=jvd service
Requires=jvd.socket
After=network.target

[Service]
Type=notify
# the specific user that our service will run as
User=www-data
Group=www-data
# another option for an even more restricted service is
# DynamicUser=yes
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
RuntimeDirectory=gunicorn
WorkingDirectory=/var/www/jvd/tanzawa/apps/
ExecStart=/var/www/jvd/tanzawa/venv/bin/gunicorn core.wsgi -w 4
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target
rmdes commented 2 years ago

I'm running it with a nginx proxy in front (cloudron.io) so I'm wondering how I could use the non-development production HTTP server in my context (docker with nginx HTTP proxy sitting in front of every of my containers)

jamesvandyne commented 2 years ago

@rmdes Running a production should be a matter of:

  1. Changing the command you use to run Tanzawa from manage.py runserver to something like gunicorn --bind 0.0.0.0:8000 -w 4 (you'll want to double check if it should be 0.0.0.0 or 127.0.0.1 so as to not expose the gunicorn server to the internet. The gunicorn binary should be located in the virtualenv's bin directory.
  2. Mapping the staticfiles location in Docker so nginx can access it.
  3. Mapping the media location in Docker so nginx can access it (this may already be on your local file system)
  4. Updating nginx to serve from static/media file locations. The nginx config in packer/base_server/templates/ might serve as a good example?

I'll put proper deployment docs as my next priority.

MaybeThisIsRu commented 2 years ago

That looks very similar to what I'm doing with my project at work (and why wouldn't it -- literally the point of Django πŸ˜„).

It can definitely be made easier by supplying a docker compose config that includes the nginx static+media files proxy.

jamesvandyne commented 2 years ago

Yes - I've got a base docker-compose file in packer/base_server/templates/docker-compose.yml that sets up the media/staticfiles mounts and it worked last I used it.

In this base_server configuration, I decided to run nginx on the server, rather than via docker-compose because I remember it being difficult to get dockerized-nginx and let's encrypt playing nicely... it worked at one point, but I know there's more work required around handling environment variables to finish it up.

MaybeThisIsRu commented 2 years ago

Is there an update on this? I'm itching to get started. :sweat_smile:

jamesvandyne commented 2 years ago

@MaybeThisIsRu Not quite yet. Been busy preparing for a work trip. Hoping to get some instructions written on the plane this weekend. I'll ping you in the PR for review, if that's ok? πŸ™πŸ»

MaybeThisIsRu commented 2 years ago

Yes, that’s absolutely fine!

jamesvandyne commented 2 years ago

Started on the running with Docker instructions in #227 . I think the "current" Docker image needs to be rebuilt before they're ready for testing out.

jamesvandyne commented 2 years ago

@MaybeThisIsRu I've got some base instructions for setting up an Unbuntu server with Docker and Tanzawa running via docker / docker-compose. When you have a minute, can you try running through the install instructions here and let me know if they work for you? πŸ™

MaybeThisIsRu commented 2 years ago

Thank you!! I'll get to those during the week now. Quite busy the rest of the weekend.

jamesvandyne commented 1 year ago

I've written instructions for how to deploy Tanzawa using Fly.io, which is much easier / faster than using a VPS that you need to manage yourself. The README now indicates that the runserver is used for development. Closing this issue as the main request has been resolved :-)