'Multiple websites on single VPS (nginx + centos + django)

I'm using VPS with nginx + centos + django. I already have one website running on it. Now i want to add one more domain, but after reading a lot of articles i still have troubles with it.

Here is my nginx.conf file:

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/sites-enabled/*.conf;
    server_names_hash_bucket_size 64;


server {

    listen 443 ssl;

    server_name website1.com www.website1.com;
    
    ssl_certificate /etc/ssl/www.website1.com.crt;
    
    ssl_certificate_key /etc/ssl/www.website1.com.key;
    
    location /static/ {
        root /var/www/website1;
        index index.html index.htm index.php;
    }

    location / {
        root /var/www/website1;
        proxy_pass http://127.0.0.1:8888;
        index index.html index.htm index.php;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
    }
    
    
}





    server {
    
    listen 80;
    
    server_name website1.com www.website1.com;
    return 301 https://$host:443$request_uri;
    
    
    location = /favicon.ico {
    alias /var/www/website1/static/img/favicon.png;
}


    
    location /static/ {
        root /var/www/website1;
        index index.html index.htm index.php;
    }

    location / {
        root /var/www/website1;
        proxy_pass http://127.0.0.1:8888;
        index index.html index.htm index.php;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
    }
    }
    
    
    
    
    server {

    listen 443 ssl;

    server_name website2.com www.website2.com;
    
    ssl_certificate /etc/ssl/www.website2.com.crt;
    
    ssl_certificate_key /etc/ssl/www.website2.com.key;
    
    location /static/ {
        root /var/www/website2;
        index index.html index.htm index.php;
    }

    location / {
        root /var/www/website2;
        proxy_pass http://127.0.0.1:8888;
        index index.html index.htm index.php;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
    }
    
    
}





    server {
    
    listen 80;
    
    server_name website2.com www.website2.com;
    return 301 https://$host:443$request_uri;
    
    
    location = /favicon.ico {
    alias /var/www/website2/static/img/favicon.png;
}


    
    location /static/ {
        root /var/www/website2;
        index index.html index.htm index.php;
    }

    location / {
        root /var/www/website2;
        proxy_pass http://127.0.0.1:8888;
        index index.html index.htm index.php;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
    }
    }
}

I've tried using one short main file and two files for each website with server blocks same as in the file above. In this case both website doesn't open at all.

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/sites-enabled/*.conf;
    server_names_hash_bucket_size 64;
}

Here is my django settings file, it is almost the same for both domains, so i leave here only one

"""
Django settings for apartment project.

Generated by 'django-admin startproject' using Django 2.1.4.

For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""

import os


# Logging settings for django projects, works with django 1.5+
# If DEBUG=True, all logs (including django logs) will be
# written to console and to debug_file.
# If DEBUG=False, logs with level INFO or higher will be
# saved to production_file.
# Logging usage:

# import logging
# logger = logging.getLogger(__name__)
# logger.info("Log this message")



# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ''

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['*']


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'website1.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'website1.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, "static")
STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'website1', "static")
]

What i'm doing wrong? Now it seems to me both website adress the same path, so i get the same content for different domains, but i can't find where is my mistake.



Solution 1:[1]

it seems for me, you are trying to start django manually, at some port and connect it with nginx but it is wrong, nginx can serve only static files, and defualt django core python manage.py runserver isn't good enough to use it in production, it is only for testing purpose. You need to connenct it with gunicorn, gunicorn can serve scripts, and nginx for static files. I'll share my configuration which is 100% working with multiple django projects, but i use it on ubuntu

this example project called mail, so you can change "mail" on what you want

  1. mail project deployment:
  2. mkdir mail
  3. cd mail
  4. virtualenv venv
  5. source venv/bin/activate
  6. pip install django gunicorn nginx
  7. django-admin.py startproject mail ~/mail
  8. nano ~/mail/mail/settings.py

in settings.py add:

8.a) import os
8.b) ALLOWED_HOSTS = ["*"]
8.c) TIME_ZONE = 'Europe/Moscow'
8.d) STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
  1. python manage.py makemigrations
  2. python manage.py migrate
  3. python manage.py createsuperuser
  4. python manage.py collectstatic
  5. python manage.py runserver 0.0.0.0:8000

13.a) go to "(ip)0.0.0.0:8000/admin" in your browser the site should work and css styles should be in the admin panel

  1. gunicorn --bind 0.0.0.0:8000 mail.wsgi

14.a) (run command above^^ in a folder with manage.py )

14.b) go to "(ip)0.0.0.0:8000/admin" the site should work and css styles MUST NOT work

  1. deactivate

  2. sudo nano /etc/systemd/system/mail.service

Carefully replace all the words "mail" with the name of your project,

/home/admin/mail >> this is root folder (in config under), keep it in mind, you can check your real path to your project by typing pwd command inside your projects folder

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=admin
Group=www-data
WorkingDirectory=/home/admin/mail
ExecStart=/home/admin/mail/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/admin/mail/mail.sock mail.wsgi:application

[Install]
WantedBy=multi-user.target
  1. sudo systemctl start mail
  2. sudo systemctl enable mail
  3. in the mail project folder (where manage.py ) The file SHOULD (MUST) appear “mail.sock”, if it doesn't go to 16 paragraph, you made misstake there

list your folders:

~/mail$ ls

output should look like this:

db.sqlite3 mail mail.sock manage.py static venv

  1. sudo systemctl status mail

it will check status of service for project mail, which should start it with gunicorn

  1. Nginx configuration:

sudo nano /etc/nginx/sites-available/mail

replace mail in the config with your project (3 places and 1 address)

/home/admin/mail >> this is root folder (in config under), keep it in mind, you can check your real path to your project by typing pwd command inside your projects folder

server {
listen 80;
server_name adress.mail.com;

location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/admin/mail;
}

location / {
include proxy_params;
proxy_pass http://unix:/home/admin/mail/mail.sock;
}
}
  1. sudo ln -s /etc/nginx/sites-available/mail /etc/nginx/sites-enabled

23.a) cd /etc/nginx/sites-enabled

23.b) type ls

project mail must appear in this folder

  1. sudo nginx -t

this will check nginx for errors

  1. sudo systemctl reload nginx

  2. next you need to assign a domain name in this example adress.mail.com to your ip adress of you virtual machine, with CNAME or A type. But if you have no any domains name, you can assign you ip adress server_name 222.333.444.555;, but in this case you can't use different port, so no multiple django projects for you (buy a domain)

your project will work super good if you done all correctly, if you want to add one more project, just simply redo everything in this list

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1