diff --git a/.dockerignore b/.dockerignore index a715c9d7..c78a38ef 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,5 @@ .git .env +*.pyc +__pycache__ +dynamicweb/settings/dynamic.py diff --git a/.env.docker b/.env.docker new file mode 100644 index 00000000..4505a0f2 --- /dev/null +++ b/.env.docker @@ -0,0 +1,41 @@ +# Dev defaults for docker compose. Override any value in a local ".env" file. +# DEBUG=True makes settings load local.py (ALLOWED_HOSTS=*, console email). +DEBUG=True +ENABLE_LOGGING=False +LOG_LEVEL=DEBUG + +# Leave empty: the entrypoint generates and persists one in the "appdata" volume +DJANGO_SECRET_KEY= + +POSTGRES_DB=app +POSTGRES_USER=app +POSTGRES_PASSWORD=app +POSTGRES_HOST=db + +CELERY_BROKER_URL=redis://redis:6379/0 +CELERY_RESULT_BACKEND=redis://redis:6379/0 + +# Host -> urlconf. Add the VPS IP / domain here if you access it that way. +UNGLEICH_SITE_CONFIGS={"ungleich.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"blog.ungleich.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"comic.ungleich.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"digitalglarus.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"datacenterlight.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"rails-hosting.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"django-hosting.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"node-hosting.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"devuanhosting.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"devuanhosting.com":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"ipv6onlyhosting.com":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"digitalezukunft.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"hack4glarus.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"xn--nglarus-n2a.ch":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"localhost:8000":{"MULTISITE_CMS_URL":"dynamicweb.urls"},"127.0.0.1:8000":{"MULTISITE_CMS_URL":"dynamicweb.urls"}} +UNGLEICH_BLOG_SITE_ID=1 +MULTISITE_CMS_FALLBACK= + +EMAIL_HOST=localhost +DCL_ERROR_EMAILS_TO=dev@example.com +ADMIN_EMAIL=dev@example.com +DCL_SUPPORT_FROM_ADDRESS=dev@example.com +WEBHOOK_SECRET=dev +RECAPTCHA_PUBLIC_KEY=dev +RECAPTCHA_PRIVATE_KEY=dev +STRIPE_API_PRIVATE_KEY= +STRIPE_API_PUBLIC_KEY= +STRIPE_API_PRIVATE_KEY_TEST= + +# OpenNebula / LDAP are not available in the test env +OPENNEBULA_USERNAME=oneadmin +OPENNEBULA_PASSWORD=opennebula +OPENNEBULA_PROTOCOL=http +# "test_domain" skips the import-time VMTemplate query (tables do not exist before migrate) +OPENNEBULA_DOMAIN=test_domain +OPENNEBULA_PORT=2633 +OPENNEBULA_ENDPOINT=/RPC2 diff --git a/.gitignore b/.gitignore index a41d813d..fb7ad783 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,10 @@ secret-key 2024-* 2025-* 2023-* + +.env +dynamicweb/settings/dynamic.py + +# database dumps are kept out of git (personal data) +db-init/*.sql +db-init/*.sql.gz diff --git a/db-init/README.md b/db-init/README.md new file mode 100644 index 00000000..812b5d71 --- /dev/null +++ b/db-init/README.md @@ -0,0 +1 @@ +# Put a Postgres dump here (*.sql or *.sql.gz); it is restored on first start. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..3e5d2e68 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +x-app: &app + build: . + env_file: + - .env.docker + - path: .env # optional local overrides + required: false + volumes: + - appdata:/data # generated secret key + - media:/usr/src/app/media + - logs:/usr/src/app/logs + depends_on: [db, redis] + +services: + db: + image: postgres:12-alpine + environment: + POSTGRES_DB: app + POSTGRES_USER: app + POSTGRES_PASSWORD: app + volumes: + - pgdata:/var/lib/postgresql/data + # any *.sql / *.sql.gz here is restored on the first start (empty pgdata) + - ./db-init:/docker-entrypoint-initdb.d:ro + + redis: + image: redis:6-alpine + + web: + <<: *app + command: sh start-web.sh + ports: + - "8000:8000" + + celery: + <<: *app + command: celery -A dynamicweb worker -l info + +volumes: + pgdata: + appdata: + media: + logs: diff --git a/entrypoint.sh b/entrypoint.sh index e207a457..7d024a79 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,19 +1,50 @@ #!/bin/sh -set -uex +set -ue cd /usr/src/app/ -cat > dynamicweb/settings/dynamic.py < "$TMP_KEY" + # hard link is atomic: only one container wins the race + ln "$TMP_KEY" "$KEY_FILE" 2>/dev/null || true + rm -f "$TMP_KEY" + fi + DJANGO_SECRET_KEY="$(cat "$KEY_FILE")" + export DJANGO_SECRET_KEY +fi + +cat > dynamicweb/settings/dynamic.py <