diff --git a/backend/.gitignore b/backend/.gitignore index 28d3762..e2bd6cf 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -3,4 +3,5 @@ __pycache__ resources -right_tree/api/data/fixtures/plants.json \ No newline at end of file +right_tree/api/data/fixtures/plants.json +right_tree/staticfiles \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index fb85742..d826a02 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,9 +1,5 @@ FROM python:3.8-slim-bullseye -ENV DJANGO_SUPERUSER_USERNAME=admin -ENV DJANGO_SUPERUSER_EMAIL=admin@admin.com -ENV DJANGO_SUPERUSER_PASSWORD=admin - WORKDIR /app RUN apt update && \ diff --git a/backend/requirements.txt b/backend/requirements.txt index 266dc2c..61ea7a2 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -3,4 +3,5 @@ psycopg2-binary>=2.8 djangorestframework==3.12.4 django-cors-headers==3.10.0 openpyxl==3.0.9 -requests==2.26.0 \ No newline at end of file +requests==2.26.0 +gunicorn==20.1.0 \ No newline at end of file diff --git a/backend/right_tree/settings.py b/backend/right_tree/settings.py index a567492..1a9b95f 100644 --- a/backend/right_tree/settings.py +++ b/backend/right_tree/settings.py @@ -16,17 +16,19 @@ from pathlib import Path # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent +BASE_URL = os.getenv("BASE_URL", "localhost:8000") # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-5t05qc2&14xuot4lgs#z0ll9(nn-=3-8yks!u(5ce704t&m_*q' +SECRET_KEY = os.getenv("DJANGO_SECRET_KEY", 'django-insecure-5t05qc2&14xuot4lgs#z0ll9(nn-=3-8yks!u(5ce704t&m_*q') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = os.getenv('DJANGO_DEBUG_MODE', '') != 'False' -ALLOWED_HOSTS = [] +# os.getenv("ALLOWED_HOSTS", "").split(","), +ALLOWED_HOSTS = (BASE_URL,) # Application definition @@ -85,9 +87,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.postgis', 'NAME': 'right_tree', - 'USER': 'postgres', - 'PASSWORD': 'postgres', - 'HOST': 'postgres', + 'USER': os.getenv("POSTGRES_DB", "postgres"), + 'PASSWORD': os.getenv("POSTGRES_USER", "postgres"), + 'HOST': os.getenv("POSTGRES_PASSWORD", "postgres"), 'PORT': 5432, } } @@ -129,7 +131,9 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = '/staticfiles/' +PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) +STATIC_ROOT = os.path.join(PROJECT_DIR, 'staticfiles') # Default primary key field type # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field diff --git a/backend/right_tree/urls.py b/backend/right_tree/urls.py index 995313d..694a552 100644 --- a/backend/right_tree/urls.py +++ b/backend/right_tree/urls.py @@ -30,6 +30,6 @@ router.register(r'download/csv', views.CSVDownloadView ,basename='downloadcsv') urlpatterns = [ path('admin/', admin.site.urls), - path('', include(router.urls)), + path('api/', include(router.urls)), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) ] diff --git a/default.env b/default.env index d564e4d..50a0a18 100644 --- a/default.env +++ b/default.env @@ -1,5 +1,12 @@ -LINZ_API_KEY=YOUR_API_KEY +# POSTGRES CONFIG POSTGRES_DB=postgres POSTGRES_USER=postgres POSTGRES_PASSWORD=postgres -FRONTEND_BASE_URL=http://localhost:3000 \ No newline at end of file + +# DJANGO BACKEND CONFIG +LINZ_API_KEY=YOUR_API_KEY +FRONTEND_BASE_URL=http://localhost:9000 +DJANGO_DEBUG_MODE=False +DJANGO_SECRET_KEY=YOUR_DJANGO_SECRET_KEY + +BASE_URL=localhost:9000 \ No newline at end of file diff --git a/dev b/dev index 5222be4..93896e4 100755 --- a/dev +++ b/dev @@ -15,27 +15,27 @@ cmd_create_database() { cmd_makemigrations() { echo "Creating database migrations..." - docker-compose exec django-backend python manage.py makemigrations --no-input + docker-compose exec backend python manage.py makemigrations --no-input } cmd_migrate() { echo "Running database migrations..." - docker-compose exec django-backend python manage.py migrate + docker-compose exec backend python manage.py migrate } cmd_createsuperuser() { - echo "Loading shapefiles into the database..." - docker-compose exec django-backend python manage.py createsuperuser --noinput + echo "Creating django superuser..." + docker-compose run backend python manage.py createsuperuser } cmd_load_fixtures() { echo "Loading fixtures..." - docker-compose exec django-backend bash -c "python manage.py loaddata right_tree/api/data/fixtures/*.json" + docker-compose exec backend bash -c "python manage.py loaddata right_tree/api/data/fixtures/*.json" } cmd_load_shapefiles() { echo "Loading shapefiles into the database..." - docker-compose exec django-backend python manage.py loadshapefiles + docker-compose exec backend python manage.py loadshapefiles } cmd_create_plant_fixtures() { @@ -45,12 +45,12 @@ cmd_create_plant_fixtures() { cmd_reset_plants() { echo "Resetting plants..." - docker-compose exec django-backend python manage.py resetplants + docker-compose exec backend python manage.py resetplants } cmd_load_plant_fixtures() { echo "Loading plants..." - docker-compose exec django-backend python manage.py loaddata right_tree/api/data/fixtures/plants.json + docker-compose exec backend python manage.py loaddata right_tree/api/data/fixtures/plants.json } cmd_load_plants() { @@ -61,16 +61,15 @@ cmd_load_plants() { cmd_load_sites_from_spreadsheet() { echo "Loading habitats and zones..." - docker-compose exec django-backend python manage.py loadsitedata + docker-compose exec backend python manage.py loadsitedata } cmd_populate_database() { echo "Populating the database..." - docker-compose up -d django-backend postgres + docker-compose up -d backend postgres cmd_makemigrations cmd_migrate - cmd_createsuperuser cmd_load_fixtures cmd_load_shapefiles cmd_load_plants @@ -95,7 +94,14 @@ cmd_start() { docker-compose up } +cmd_create_staticfiles() { + docker-compose -f docker-compose.production.yaml build + docker-compose run backend python manage.py collectstatic --no-input + docker-compose run frontend npm run-script build +} + cmd_build_production() { + cmd_create_staticfiles docker-compose -f docker-compose.production.yaml build } @@ -103,6 +109,10 @@ cmd_start_production() { docker-compose -f docker-compose.production.yaml up --remove-orphans } +cmd_stop_production() { + docker-compose -f docker-compose.production.yaml stop --remove-orphans +} + # Run the command cmd="$1" "cmd_$cmd" "$@" diff --git a/docker-compose.production copy.yaml b/docker-compose.production copy.yaml new file mode 100644 index 0000000..f10be43 --- /dev/null +++ b/docker-compose.production copy.yaml @@ -0,0 +1,45 @@ +version: "3.8" + +volumes: + righttree-postgres-data: + name: righttree-postgres-data + +services: + backend: + restart: unless-stopped + build: + context: backend + dockerfile: Dockerfile + container_name: righttree-backend + depends_on: + - postgres + env_file: .env + ports: + - "8000:8000" + command: bash -c "gunicorn --bind 0.0.0.0:8000 right_tree.wsgi" + + frontend: + build: + context: frontend + dockerfile: Dockerfile + restart: unless-stopped + container_name: righttree-frontend + ports: + - "3000:3000" + working_dir: /app + command: sh -c "serve -s build" + + postgres: + image: postgis/postgis:13-3.0 + restart: unless-stopped + container_name: postgres + volumes: + - righttree-postgres-data:/var/lib/postgresql/data + - ./create_database.sql:/docker-entrypoint-initdb.d/create_database.sql + ports: + - "5432:5432" + environment: + - POSTGRES_DB=${POSTGRES_DB} + - POSTGRES_USER=${POSTGRES_USER} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + diff --git a/docker-compose.production.yaml b/docker-compose.production.yaml index a8e4a2d..8f7181b 100644 --- a/docker-compose.production.yaml +++ b/docker-compose.production.yaml @@ -1,45 +1,43 @@ version: "3.8" volumes: - local-postgres-data: - name: local-postgres-data + righttree-postgres-data: + name: righttree-postgres-data services: - django-backend: + backend: restart: unless-stopped build: context: backend dockerfile: Dockerfile - container_name: righttree-backend + container_name: backend depends_on: - postgres - volumes: - - ./backend:/app - environment: - - LINZ_API_KEY=${LINZ_API_KEY} - - FRONTEND_BASE_URL=${FRONTEND_BASE_URL} + env_file: .env ports: - "8000:8000" - command: bash -c "./manage.py runserver 0.0.0.0:8000" + command: bash -c "gunicorn --bind 0.0.0.0:8000 right_tree.wsgi" - react-frontend: - build: - context: frontend - dockerfile: Dockerfile - restart: unless-stopped - container_name: righttree-frontend + nginx: + container_name: nginx + image: nginx + depends_on: + - postgres + - backend + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + - ./backend/right_tree/staticfiles:/etc/nginx/html/staticfiles + - ./frontend/build:/etc/nginx/html/build + - ./keys:/etc/ssl/private/nginx ports: - - "3000:3000" - working_dir: /app - command: sh -c "serve -s build" - + - "9000:80" postgres: image: postgis/postgis:13-3.0 restart: unless-stopped container_name: postgres volumes: - - local-postgres-data:/var/lib/postgresql/data + - righttree-postgres-data:/var/lib/postgresql/data - ./create_database.sql:/docker-entrypoint-initdb.d/create_database.sql ports: - "5432:5432" diff --git a/docker-compose.yaml b/docker-compose.yaml index 37a9816..557cab9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -5,7 +5,7 @@ volumes: name: local-postgres-data services: - django-backend: + backend: restart: unless-stopped build: context: backend @@ -21,7 +21,7 @@ services: - "8000:8000" command: bash -c "./manage.py runserver 0.0.0.0:8000" - react-frontend: + frontend: image: node:16-alpine3.11 restart: unless-stopped container_name: righttree-frontend diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..848fc20 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,29 @@ +http { + server { + listen 80; + listen 443 ssl; + index index.html; + include /etc/nginx/mime.types; + proxy_set_header Host $http_host; + + ssl_certificate /etc/ssl/private/nginx/selfsigned.crt; + ssl_certificate_key /etc/ssl/private/nginx/selfsigned.key; + + location / { + root /etc/nginx/html/build; + } + + location /staticfiles { + root /etc/nginx/html/; + } + + location ~* ^/(api|admin) { + proxy_pass http://backend:8000; + } + } +} + + +events { + # configuration of connection processing +}