Compare commits
1 Commits
fix/prod-s
...
fix/dev-st
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf1187bc65
|
@@ -2,9 +2,6 @@ name: CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 2 * * *"
|
- cron: "0 2 * * *"
|
||||||
|
|
||||||
@@ -191,15 +188,3 @@ jobs:
|
|||||||
- name: Remove CI image
|
- name: Remove CI image
|
||||||
if: always()
|
if: always()
|
||||||
run: docker image rm -f "$CI_IMAGE" || true
|
run: docker image rm -f "$CI_IMAGE" || true
|
||||||
|
|
||||||
deploy:
|
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Deploy to lintel-prod-01
|
|
||||||
uses: appleboy/ssh-action@v1
|
|
||||||
with:
|
|
||||||
host: ${{ secrets.PROD_SSH_HOST }}
|
|
||||||
username: deploy
|
|
||||||
key: ${{ secrets.PROD_SSH_KEY }}
|
|
||||||
script: bash /srv/sum/nohype/app/deploy/deploy.sh
|
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ DEBUG = True
|
|||||||
|
|
||||||
INTERNAL_IPS = ["127.0.0.1"]
|
INTERNAL_IPS = ["127.0.0.1"]
|
||||||
|
|
||||||
# Drop WhiteNoise in dev — it serves from STATIC_ROOT which is empty without
|
# Use plain static file storage in dev — CompressedManifestStaticFilesStorage
|
||||||
# collectstatic, so it 404s every asset. Django's runserver serves static and
|
# (set in base.py) requires collectstatic to have been run and will 404 on
|
||||||
# media files natively when DEBUG=True (via django.contrib.staticfiles + the
|
# every asset otherwise.
|
||||||
# media URL pattern in urls.py).
|
|
||||||
MIDDLEWARE = [m for m in MIDDLEWARE if m != "whitenoise.middleware.WhiteNoiseMiddleware"]
|
|
||||||
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -2,16 +2,8 @@ from .base import * # noqa
|
|||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
# Behind Caddy: trust the forwarded proto header so Django knows it's HTTPS.
|
|
||||||
# SECURE_SSL_REDIRECT is intentionally off — Caddy handles HTTPS redirects
|
|
||||||
# before the request reaches Django; enabling it here causes redirect loops.
|
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
USE_X_FORWARDED_HOST = True
|
USE_X_FORWARDED_HOST = True
|
||||||
SECURE_SSL_REDIRECT = False
|
SECURE_SSL_REDIRECT = True
|
||||||
SESSION_COOKIE_SECURE = True
|
SESSION_COOKIE_SECURE = True
|
||||||
CSRF_COOKIE_SECURE = True
|
CSRF_COOKIE_SECURE = True
|
||||||
|
|
||||||
CSRF_TRUSTED_ORIGINS = [
|
|
||||||
"https://nohypeai.net",
|
|
||||||
"https://www.nohypeai.net",
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from django.conf import settings
|
|
||||||
from django.conf.urls.static import static
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
@@ -23,6 +21,3 @@ urlpatterns = [
|
|||||||
path("admin/", RedirectView.as_view(url="/cms/", permanent=False)),
|
path("admin/", RedirectView.as_view(url="/cms/", permanent=False)),
|
||||||
path("", include(wagtail_urls)),
|
path("", include(wagtail_urls)),
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
nohypeai.net, www.nohypeai.net {
|
|
||||||
encode gzip zstd
|
|
||||||
|
|
||||||
header {
|
|
||||||
X-Content-Type-Options nosniff
|
|
||||||
X-Frame-Options DENY
|
|
||||||
Referrer-Policy strict-origin-when-cross-origin
|
|
||||||
Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
|
||||||
X-Forwarded-Proto https
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_path /static/* {
|
|
||||||
root * /srv/sum/nohype/static
|
|
||||||
file_server
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_path /media/* {
|
|
||||||
root * /srv/sum/nohype/media
|
|
||||||
file_server
|
|
||||||
}
|
|
||||||
|
|
||||||
reverse_proxy localhost:8001
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Deploy script for No Hype AI — runs on lintel-prod-01 as deploy user.
|
|
||||||
# Called by CI after a successful push to main.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
SITE_DIR=/srv/sum/nohype
|
|
||||||
APP_DIR=${SITE_DIR}/app
|
|
||||||
|
|
||||||
echo "==> Pulling latest code"
|
|
||||||
git -C "${APP_DIR}" pull origin main
|
|
||||||
|
|
||||||
echo "==> Updating compose file"
|
|
||||||
cp "${APP_DIR}/docker-compose.prod.yml" "${SITE_DIR}/docker-compose.prod.yml"
|
|
||||||
|
|
||||||
echo "==> Ensuring static/media directories exist"
|
|
||||||
mkdir -p "${SITE_DIR}/static" "${SITE_DIR}/media"
|
|
||||||
|
|
||||||
echo "==> Building image"
|
|
||||||
docker compose -f "${SITE_DIR}/docker-compose.prod.yml" build --no-cache
|
|
||||||
|
|
||||||
echo "==> Restarting service"
|
|
||||||
sudo systemctl restart sum-nohype
|
|
||||||
|
|
||||||
echo "==> Waiting for health check"
|
|
||||||
for i in $(seq 1 30); do
|
|
||||||
if curl -fsS -H "Host: nohypeai.net" http://localhost:8001/ >/dev/null 2>&1; then
|
|
||||||
echo "==> Site is up"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
sleep 3
|
|
||||||
done
|
|
||||||
echo "ERROR: site did not come up after 90s" >&2
|
|
||||||
sudo journalctl -u sum-nohype --no-pager -n 50
|
|
||||||
exit 1
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
python manage.py tailwind install --no-input
|
|
||||||
python manage.py tailwind build
|
|
||||||
python manage.py migrate --noinput
|
|
||||||
python manage.py collectstatic --noinput
|
|
||||||
|
|
||||||
# Set Wagtail site hostname from first entry in ALLOWED_HOSTS
|
|
||||||
python manage.py shell -c "
|
|
||||||
from wagtail.models import Site
|
|
||||||
import os
|
|
||||||
hostname = os.environ.get('ALLOWED_HOSTS', 'localhost').split(',')[0].strip()
|
|
||||||
Site.objects.update(hostname=hostname, port=443, site_name='No Hype AI')
|
|
||||||
"
|
|
||||||
|
|
||||||
exec gunicorn config.wsgi:application \
|
|
||||||
--workers 3 \
|
|
||||||
--bind 0.0.0.0:8000 \
|
|
||||||
--access-logfile - \
|
|
||||||
--error-logfile - \
|
|
||||||
--capture-output
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=No Hype AI (Docker Compose)
|
|
||||||
Requires=docker.service
|
|
||||||
After=docker.service network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=deploy
|
|
||||||
Group=www-data
|
|
||||||
WorkingDirectory=/srv/sum/nohype
|
|
||||||
|
|
||||||
ExecStartPre=docker compose -f docker-compose.prod.yml pull --ignore-pull-failures
|
|
||||||
ExecStart=docker compose -f docker-compose.prod.yml up --build
|
|
||||||
ExecStop=docker compose -f docker-compose.prod.yml down
|
|
||||||
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
TimeoutStartSec=300
|
|
||||||
TimeoutStopSec=30
|
|
||||||
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
SyslogIdentifier=sum-nohype
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
services:
|
|
||||||
web:
|
|
||||||
build: app
|
|
||||||
working_dir: /app
|
|
||||||
command: /app/deploy/entrypoint.prod.sh
|
|
||||||
env_file: .env
|
|
||||||
environment:
|
|
||||||
DJANGO_SETTINGS_MODULE: config.settings.production
|
|
||||||
volumes:
|
|
||||||
- /srv/sum/nohype/static:/app/staticfiles
|
|
||||||
- /srv/sum/nohype/media:/app/media
|
|
||||||
ports:
|
|
||||||
- "127.0.0.1:8001:8000"
|
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: postgres:16-alpine
|
|
||||||
env_file: .env
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: nohype
|
|
||||||
POSTGRES_USER: nohype
|
|
||||||
volumes:
|
|
||||||
- nohype_pg:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U nohype -d nohype"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
start_period: 10s
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
nohype_pg:
|
|
||||||
@@ -3,9 +3,7 @@ services:
|
|||||||
build: .
|
build: .
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
command: >
|
command: >
|
||||||
sh -c "python manage.py tailwind install --no-input &&
|
sh -c "python manage.py migrate --noinput &&
|
||||||
python manage.py tailwind build &&
|
|
||||||
python manage.py migrate --noinput &&
|
|
||||||
python manage.py seed_e2e_content &&
|
python manage.py seed_e2e_content &&
|
||||||
python manage.py runserver 0.0.0.0:8000"
|
python manage.py runserver 0.0.0.0:8000"
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
Reference in New Issue
Block a user