I have just finished building my web app and migrated it to a digital ocean droplet. The problem that I am having is I can run runserver 0.0.0.0:8000
and use my server IP to get to my homepage, landing-page, signup etc. As well I am able to enter incorrect credentials and be redirected back to sign-in again. As soon as the correct credentials are entered Django hangs up until I stop the server.
On my local machine I do not have this problem, as well by connecting through LAN I am able to login successfully. My local machine connects to a database on a droplet in the same datacenter as my Django prod server.
Strangely, According to my database, the attempt to login is successful. The issue seems to be something related to redirecting to my view. by changing the redirect to my landing page and adding print statements to my view I can see that it is never accessed following authentication.
Mysql version is identical across both instances.
From my Django Instance:
manage.py shell
manage.py shell
manage.py shell
As well I have cloned my repo on the same instance as my database. unfortunately, this did not resolve my issue.
I am using : python3.6.8 - Django 2.2.1 - MySQL 5.7
settings.py
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = os.environ['SECRET_KEY']
DEBUG = True
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
#django builtin Imports
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
#django installed pacakges imports
'allauth',
'allauth.account',
'crispy_forms',
'jquery',
'rest_framework',
'rest_framework_datatables',
'chartjs',
'sass_processor',
'django_nose',
#user built imports
'users',
'pages',
'authenticated',
'exchange',
'celerytasks'
]
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
'rest_framework_datatables.renderers.DatatablesRenderer',
),
'DEFAULT_FILTER_BACKENDS': (
'rest_framework_datatables.filters.DatatablesFilterBackend',
),
'DEFAULT_PAGINATION_CLASS': (
'rest_framework_datatables.pagination.DatatablesPageNumberPagination'
),
'PAGE_SIZE': 3,
}
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',
'django.contrib.auth.middleware.RemoteUserMiddleware',
]
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
ROOT_URLCONF = 'rubillion.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'libraries':{
'file_exists': 'authenticated.templatetags.app_filters'
},
'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 = 'rubillion.wsgi.application'
#SESSION_ENGINE = "django.contrib.sessions.backends.cache"
DATABASES = {
'default': {
'HOST': os.environ['HOST'],
'NAME': 'user_db',
'ENGINE': 'django.db.backends.mysql',
'USER': os.environ['DBUSER'],
'PASSWORD': os.environ['DBPWD']
},
'auth_db': {
'HOST': os.environ['HOST'],
'NAME': 'user_db',
'ENGINE': 'django.db.backends.mysql',
'USER': os.environ['DBUSER'],
'PASSWORD': os.environ['DBPWD']
},
'exchange_db': {
'HOST': os.environ['HOST'],
'NAME': 'exchange',
'ENGINE': 'django.db.backends.mysql',
'USER': os.environ['DBUSER'],
'PASSWORD': os.environ['DBPWD']
},
}
DATABASE_ROUTERS = ['rubillion.routers.ExchangeRouter', 'rubillion.routers.AuthRouter']
# 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',
},
]
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
AUTH_USER_MODEL = 'users.CustomUser'
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
LOGIN_REDIRECT_URL = 'pages:home'
ACCOUNT_LOGOUT_REDIRECT_URL = 'pages:home'
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.RemoteUserBackend",
"allauth.account.auth_backends.AuthenticationBackend",
"django.contrib.auth.backends.ModelBackend",
)
SITE_ID = 1
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_SIGNUP_FORM_CLASS = "users.forms.CustomUserCreationForm"
ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = False
ACCOUNT_SESSION_REMEMBER = True
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_UNIQUE_EMAIL = True
CRISPY_TEMPLATdE_PACK = 'bootstrap4'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
'''
--------------------------------------------------
ALL SECURITY CONCERNS MUST BE ADDRESSED BELOW THIS LINE
--------------------------------------------------
'''
#SECURE_BROWSER_XSS_FILTER = True
#SECURE_CONTENT_TYPE_NOSNIFF = True
#SECURE_HSTS_INCLUDE_SUBDOMAINS = True
#SECURE_SSL_REDIRECT = True
#SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
#SESSION_COOKIE_SECURE = False
#CSRF_COOKIE_SECURE = True
#SECURE_HSTS_SECONDS = 60
#PREPEND_WWW = True
#BASE_URL = "https://###"
#X_FRAME_OPTIONS = 'DENY'
#SECURE_HSTS_PRELOAD = True
wsgi.py
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rubillion.settings')
application = get_wsgi_application()
relevant urls.py
from django.urls import path, include, re_path
from .views import *
from rest_framework import routers, renderers
app_name = "pages"
router = routers.DefaultRouter())
urlpatterns = [
path('', HomePageView.as_view(), name='home'),
]
How I created superuser & check if they exist
(rubyenv)$ python3 manage.py shell
>>> from users.models import CustomUser;
>>> CustomUser.objects.create_superuser('admin', 'a@gmail.com', '$Admin11')
(rubyenv)$ python3 manage.py shell
>>> from users.models import CustomUser
>>> c = CustomUser.objects.filter(is_superuser=True)
>>> print(c)
<QuerySet [
<CustomUser: **@gmail.com>,
<CustomUser: admin@example.com>,
<CustomUser: **@test.com>
]>
My Homepage view that is being redirected. I added two print statements to verify headers match the headers on my local machine.
class HomePageView(TemplateView):
template_name = 'pages/home.html'
def get(self, request):
#print(request.headers)
#print(request.META)
return render(request, self.template_name, {})
My error log when I have to cancel create_superuser (User is created regardless)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/contrib/auth/models.py", line 162, in create_superuser
return self._create_user(username, email, password, **extra_fields)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/contrib/auth/models.py", line 145, in _create_user
user.save(using=self._db)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/contrib/auth/base_user.py", line 66, in save
super().save(*args, **kwargs)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
force_update=force_update, update_fields=update_fields)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 790, in save_base
update_fields=update_fields, raw=raw, using=using,
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in send
for receiver in self._live_receivers(sender)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
for receiver in self._live_receivers(sender)
File "/home/antony/ruby/authenticated/models.py", line 320, in create_user_profile
Users.objects.get_or_create(username=instance)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/query.py", line 541, in get_or_create
return self._create_object_from_params(kwargs, params)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/query.py", line 575, in _create_object_from_params
obj = self.create(**params)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/query.py", line 422, in create
obj.save(force_insert=True, using=self.db)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 741, in save
force_update=force_update, update_fields=update_fields)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/db/models/base.py", line 790, in save_base
update_fields=update_fields, raw=raw, using=using,
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in send
for receiver in self._live_receivers(sender)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
for receiver in self._live_receivers(sender)
File "/home/antony/ruby/exchange/models.py", line 49, in queue_task
send_task('celerytasks.tasks.volatilityTrader')
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/celery/local.py", line 191, in __call__
return self._get_current_object()(*a, **kw)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/celery/app/base.py", line 756, in send_task
amqp.send_task_message(P, name, message, **options)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/celery/app/amqp.py", line 552, in send_task_message
**properties
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 181, in publish
exchange_name, declare,
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/connection.py", line 510, in _ensured
return fun(*args, **kwargs)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 187, in _publish
channel = self.channel
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 209, in _get_channel
channel = self._channel = channel()
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/utils/functional.py", line 44, in __call__
value = self.__value__ = self.__contract__()
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/messaging.py", line 224, in <lambda>
channel = ChannelPromise(lambda: connection.default_channel)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/connection.py", line 852, in default_channel
self.ensure_connection(**conn_opts)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/connection.py", line 422, in ensure_connection
callback, timeout=timeout)
File "/home/antony/ruby/rubyenv/lib/python3.6/site-packages/kombu/utils/functional.py", line 355, in retry_over_time
sleep(1.0)
I have gone through every stack overflow question I could find and tried what feels like every solution. I have been debugging this problem for 4 days and am in desperate need of some help. If there is any information I forgot to provide please let me know :)
SOLVED:
As pointed out by Sidnei Pereira answer the problem is celery related.
I did not setup rabbitmq on my remote server. I was waiting for to complete setting up Gunicorn and Nginx first and I did not need it for authentication. In another app exchange/models.py
I used a receiver decorator and omitted sender=model_name. I planned to run a celery task when new price records are added to db. Instead this event would fire anytime any record is added to db
class Price(models.Model):
ModelField
ModelField
objects = models.Manager()
def __str__(self):
return self.pair + ' / ' + str(self.timestamp)
@receiver(post_save)
def queue_task(instance, created, **kwargs):
send_task('celerytasks.tasks.volatilityTrader')
send_task('celerytasks.tasks.swingTrader')
class Meta:
managed = False
Solution:
class Price(models.Model):
ModelField
ModelField
objects = models.Manager()
def __str__(self):
return self.pair + ' / ' + str(self.timestamp)
class Meta:
managed = False
#reciever must go after model is defined and a sender arg is required
@receiver(post_save, sender=Price)
def queue_task(instance, created, **kwargs):
send_task('celerytasks.tasks.volatilityTrader')
send_task('celerytasks.tasks.swingTrader')
By the traceback I figure you are using celery for an asynchronous task by the login moment. This celery task seems to be triggered by a Django signal when saving the User model. Since it's hang for a long time I think it's because when you celery to push a message to the broker, it can't reach it. That could means Celery isn't properly configured (or not configured at all) in this remote environment or the Message Broker it connects to (RabbitMQ, Redis, SQS, Kafka, etc.) is not running.
Well, if you have no idea about the use of celery (I guess you do since it's in INSTALLED_APPS) in the project - like "it works fine without any broker running in local environment", which means some debug flag is ignoring this - I guess another package you're using depends and uses Celery.
Some things to debug:
File "/home/antony/ruby/authenticated/models.py", line 320, in create_user_profile
Users.objects.get_or_create(username=instance)
Looks like this is being executed because of a Django signal
File "/home/antony/ruby/exchange/models.py", line 49, in queue_task
send_task('celerytasks.tasks.volatilityTrader')
See? Here a message/task is being sent to the broker's queue so an network connection is involved (unless you are using CELERY_TASK_ALWAYS_EAGER), probably that's why the server never responds.