{"id":20984718,"url":"https://github.com/dtcooper/jewpizza","last_synced_at":"2025-05-14T17:31:06.758Z","repository":{"id":141540116,"uuid":"359556345","full_name":"dtcooper/jewpizza","owner":"dtcooper","description":"A serious website for a serious domain name.","archived":false,"fork":false,"pushed_at":"2025-03-07T22:55:10.000Z","size":39804,"stargazers_count":8,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-10T06:04:21.718Z","etag":null,"topics":["alpinejs","clang-thud-its-a-darn-jews-panda","daisyui","django","docker","docker-compose","github-actions","huey","icecast","liquidsoap","navigo","nchan","nginx","redis","tailwindcss","umami"],"latest_commit_sha":null,"homepage":"https://jew.pizza/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dtcooper.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-19T18:15:12.000Z","updated_at":"2024-09-27T08:13:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"cd9aa649-7d47-419b-b9ee-db106fb1c28f","html_url":"https://github.com/dtcooper/jewpizza","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcooper%2Fjewpizza","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcooper%2Fjewpizza/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcooper%2Fjewpizza/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dtcooper%2Fjewpizza/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dtcooper","download_url":"https://codeload.github.com/dtcooper/jewpizza/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254194791,"owners_count":22030429,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alpinejs","clang-thud-its-a-darn-jews-panda","daisyui","django","docker","docker-compose","github-actions","huey","icecast","liquidsoap","navigo","nchan","nginx","redis","tailwindcss","umami"],"created_at":"2024-11-19T05:54:19.740Z","updated_at":"2025-05-14T17:31:01.751Z","avatar_url":"https://github.com/dtcooper.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [jew.pizza][jewpizza-url] Website ✡️🍕\n\n[![][jewpizza-badge]][jewpizza-url]\n[![][stack-badge]][stack-url]\n[![][license-badge]][license-url]\n[![][hurd-badge]][hurd-url]\n\n[![][build-badge]][build-url]\n[![][last-commit-badge]][last-commit-url]\n[![][stars-badge]][stars-url]\n\n[![][app-container-badge]][app-container-url]\n[![][radio-container-badge]][radio-container-url]\n[![][nginx-container-badge]][nginx-container-url]\n[![][icecast-container-badge]][icecast-container-url]\n\nHere's the code for the website that powers [jew.pizza][jewpizza-url], my\npersonal website. Built using the\n[CLANG! THUD! IT'S A DARN JEW'S PANDA!][stack-url] stack.\n\n\n## Preface\n\nI can't imagine _why on earth_ in a million years you'd want to run this code.\nSo, these instructions are mostly for me \u0026mdash; in case of sudden amnesia or\ncoming back to this project after a period of neglect.\n\n\n## Stack \u0026mdash; **CLANG! THUD! IT'S A DARN JEW'S PANDA!**\n\nIt's built using the _wildly_ popular and _extremely_ common **CLANG! THUD! IT'S\nA DARN JEW'S PANDA!** stack, ie,\n\n* **C** is for [Compose][docker-compose-url], ie Docker Compose, a\n    multi-container orchestration tool;\n* **L** is for [Liquidsoap][liquidsoap-url], a fantastic scripting language for\n    declaratively describing audio streams;\n* **A** is for [Alpine Linux][alpine-linux-url], a lightweight\n    [Linux][linux-url] distribution perfect for containers, based on\n    [musl libc][musl-url] and [BusyBox][busybox-url];\n* **N** is for [nginx][nginx-url], a web server and\n    [reverse proxy][reverse-proxy-url] using the\n    [jonasal/nginx-certbot][nginx-certbot-url] container as its base (for\n    [HTTPS][https-url]), using [embedded Lua][nginx-lua-url];\n* **G** is for [Gunicorn][gunicorn-url] to run the web app via\n    [Python][python-url]'s [Web Server Gateway Interface][wsgi-url];\n* **T** is for [Tailwind CSS][tailwind-url], a utility-first CSS framework;\n* **H** is for [huey][huey-url], a lightweight asynchronous task queue for\n    [Python][python-url];\n* **U** is for [Umami][umami-url] to get insights via web analytics;\n* **D** is for [Docker][docker-url] to run all this crap in containers;\n* **I** for [Icecast][icecast-url], a streaming media server for listeners to\n    connect (using [Karl Heyes's fork][icecast-kh-url]);\n* **T** for [Twilio][twilio-url], an API to send programmable communications —\n    in this case, [text messages (SMS)][sms-url];\n* **S** for [S3][amazon-s3-url], ie Amazon S3 Cloud Object Storage, to store\n    large audio files (I use the compatible\n    [DigitalOcean Spaces][digitalocean-spaces-url]);\n* **A** is for [AlpineJS][alpinejs-url], a lightweight, reactive front-end\n    [JavaScript][javascript-url] framework;\n* **D** is for [Django][django-url], a [Python][python-url] back-end web\n    framework;\n* **A** is for Actions, ie [GitHub Actions][github-actions-url], to continuously\n    and automatically build, test and deploy this code;\n* **R** is for [Redis][redis-url], a data store and message broker;\n* **N** is for [Navigo][navigo-url] that provides a simple [SPA][spa-url]\n    router;\n* **J** is for [Jinja][jinja-url] templating — like [Django][django-url]'s,\n    but less sucky;\n* **E** is for [esbuild][esbuild-url], a fast [JavaScript][javascript-url]\n    bundler;\n* **W** is for [WaveSurfer.js][wavesurfer-url], a front-end audio player with\n    waveform visualizations;\n* **S** is for [Server-Sent Events (SSE)][sse-url], to send realtime messages to\n    the browser;\n* **P** is for [PostgresSQL][postgres-url], a [SQL][sql-url] database;\n* **A** for [autoheal][autoheal-url], ie Docker Autoheal, a tool to monitor and\n    restart unhealthy docker containers;\n* **N** is for [Nchan][nchan-url], an [nginx][nginx-url] module managing\n    [EventSource][eventsource-url] ([SSE][sse-url]) clients;\n* **D** is for [daisyUI][daisyui-url], a lightweight UI component framework on\n    top of [Tailwind CSS][tailwind-url]; and\n* **A** is for [audiowaveform][audiowaveform-url], The [BBC][bbc-url]'s offline\n    rendering tool for generating waveforms for [WaveSurfer.js][wavesurfer-url].\n\n**CLANG! THUD! IT'S A DARN JEW'S PANDA!** A very well-known acronym in the\nengineering world, _probably._ I definitely didn't just make this up as a joke.\n\n\n## Prerequisites\n\nEverything runs with [Docker][docker-url] and\n[Docker Compose][docker-compose-url], including [nginx][nginx-url]. This can be\ndeployed on any [Linux][linux-url] machine.\n\nInstalling, compiling, running, and maintaining the motley crew of technologies\nthat make up the [**CLANG! THUD! IT'S A DARN JEW'S PANDA!**][stack-url] stack in\nboth prod and dev environments would be an absolute nightmare. With\n[Docker][docker-url] and [Docker Compose][docker-compose-url], that can be done\nin just a couple of commands. It even works with\n[Docker Desktop on macOS][docker-for-mac-url]!\n\nTo install these on [Debian][debian-url]/[Ubuntu][ubuntu-url],\n\n```bash\n# Install Docker\ncurl -fsSL https://get.docker.com | sh\n\n# Install latest Compose\nsudo mkdir -p /usr/local/lib/docker/cli-plugins/\nsudo curl -fsSL -o /usr/local/lib/docker/cli-plugins/docker-compose \\\n    \"$(curl -fsSL https://api.github.com/repos/docker/compose/releases/latest | grep browser_download_url | cut -d '\"' -f 4 | grep -i \"$(uname -s)-$(arch)$\")\"\nsudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose\n```\n\n\n## Initial Setup\nClone, then copy and edit the `.env` file, and optionally copy over the\n[Docker Compose][docker-compose-url] dev overrides.\n\n```bash\ngit clone https://github.com/dtcooper/jewpizza.git\n\n# Edit me, make sure you set SECRET_KEY!\ncp .env.sample .env\n\n# Needed for development only (when DEBUG=1)\nln -s docker-compose.dev.yml docker-compose.override.yml\n```\n\nAssuming you set `DOMAIN_NAME=local.jew.pizza` for local development, you'll\nwant to properly point your system's DNS that way. For example, add the following\nto `/etc/hosts`.\n\n```\n# jew.pizza local development\n127.0.0.1 local.jew.pizza\n127.0.0.1 analytics.local.jew.pizza umami.local.jew.pizza\n127.0.0.1 etc.local.jew.pizza\n127.0.0.1 priv.local.jew.pizza\n127.0.0.1 radio.local.jew.pizza play.local.jew.pizza listen.local.jew.pizza\n127.0.0.1 www.local.jew.pizza\n```\n\nIf you set `NGINX_USE_LOCAL_CERTIFICATE_AUTHORITY=1` (and you **should** for\nlocal development), you'll want to install the phony certificate authority's\nroot certificate located at `\u003cproject-dir\u003e/local-certificate-authority/caCert.pem`.\nIt expires every 30 days.\n\n\n## Running\n\n### Development Mode (`DEBUG=1` with `docker-compose.dev.yml` symlinked)\n\nBuild and start containers,\n\n```bash\nmake build\ndocker compose up\n```\n\nThe development `app` server will run at \u003chttp://localhost:8000/\u003e, or if you've\nset a `DOMAIN_NAME` and your `/etc/hosts` to work properly with it, navigate to\nthat. For example, \u003chttps://local.jew.pizza/\u003e. You'll need to install the phony\ncertificate authority's root certificate (see above).\n\n\n#### Miscellaneous Development Operations\n\n```bash\n# Django management command\ndocker compose run --rm app ./manage.py\n\n# Run shell in app container (make shell)\ndocker compose run --rm app bash\n\n# Pre commit checks + reformatting (not required)\nmake pre-commit\n```\n\n#### Faster Start Time (SSL Certificate Generation)\n\nThe entropy daemon [haveged][haveged-url] is a nice-to-have to provide your\nsystem with randomness to speed up SSL certificate generation. On\n[Debian][debian-url]/[Ubuntu][ubuntu-url], it can be installed via the\nfollowing,\n\n```bash\nsudo apt-get install haveged\n```\n\n\n### Production Mode (`DEBUG=0`)\n\nPull (or build) containers and run `docker compose up` in daemon mode (`-d`).\nSet all appropriate variables in the `.env` file, making note to properly\nconfigure the following,\n\n* An SMTP server \u0026mdash; works with [SendGrid][sendgrid-url]\n* [Twilio][twilio-url] account SID and auth token\n* [DigitalOcean][digitalocean-url] [Spaces][digitalocean-spaces-url], along with\n    an API key, taking note to run the domain name's DNS off of\n    [DigitalOcean][digitalocean-url]. This is necessary for wildcard certificates\n    from [Certbot][certbot-url]/[Lets Encrypt][letsencrypt-url].\n\n```bash\ndocker compose pull\n# Or optionally build the containers via: make build\ndocker compose up -d\n```\n\n#### Change Passwords\n\nMake sure to change these insecure passwords not sent in the `.env` file,\n\n* Django: `dave:cooper`\n* Umami: `dave:cooper`\n\n\n## Automatic Deploying\n\nYou can automatically deploy the code one of two ways via\n[GitHub Actions][github-actions-url],\n\n1. Include the string `[deploy]` (or `🚀`) in your HEAD commit message and push;\n    or\n2. Trigger the [Deploy Workflow][deploy-workflow-url] manually.\n\n\n## License\n\nThis project is licensed under the [MIT License][mit-license-url] \u0026mdash; see\nthe [LICENSE][license-url] file for details.\n\n## Final Note\n\n**_...and remember kids, have fun!_**\n\n[app-container-badge]: https://img.shields.io/badge/container-app-informational?logo=docker\u0026logoColor=ffffff\u0026style=flat-square\n[app-container-url]: https://github.com/dtcooper/jewpizza/pkgs/container/jewpizza-app\n[icecast-container-badge]: https://img.shields.io/badge/container-icecast-informational?logo=docker\u0026logoColor=ffffff\u0026style=flat-square\n[icecast-container-url]: https://github.com/dtcooper/jewpizza/pkgs/container/jewpizza-icecast\n[nginx-container-badge]: https://img.shields.io/badge/container-nginx-informational?logo=docker\u0026logoColor=ffffff\u0026style=flat-square\n[nginx-container-url]: https://github.com/dtcooper/jewpizza/pkgs/container/jewpizza-nginx\n[radio-container-badge]: https://img.shields.io/badge/container-radio-informational?logo=docker\u0026logoColor=ffffff\u0026style=flat-square\n[radio-container-url]: https://github.com/dtcooper/jewpizza/pkgs/container/jewpizza-radio\n\n[build-badge]: https://img.shields.io/github/workflow/status/dtcooper/jewpizza/Build%20and%20Deploy?label=build%20%26%20deploy\u0026logo=github\u0026style=flat-square\n[build-url]: https://github.com/dtcooper/jewpizza/actions/workflows/docker-build.yml\n[hurd-badge]: https://img.shields.io/badge/GNU%20hurd-incompatable-critical?logo=gnu\u0026logoColor=white\u0026style=flat-square\n[hurd-url]: https://github.com/dtcooper/jewpizza/issues/1\n[jewpizza-badge]: https://img.shields.io/badge/website-jew.pizza-informational?style=flat-square\n[jewpizza-url]: https://jew.pizza/\n[stack-badge]: https://img.shields.io/badge/stack-CLANG%21%20THUD%21%20IT%27S%20A%20DARN%20JEW%27S%20PANDA%21-informational?style=flat-square\n[stack-url]: https://github.com/dtcooper/jewpizza#stack--clang-thud-its-a-darn-jews-panda\n[last-commit-badge]: https://img.shields.io/github/last-commit/dtcooper/jewpizza/main?logo=github\u0026style=flat-square\n[last-commit-url]: https://github.com/dtcooper/jewpizza/commits/main\n[license-badge]: https://img.shields.io/github/license/dtcooper/jewpizza?style=flat-square\u0026color=success\n[license-url]: https://github.com/dtcooper/jewpizza/blob/main/LICENSE\n[stars-badge]: https://img.shields.io/github/stars/dtcooper/jewpizza?logo=github\u0026style=flat-square\n[stars-url]: https://github.com/dtcooper/jewpizza/stargazers\n\n[alpine-linux-url]: https://alpinelinux.org/\n[alpinejs-url]: https://alpinejs.dev/\n[amazon-s3-url]: https://aws.amazon.com/s3/\n[audiowaveform-url]: https://github.com/bbc/audiowaveform\n[autoheal-url]: https://github.com/willfarrell/docker-autoheal\n[bbc-url]: https://www.bbc.com/\n[busybox-url]: https://busybox.net/\n[certbot-url]: https://certbot.eff.org/\n[daisyui-url]: https://daisyui.com/\n[debian-url]: https://www.debian.org/\n[digitalocean-spaces-url]: https://www.digitalocean.com/products/spaces\n[digitalocean-url]: https://www.digitalocean.com/\n[django-url]: https://www.djangoproject.com/\n[docker-compose-url]: https://docs.docker.com/compose/\n[docker-for-mac-url]: https://docs.docker.com/desktop/mac/install/\n[docker-url]: https://www.docker.com/\n[deploy-workflow-url]: https://github.com/dtcooper/jewpizza/actions/workflows/deploy.yml\n[esbuild-url]: https://esbuild.github.io/\n[eventsource-url]: https://developer.mozilla.org/en-US/docs/Web/API/EventSource\n[github-actions-url]: https://docs.github.com/en/actions\n[gunicorn-url]: https://gunicorn.org/\n[haveged-url]: https://www.issihosts.com/haveged/\n[https-url]: https://en.wikipedia.org/wiki/HTTPS\n[huey-url]: https://huey.readthedocs.io/\n[icecast-kh-url]: https://github.com/karlheyes/icecast-kh\n[icecast-url]: https://icecast.org/\n[javascript-url]: https://developer.mozilla.org/en-US/docs/Web/JavaScript\n[jinja-url]: https://jinja.palletsprojects.com/\n[letsencrypt-url]: https://letsencrypt.org/\n[linux-url]: https://www.kernel.org/\n[liquidsoap-url]: https://www.liquidsoap.info/\n[mit-license-url]: https://en.wikipedia.org/wiki/MIT_License\n[musl-url]: https://musl.libc.org/\n[navigo-url]: https://github.com/krasimir/navigo\n[nchan-url]: https://nchan.io/\n[nginx-certbot-url]: https://github.com/JonasAlfredsson/docker-nginx-certbot/\n[nginx-lua-url]: https://github.com/openresty/lua-nginx-module\n[nginx-url]: https://www.nginx.com/\n[postgres-url]: https://www.postgresql.org/\n[python-url]: https://www.python.org/\n[redis-url]: https://redis.io/\n[reverse-proxy-url]: https://en.wikipedia.org/wiki/Reverse_proxy\n[sendgrid-url]: https://sendgrid.com/\n[sms-url]: https://en.wikipedia.org/wiki/SMS\n[spa-url]: https://en.wikipedia.org/wiki/Single-page_application\n[sql-url]: https://en.wikipedia.org/wiki/SQL\n[sse-url]: https://en.wikipedia.org/wiki/Server-sent_events\n[tailwind-url]: https://tailwindcss.com/\n[twilio-url]: https://www.twilio.com/\n[ubuntu-url]: https://ubuntu.com/\n[umami-url]: https://umami.is/\n[wavesurfer-url]: https://wavesurfer-js.org/\n[web-app-url]: https://en.wikipedia.org/wiki/Web_application\n[wsgi-url]: https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdtcooper%2Fjewpizza","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdtcooper%2Fjewpizza","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdtcooper%2Fjewpizza/lists"}