mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-06 13:45:17 +02:00
feat(devsecops): optimized runtime containers
organized docker-compose files updated pipelines to fix created date using nonroot user in runtime environment synced .env.example and docker compose file normalized usage of PG variables
This commit is contained in:
parent
cadea118d3
commit
3c3288eab9
29 changed files with 784 additions and 412 deletions
57
.env.example
57
.env.example
|
@ -1,47 +1,46 @@
|
||||||
# 🌐 Frontend
|
# 🌐 Frontend
|
||||||
|
FRONTEND_PORT=8015 # Don't forget to update CSRF_TRUSTED_ORIGINS in backend and FRONTEND_URL in backend and ORIGIN in frontend if you make changes to this.
|
||||||
PUBLIC_SERVER_URL=http://server:8000 # PLEASE DON'T CHANGE :) - Should be the service name of the backend with port 8000, even if you change the port in the backend service. Only change if you are using a custom more complex setup.
|
PUBLIC_SERVER_URL=http://server:8000 # PLEASE DON'T CHANGE :) - Should be the service name of the backend with port 8000, even if you change the port in the backend service. Only change if you are using a custom more complex setup.
|
||||||
ORIGIN=http://localhost:8015
|
ORIGIN=http://localhost:8015
|
||||||
BODY_SIZE_LIMIT=Infinity
|
BODY_SIZE_LIMIT=Infinity
|
||||||
FRONTEND_PORT=8015
|
|
||||||
|
|
||||||
# 🐘 PostgreSQL Database
|
# 🐘 PostgreSQL Database
|
||||||
PGHOST=db
|
PGHOST=db # Supposed to match the host of the postgis database
|
||||||
POSTGRES_DB=database
|
POSTGRES_DB=adventureloga
|
||||||
POSTGRES_USER=adventure
|
POSTGRES_USER=adventurelog
|
||||||
POSTGRES_PASSWORD=changeme123
|
POSTGRES_PASSWORD=changeme123
|
||||||
|
|
||||||
# 🔒 Django Backend
|
# 🔒 Django Backend
|
||||||
SECRET_KEY=changeme123
|
SECRET_KEY=changeme123 # Replace with the actual secret key
|
||||||
DJANGO_ADMIN_USERNAME=admin
|
DJANGO_ADMIN_USERNAME=admin # Replace with the actual admin username
|
||||||
DJANGO_ADMIN_PASSWORD=admin
|
DJANGO_ADMIN_PASSWORD=admin # Replace with the actual admin password
|
||||||
DJANGO_ADMIN_EMAIL=admin@example.com
|
DJANGO_ADMIN_EMAIL=admin@example.com # Replace with the actual admin email
|
||||||
PUBLIC_URL=http://localhost:8016 # Match the outward port, used for the creation of image urls
|
BACKEND_PORT=8016 # Don't forget to update CSRF_TRUSTED_ORIGINS and PUBLIC_URL in backend, and PUBLIC_SERVER_URL in frontend if you make changes to this.
|
||||||
CSRF_TRUSTED_ORIGINS=http://localhost:8016,http://localhost:8015
|
PUBLIC_URL=http://localhost:8016 # Replace with your domain where the backend is accessible publicly, used for the creation of image urls
|
||||||
DEBUG=False
|
CSRF_TRUSTED_ORIGINS=http://localhost:8016,http://localhost:8015 # Replace with your domain, if applicable
|
||||||
FRONTEND_URL=http://localhost:8015 # Used for email generation. This should be the url of the frontend
|
FRONTEND_URL=http://localhost:8015 # Replace with your domain where the frontend is accessible, used for email generation.
|
||||||
BACKEND_PORT=8016
|
# Disabling Registration: https://adventurelog.app/docs/configuration/disable_registration.html
|
||||||
|
# DISABLE_REGISTRATION=False
|
||||||
|
# DISABLE_REGISTRATION_MESSAGE='Registration is disabled for this instance of AdventureLog.'
|
||||||
|
|
||||||
# Optional: use Google Maps integration
|
|
||||||
# https://adventurelog.app/docs/configuration/google_maps_integration.html
|
|
||||||
# GOOGLE_MAPS_API_KEY=your_google_maps_api_key
|
|
||||||
|
|
||||||
# Optional: disable registration
|
# Integrations
|
||||||
# https://adventurelog.app/docs/configuration/disable_registration.html
|
## Email: https://adventurelog.app/docs/configuration/email.html
|
||||||
DISABLE_REGISTRATION=False
|
|
||||||
# DISABLE_REGISTRATION_MESSAGE=Registration is disabled for this instance of AdventureLog.
|
|
||||||
|
|
||||||
# Optional: Use email
|
|
||||||
# https://adventurelog.app/docs/configuration/email.html
|
|
||||||
# EMAIL_BACKEND=email
|
# EMAIL_BACKEND=email
|
||||||
# EMAIL_HOST=smtp.gmail.com
|
# EMAIL_HOST=smtp.mail.com
|
||||||
# EMAIL_USE_TLS=True
|
# EMAIL_USE_TLS=False
|
||||||
# EMAIL_PORT=587
|
# EMAIL_PORT=587
|
||||||
# EMAIL_USE_SSL=False
|
# EMAIL_USE_SSL=True
|
||||||
# EMAIL_HOST_USER=user
|
# EMAIL_HOST_USER=user
|
||||||
# EMAIL_HOST_PASSWORD=password
|
# EMAIL_HOST_PASSWORD=password
|
||||||
# DEFAULT_FROM_EMAIL=user@example.com
|
# DEFAULT_FROM_EMAIL=adventurelog@example.com
|
||||||
|
|
||||||
# Optional: Use Umami for analytics
|
## Google Maps: https://adventurelog.app/docs/configuration/google_maps_integration.html
|
||||||
# https://adventurelog.app/docs/configuration/analytics.html
|
# GOOGLE_MAPS_API_KEY=your_google_maps_api_key
|
||||||
|
|
||||||
|
## Umami for analytics: https://adventurelog.app/docs/configuration/analytics.html
|
||||||
# PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js # If you are using the hosted version of Umami
|
# PUBLIC_UMAMI_SRC=https://cloud.umami.is/script.js # If you are using the hosted version of Umami
|
||||||
# PUBLIC_UMAMI_WEBSITE_ID=
|
# PUBLIC_UMAMI_WEBSITE_ID=
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
DEBUG=false # Use to enable debugging
|
4
.github/.docker-compose-database.yml
vendored
4
.github/.docker-compose-database.yml
vendored
|
@ -6,8 +6,8 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:5432:5432"
|
- "127.0.0.1:5432:5432"
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: database
|
POSTGRES_DB: adventurelog
|
||||||
POSTGRES_USER: adventure
|
POSTGRES_USER: adventurelog
|
||||||
POSTGRES_PASSWORD: changeme123
|
POSTGRES_PASSWORD: changeme123
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data/
|
- postgres_data:/var/lib/postgresql/data/
|
||||||
|
|
43
.github/workflows/backend-beta.yml
vendored
43
.github/workflows/backend-beta.yml
vendored
|
@ -36,11 +36,42 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: "${{ github.repository_owner }}"
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "GIT_TAG=$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || echo unknown)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build and push Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:beta -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:beta ./backend
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg GIT_TAG=${{ steps.vars.outputs.GIT_TAG }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/$REPO_OWNER/$IMAGE_NAME:beta \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:beta \
|
||||||
|
./backend
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for backend beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for backend beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
41
.github/workflows/backend-latest.yml
vendored
41
.github/workflows/backend-latest.yml
vendored
|
@ -36,11 +36,42 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: '${{ github.repository_owner }}'
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "GIT_TAG=$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || echo unknown)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build and push Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:latest -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:latest ./backend
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg GIT_TAG=${{ steps.vars.outputs.GIT_TAG }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/${{ steps.vars.outputs.REPO_OWNER }}/$IMAGE_NAME:latest \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:latest \
|
||||||
|
./backend
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for backend latest\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for backend latest\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
44
.github/workflows/backend-release.yml
vendored
44
.github/workflows/backend-release.yml
vendored
|
@ -33,11 +33,43 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: "${{ github.repository_owner }}"
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "GIT_TAG=$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || echo unknown)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build and push Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:${{ github.event.release.tag_name }} -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:${{ github.event.release.tag_name }} ./backend
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg GIT_TAG=${{ steps.vars.outputs.GIT_TAG }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/${{ steps.vars.outputs.REPO_OWNER }}/$IMAGE_NAME:${{ github.event.release.tag_name }} \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:${{ github.event.release.tag_name }} \
|
||||||
|
./backend
|
||||||
|
|
||||||
|
|
||||||
|
# # Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for backend release ${{ github.event.release.tag_name }}\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for backend release ${{ github.event.release.tag_name }}\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
8
.github/workflows/backend-test.yml
vendored
8
.github/workflows/backend-test.yml
vendored
|
@ -43,10 +43,10 @@ jobs:
|
||||||
working-directory: backend/server
|
working-directory: backend/server
|
||||||
env:
|
env:
|
||||||
PGHOST: "127.0.0.1"
|
PGHOST: "127.0.0.1"
|
||||||
PGDATABASE: "database"
|
POSTGRES_DB: "adventurelog"
|
||||||
PGUSER: "adventure"
|
POSTGRES_USER: "adventurelog"
|
||||||
PGPASSWORD: "changeme123"
|
POSTGRES_PASSWORD: "changeme123"
|
||||||
SECRET_KEY: "changeme123"
|
SECRET_KEY: "secretkey"
|
||||||
DJANGO_ADMIN_USERNAME: "admin"
|
DJANGO_ADMIN_USERNAME: "admin"
|
||||||
DJANGO_ADMIN_PASSWORD: "admin"
|
DJANGO_ADMIN_PASSWORD: "admin"
|
||||||
DJANGO_ADMIN_EMAIL: "admin@example.com"
|
DJANGO_ADMIN_EMAIL: "admin@example.com"
|
||||||
|
|
39
.github/workflows/cdn-beta.yml
vendored
39
.github/workflows/cdn-beta.yml
vendored
|
@ -36,11 +36,40 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: "${{ github.repository_owner }}"
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:beta -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:beta ./cdn
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/${{ steps.vars.outputs.REPO_OWNER }}/$IMAGE_NAME:beta \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:beta \
|
||||||
|
./cdn
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for CDN beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for CDN beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
39
.github/workflows/cdn-latest.yml
vendored
39
.github/workflows/cdn-latest.yml
vendored
|
@ -36,11 +36,40 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: "${{ github.repository_owner }}"
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:latest -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:latest ./cdn
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/${{ steps.vars.outputs.REPO_OWNER }}/$IMAGE_NAME:latest \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:latest \
|
||||||
|
./cdn
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for CDN latest\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for CDN latest\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
40
.github/workflows/cdn-release.yml
vendored
40
.github/workflows/cdn-release.yml
vendored
|
@ -33,11 +33,41 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: "${{ github.repository_owner }}"
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:${{ github.event.release.tag_name }} -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:${{ github.event.release.tag_name }} ./cdn
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/${{ steps.vars.outputs.REPO_OWNER }}/$IMAGE_NAME:${{ github.event.release.tag_name }} \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:${{ github.event.release.tag_name }} \
|
||||||
|
./cdn
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for CDN release ${{ github.event.release.tag_name }}\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for CDN release ${{ github.event.release.tag_name }}\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
|
43
.github/workflows/frontend-beta.yml
vendored
43
.github/workflows/frontend-beta.yml
vendored
|
@ -36,11 +36,42 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: "${{ github.repository_owner }}"
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "GIT_TAG=$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || echo unknown)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build and push Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:beta -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:beta ./frontend
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg GIT_TAG=${{ steps.vars.outputs.GIT_TAG }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/$REPO_OWNER/$IMAGE_NAME:beta \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:beta \
|
||||||
|
./frontend
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for frontend beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for frontend beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
41
.github/workflows/frontend-latest.yml
vendored
41
.github/workflows/frontend-latest.yml
vendored
|
@ -36,11 +36,42 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: '${{ github.repository_owner }}'
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "GIT_TAG=$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || echo unknown)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build and push Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:latest -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:latest ./frontend
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg GIT_TAG=${{ steps.vars.outputs.GIT_TAG }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/$REPO_OWNER/$IMAGE_NAME:latest \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:latest \
|
||||||
|
./frontend
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for frontend beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for frontend beta\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
43
.github/workflows/frontend-release.yml
vendored
43
.github/workflows/frontend-release.yml
vendored
|
@ -33,11 +33,42 @@ jobs:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: set lower case owner name
|
- name: Set build metadata
|
||||||
run: |
|
id: vars
|
||||||
echo "REPO_OWNER=${OWNER,,}" >>${GITHUB_ENV}
|
|
||||||
env:
|
env:
|
||||||
OWNER: "${{ github.repository_owner }}"
|
OWNER: '${{ github.repository_owner }}'
|
||||||
|
run: |
|
||||||
|
echo "GIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
echo "GIT_TAG=$(git describe --tags --abbrev=0 --exact-match 2>/dev/null || echo unknown)" >> $GITHUB_OUTPUT
|
||||||
|
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
|
||||||
|
echo "REPO_OWNER=${OWNER,,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build Docker images
|
- name: Build and push Docker images
|
||||||
run: docker buildx build --platform linux/amd64,linux/arm64 --push -t ghcr.io/$REPO_OWNER/$IMAGE_NAME:${{ github.event.release.tag_name }} -t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:${{ github.event.release.tag_name }} ./frontend
|
run: |
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--push \
|
||||||
|
--build-arg GIT_SHA=${{ steps.vars.outputs.GIT_SHA }} \
|
||||||
|
--build-arg GIT_TAG=${{ steps.vars.outputs.GIT_TAG }} \
|
||||||
|
--build-arg BUILD_DATE=${{ steps.vars.outputs.BUILD_DATE }} \
|
||||||
|
-t ghcr.io/$REPO_OWNER/$IMAGE_NAME:${{ github.event.release.tag_name }} \
|
||||||
|
-t ${{ secrets.DOCKERHUB_USERNAME }}/$IMAGE_NAME:${{ github.event.release.tag_name }} \
|
||||||
|
./frontend
|
||||||
|
|
||||||
|
# Notify on success
|
||||||
|
# - name: Notify Discord on success
|
||||||
|
# if: success()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"✅ Build and push succeeded for frontend release ${{ github.event.release.tag_name }}\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
||||||
|
# # Notify on failure
|
||||||
|
# - name: Notify Discord on failure
|
||||||
|
# if: failure()
|
||||||
|
# run: |
|
||||||
|
# curl -H "Content-Type: application/json" \
|
||||||
|
# -X POST \
|
||||||
|
# -d "{\"username\": \"CI Bot\", \"content\": \"❌ Build or push failed for frontend release ${{ github.event.release.tag_name }}\"}" \
|
||||||
|
# ${{ secrets.DISCORD_WEBHOOK_BUILD }}
|
||||||
|
|
7
backend/.dockerignore
Normal file
7
backend/.dockerignore
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.env.example
|
||||||
|
.devcontainer
|
||||||
|
.github
|
||||||
|
server/build_files.sh
|
||||||
|
.gitignore
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
|
@ -1,7 +1,49 @@
|
||||||
# Use the official Python slim image as the base image
|
# -------------------
|
||||||
FROM python:3.13-slim
|
# Stage 1: Build Stage
|
||||||
|
# -------------------
|
||||||
|
FROM docker.io/python:3.13-alpine AS builder
|
||||||
|
|
||||||
|
# Build-time metadata
|
||||||
|
ARG GIT_SHA=unknown
|
||||||
|
ARG GIT_TAG=latest
|
||||||
|
ARG BUILD_DATE=unknown
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
PYTHONPATH=/install
|
||||||
|
|
||||||
|
# Install build dependencies for Alpine
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
build-base \
|
||||||
|
libpq \
|
||||||
|
libpq-dev \
|
||||||
|
gdal \
|
||||||
|
gdal-dev \
|
||||||
|
geos \
|
||||||
|
geos-dev \
|
||||||
|
postgresql-dev \
|
||||||
|
musl-dev \
|
||||||
|
python3-dev \
|
||||||
|
linux-headers \
|
||||||
|
git
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Copy entire project into /tmp
|
||||||
|
COPY . /tmp/
|
||||||
|
|
||||||
|
# Install Python dependencies into /install
|
||||||
|
RUN pip install --upgrade pip && \
|
||||||
|
pip install --target=/install -r /tmp/server/requirements.txt && \
|
||||||
|
python3 /tmp/server/manage.py collectstatic --noinput --verbosity 2
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------
|
||||||
|
# Stage 2: Final Production
|
||||||
|
# -------------------------
|
||||||
|
FROM docker.io/python:3.13-alpine AS final
|
||||||
|
|
||||||
# Metadata labels for the AdventureLog image
|
|
||||||
LABEL maintainer="Sean Morley" \
|
LABEL maintainer="Sean Morley" \
|
||||||
version="v0.10.0" \
|
version="v0.10.0" \
|
||||||
description="AdventureLog — the ultimate self-hosted travel companion." \
|
description="AdventureLog — the ultimate self-hosted travel companion." \
|
||||||
|
@ -12,49 +54,51 @@ LABEL maintainer="Sean Morley" \
|
||||||
org.opencontainers.image.url="https://raw.githubusercontent.com/seanmorley15/AdventureLog/refs/heads/main/brand/banner.png" \
|
org.opencontainers.image.url="https://raw.githubusercontent.com/seanmorley15/AdventureLog/refs/heads/main/brand/banner.png" \
|
||||||
org.opencontainers.image.source="https://github.com/seanmorley15/AdventureLog" \
|
org.opencontainers.image.source="https://github.com/seanmorley15/AdventureLog" \
|
||||||
org.opencontainers.image.vendor="Sean Morley" \
|
org.opencontainers.image.vendor="Sean Morley" \
|
||||||
org.opencontainers.image.created="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
|
org.opencontainers.image.version="${GIT_TAG}" \
|
||||||
|
org.opencontainers.image.revision="${GIT_SHA}" \
|
||||||
|
org.opencontainers.image.created="${BUILD_DATE}" \
|
||||||
org.opencontainers.image.licenses="GPL-3.0"
|
org.opencontainers.image.licenses="GPL-3.0"
|
||||||
|
|
||||||
# Set environment variables
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
PYTHONUNBUFFERED=1 \
|
||||||
ENV PYTHONUNBUFFERED=1
|
PYTHONPATH="/install:/code" \
|
||||||
|
PATH="/install/bin:${PATH}" \
|
||||||
|
GDAL_LIBRARY_PATH="/usr/lib/libgdal.so.36.3.10.3" \
|
||||||
|
GEOS_LIBRARY_PATH="/usr/lib/libgeos_c.so"
|
||||||
|
|
||||||
|
|
||||||
|
# Copy all from builder, organize in one RUN step
|
||||||
|
COPY --from=builder /install /install
|
||||||
|
COPY --from=builder /tmp /tmp
|
||||||
|
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
nginx\
|
||||||
|
supervisor\
|
||||||
|
bash\
|
||||||
|
curl\
|
||||||
|
libpq\
|
||||||
|
gdal\
|
||||||
|
gdal-dev\
|
||||||
|
geos\
|
||||||
|
geos-dev\
|
||||||
|
postgresql-client && \
|
||||||
|
mv /tmp/server /code && \
|
||||||
|
mkdir -p /code/static /code/media && \
|
||||||
|
mv /tmp/nginx.conf /etc/nginx/nginx.conf && \
|
||||||
|
mkdir -p /etc/supervisor/conf.d/ && \
|
||||||
|
mv /tmp/supervisord.conf /etc/supervisor/conf.d/supervisord.conf && \
|
||||||
|
mv /tmp/entrypoint.sh /code/entrypoint.sh && \
|
||||||
|
chmod +x /code/entrypoint.sh && \
|
||||||
|
rm -rf /tmp && \
|
||||||
|
addgroup -g 349 adventurelog && \
|
||||||
|
adduser -D -u 349 -G adventurelog adventurelog && \
|
||||||
|
chown -R 349:349 /code
|
||||||
|
|
||||||
# Set the working directory
|
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
|
|
||||||
# Install system dependencies (Nginx included)
|
|
||||||
RUN apt-get update \
|
|
||||||
&& apt-get install -y git postgresql-client gdal-bin libgdal-dev nginx supervisor \
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install Python dependencies
|
|
||||||
COPY ./server/requirements.txt /code/
|
|
||||||
RUN pip install --upgrade pip \
|
|
||||||
&& pip install -r requirements.txt
|
|
||||||
|
|
||||||
# Create necessary directories
|
|
||||||
RUN mkdir -p /code/static /code/media
|
|
||||||
# RUN mkdir -p /code/staticfiles /code/media
|
|
||||||
|
|
||||||
# Copy the Django project code into the Docker image
|
|
||||||
COPY ./server /code/
|
|
||||||
|
|
||||||
# Copy Nginx configuration
|
|
||||||
COPY ./nginx.conf /etc/nginx/nginx.conf
|
|
||||||
|
|
||||||
# Copy Supervisor configuration
|
|
||||||
COPY ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
|
||||||
|
|
||||||
# Collect static files
|
|
||||||
RUN python3 manage.py collectstatic --noinput --verbosity 2
|
|
||||||
|
|
||||||
# Set the entrypoint script
|
|
||||||
COPY ./entrypoint.sh /code/entrypoint.sh
|
|
||||||
RUN chmod +x /code/entrypoint.sh
|
|
||||||
|
|
||||||
# Expose ports for NGINX and Gunicorn
|
|
||||||
EXPOSE 80 8000
|
EXPOSE 80 8000
|
||||||
|
|
||||||
# Command to start Supervisor (which starts Nginx and Gunicorn)
|
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||||
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=5 \
|
||||||
|
CMD curl --fail --silent --show-error http://localhost:80/ || exit 1
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Function to check PostgreSQL availability
|
# Function to check PostgreSQL availability
|
||||||
# Helper to get the first non-empty environment variable
|
# Helper to get the first non-empty environment variable
|
||||||
|
@ -13,15 +13,20 @@ get_env() {
|
||||||
}
|
}
|
||||||
|
|
||||||
check_postgres() {
|
check_postgres() {
|
||||||
|
if ! command -v psql > /dev/null 2>&1; then
|
||||||
|
>&2 echo "psql command not found — PostgreSQL client is not installed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
local db_host
|
local db_host
|
||||||
local db_user
|
local db_user
|
||||||
local db_name
|
local db_name
|
||||||
local db_pass
|
local db_pass
|
||||||
|
|
||||||
db_host=$(get_env PGHOST)
|
db_host="$(get_env PGHOST)"
|
||||||
db_user=$(get_env PGUSER POSTGRES_USER)
|
db_user="$(get_env PGUSER POSTGRES_USER)"
|
||||||
db_name=$(get_env PGDATABASE POSTGRES_DB)
|
db_name="$(get_env PGDATABASE POSTGRES_DB)"
|
||||||
db_pass=$(get_env PGPASSWORD POSTGRES_PASSWORD)
|
db_pass="$(get_env PGPASSWORD POSTGRES_PASSWORD)"
|
||||||
|
|
||||||
PGPASSWORD="$db_pass" psql -h "$db_host" -U "$db_user" -d "$db_name" -c '\q' >/dev/null 2>&1
|
PGPASSWORD="$db_pass" psql -h "$db_host" -U "$db_user" -d "$db_name" -c '\q' >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
@ -73,8 +78,6 @@ else:
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Sync the countries and world travel regions
|
|
||||||
# Sync the countries and world travel regions
|
# Sync the countries and world travel regions
|
||||||
python manage.py download-countries
|
python manage.py download-countries
|
||||||
if [ $? -eq 137 ]; then
|
if [ $? -eq 137 ]; then
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
PGHOST=''
|
|
||||||
PGDATABASE=''
|
|
||||||
PGUSER=''
|
|
||||||
PGPASSWORD=''
|
|
||||||
|
|
||||||
SECRET_KEY='pleasechangethisbecauseifyoudontitwillbeverybadandyouwillgethackedinlessthanaminuteguaranteed'
|
|
||||||
|
|
||||||
PUBLIC_URL='http://127.0.0.1:8000'
|
|
||||||
|
|
||||||
DEBUG=True
|
|
||||||
|
|
||||||
FRONTEND_URL='http://localhost:3000'
|
|
||||||
|
|
||||||
EMAIL_BACKEND='console'
|
|
||||||
|
|
||||||
# EMAIL_BACKEND='email'
|
|
||||||
# EMAIL_HOST='smtp.gmail.com'
|
|
||||||
# EMAIL_USE_TLS=False
|
|
||||||
# EMAIL_PORT=587
|
|
||||||
# EMAIL_USE_SSL=True
|
|
||||||
# EMAIL_HOST_USER='user'
|
|
||||||
# EMAIL_HOST_PASSWORD='password'
|
|
||||||
# DEFAULT_FROM_EMAIL='user@example.com'
|
|
||||||
|
|
||||||
# GOOGLE_MAPS_API_KEY='key'
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------- #
|
|
||||||
# For Developers to start a Demo Database
|
|
||||||
# docker run --name adventurelog-development -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=admin -e POSTGRES_DB=adventurelog -p 5432:5432 -d postgis/postgis:15-3.3
|
|
||||||
|
|
||||||
# PGHOST='localhost'
|
|
||||||
# PGDATABASE='adventurelog'
|
|
||||||
# PGUSER='admin'
|
|
||||||
# PGPASSWORD='admin'
|
|
||||||
# ------------------- #
|
|
|
@ -20,12 +20,19 @@ load_dotenv()
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
# GDAL library version path
|
||||||
|
GDAL_LIBRARY_PATH = getenv('GDAL_LIBRARY_PATH', None)
|
||||||
|
|
||||||
|
# GEOS library version path
|
||||||
|
GEOS_LIBRARY_PATH = getenv('GEOS_LIBRARY_PATH', None)
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = getenv('SECRET_KEY')
|
SECRET_KEY = getenv('SECRET_KEY')
|
||||||
|
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = getenv('DEBUG', 'true').lower() == 'true'
|
DEBUG = getenv('DEBUG', 'true').lower() == 'true'
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,14 @@ nodaemon=true
|
||||||
|
|
||||||
[program:nginx]
|
[program:nginx]
|
||||||
command=/usr/sbin/nginx -g "daemon off;"
|
command=/usr/sbin/nginx -g "daemon off;"
|
||||||
|
user=nginx
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
|
|
||||||
[program:gunicorn]
|
[program:gunicorn]
|
||||||
command=/code/entrypoint.sh
|
command=/code/entrypoint.sh
|
||||||
|
user=adventurelog
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stdout_logfile=/dev/stdout
|
stdout_logfile=/dev/stdout
|
||||||
stderr_logfile=/dev/stderr
|
stderr_logfile=/dev/stderr
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# This script will create a backup of the adventurelog_media volume and store it in the current directory as adventurelog-backup.tar.gz
|
# This script will create a backup of the adventurelog_media volume and store it in the current directory as adventurelog-backup.tar.gz
|
||||||
|
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v adventurelog_adventurelog_media:/backup-volume \
|
-v adventurelog_media:/backup-volume \
|
||||||
-v "$(pwd)":/backup \
|
-v "$(pwd)":/backup \
|
||||||
busybox \
|
busybox \
|
||||||
tar -zcvf /backup/adventurelog-backup.tar.gz /backup-volume
|
tar -zcvf /backup/adventurelog-backup.tar.gz /backup-volume
|
|
@ -1,36 +1,46 @@
|
||||||
# Use an official Python image as a base
|
# ---------------------
|
||||||
FROM python:3.11-slim
|
# Stage 1: Data builder
|
||||||
|
# ---------------------
|
||||||
|
FROM docker.io/python:3.11-slim AS builder
|
||||||
|
|
||||||
# Set the working directory
|
ARG GIT_SHA=unknown
|
||||||
|
ARG BUILD_DATE=unknown
|
||||||
|
|
||||||
|
# Set workdir and environment
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
# Install required Python packages
|
# Install required Python packages
|
||||||
RUN pip install --no-cache-dir requests osm2geojson
|
RUN pip install --no-cache-dir requests osm2geojson
|
||||||
|
|
||||||
# Copy the script into the container
|
# Copy and run data generation script
|
||||||
COPY main.py /app/main.py
|
COPY main.py /app/main.py
|
||||||
|
|
||||||
# Run the script to generate the data folder and GeoJSON files (this runs inside the container)
|
|
||||||
RUN python -u /app/main.py
|
RUN python -u /app/main.py
|
||||||
|
|
||||||
# Install Nginx
|
# ------------------------
|
||||||
RUN apt update && apt install -y nginx && rm -rf /var/lib/apt/lists/*
|
# Stage 2: Final Nginx-only
|
||||||
|
# ------------------------
|
||||||
|
FROM docker.io/nginx:alpine
|
||||||
|
|
||||||
# Copy the entire generated data folder to the Nginx serving directory
|
ARG GIT_SHA=unknown
|
||||||
RUN mkdir -p /var/www/html/data && cp -r /app/data/* /var/www/html/data/
|
ARG BUILD_DATE=unknown
|
||||||
|
|
||||||
# Copy Nginx configuration
|
# Optional metadata
|
||||||
|
LABEL org.opencontainers.image.revision="${GIT_SHA}" \
|
||||||
|
org.opencontainers.image.created="${BUILD_DATE}"
|
||||||
|
|
||||||
|
# Create destination directory
|
||||||
|
RUN mkdir -p /var/www/html/data
|
||||||
|
|
||||||
|
# Copy generated data and static files
|
||||||
|
COPY --from=builder /app/data /var/www/html/data
|
||||||
|
COPY index.html /usr/share/nginx/html/index.html
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||||||
|
|
||||||
# Copy the index.html file to the Nginx serving directory
|
# Add entrypoint
|
||||||
COPY index.html /usr/share/nginx/html/index.html
|
|
||||||
|
|
||||||
# Expose port 80 for Nginx
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
# Copy the entrypoint script into the container
|
|
||||||
COPY entrypoint.sh /app/entrypoint.sh
|
COPY entrypoint.sh /app/entrypoint.sh
|
||||||
RUN chmod +x /app/entrypoint.sh
|
RUN chmod +x /app/entrypoint.sh
|
||||||
|
|
||||||
# Set the entrypoint script as the default command
|
EXPOSE 80
|
||||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||||
|
|
|
@ -5,4 +5,4 @@ docker compose pull
|
||||||
echo "Stating containers"
|
echo "Stating containers"
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
echo "All set!"
|
echo "All set!"
|
||||||
docker logs adventurelog-backend --follow
|
docker compose logs --follow
|
|
@ -1,78 +0,0 @@
|
||||||
version: "3.9"
|
|
||||||
|
|
||||||
services:
|
|
||||||
traefik:
|
|
||||||
image: traefik:v2.11
|
|
||||||
command:
|
|
||||||
- "--api.insecure=true" # Enable Traefik dashboard (remove in production)
|
|
||||||
- "--providers.docker=true"
|
|
||||||
- "--entrypoints.web.address=:80"
|
|
||||||
- "--entrypoints.websecure.address=:443"
|
|
||||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
|
||||||
- "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com" # Replace with your email
|
|
||||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
||||||
- "traefik-letsencrypt:/letsencrypt"
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: postgis/postgis:15-3.3
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: database
|
|
||||||
POSTGRES_USER: adventure
|
|
||||||
POSTGRES_PASSWORD: your_postgres_password # Replace with the actual password
|
|
||||||
volumes:
|
|
||||||
- postgres-data:/var/lib/postgresql/data/
|
|
||||||
|
|
||||||
web:
|
|
||||||
image: ghcr.io/seanmorley15/adventurelog-frontend:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
PUBLIC_SERVER_URL: "http://server:8000"
|
|
||||||
BODY_SIZE_LIMIT: "100000"
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.adventurelogweb.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.adventurelogweb.rule=Host(`yourdomain.com`) && !(PathPrefix(`/media`) || PathPrefix(`/admin`) || PathPrefix(`/static`) || PathPrefix(`/accounts`))" # Replace with your domain
|
|
||||||
- "traefik.http.routers.adventurelogweb.tls=true"
|
|
||||||
- "traefik.http.routers.adventurelogweb.tls.certresolver=letsencrypt"
|
|
||||||
depends_on:
|
|
||||||
- server
|
|
||||||
|
|
||||||
server:
|
|
||||||
image: ghcr.io/seanmorley15/adventurelog-backend:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
PGHOST: "db"
|
|
||||||
PGDATABASE: "database"
|
|
||||||
PGUSER: "adventure"
|
|
||||||
PGPASSWORD: your_postgres_password # Replace with the actual password
|
|
||||||
SECRET_KEY: your_secret_key # Replace with the actual secret key
|
|
||||||
DJANGO_ADMIN_USERNAME: "admin"
|
|
||||||
DJANGO_ADMIN_PASSWORD: your_admin_password # Replace with the actual admin password
|
|
||||||
DJANGO_ADMIN_EMAIL: "adventurelog-admin@yourdomain.com" # Replace with your email
|
|
||||||
PUBLIC_URL: "https://yourdomain.com" # Replace with your domain
|
|
||||||
CSRF_TRUSTED_ORIGINS: "https://yourdomain.com" # Replace with your domain
|
|
||||||
DEBUG: "false"
|
|
||||||
FRONTEND_URL: "https://yourdomain.com" # Replace with your domain
|
|
||||||
volumes:
|
|
||||||
- adventurelog-media:/code/media
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.routers.adventurelogserver.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.adventurelogserver.rule=Host(`yourdomain.com`) && (PathPrefix(`/media`) || PathPrefix(`/admin`) || PathPrefix(`/static`) || PathPrefix(`/accounts`))" # Replace with your domain
|
|
||||||
- "traefik.http.routers.adventurelogserver.tls=true"
|
|
||||||
- "traefik.http.routers.adventurelogserver.tls.certresolver=letsencrypt"
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
postgres-data:
|
|
||||||
adventurelog-media:
|
|
||||||
traefik-letsencrypt:
|
|
|
@ -1,36 +1,128 @@
|
||||||
|
name: adventurelog
|
||||||
|
|
||||||
|
# Common DB variables used by both backend and db
|
||||||
|
x-env-common: &env-common
|
||||||
|
POSTGRES_DB: adventurelog # If you change this, it needs to also be changed in the backend
|
||||||
|
POSTGRES_USER: adventurelog # If you change this, it needs to also be changed in the backend
|
||||||
|
POSTGRES_PASSWORD: changeme123 # If you change this, it needs to also be changed in the backend
|
||||||
|
|
||||||
|
# Environment variables for the backend service
|
||||||
|
x-env-backend: &env-backend
|
||||||
|
# Database Configuration
|
||||||
|
PGHOST: db # Supposed to match the host of the postgis database
|
||||||
|
<<: *env-common
|
||||||
|
# AdventureLog base configuration
|
||||||
|
SECRET_KEY: changeme123 # Replace with the actual secret key
|
||||||
|
DJANGO_ADMIN_USERNAME: admin # Replace with the actual admin username
|
||||||
|
DJANGO_ADMIN_PASSWORD: admin # Replace with the actual admin password
|
||||||
|
DJANGO_ADMIN_EMAIL: admin@example.com # Replace with the actual admin email
|
||||||
|
BACKEND_PORT: 8016 # Don't forget to update CSRF_TRUSTED_ORIGINS and PUBLIC_URL in backend, and PUBLIC_SERVER_URL in frontend if you make changes to this.
|
||||||
|
PUBLIC_URL: http://localhost:8016 # Replace with your domain where the backend is accessible publicly, used for the creation of image URLs
|
||||||
|
CSRF_TRUSTED_ORIGINS: http://localhost:8016,http://localhost:8015 # Replace with your domain, if applicable
|
||||||
|
FRONTEND_URL: http://localhost:8015 # Replace with your domain where the frontend is accessible, used for email generation.
|
||||||
|
|
||||||
|
# Optional integrations (commented out by default)
|
||||||
|
# DISABLE_REGISTRATION: False
|
||||||
|
# DISABLE_REGISTRATION_MESSAGE: Registration is disabled for this instance of AdventureLog.
|
||||||
|
# EMAIL_BACKEND: email
|
||||||
|
# EMAIL_HOST: smtp.mail.com
|
||||||
|
# EMAIL_USE_TLS: False
|
||||||
|
# EMAIL_PORT: 587
|
||||||
|
# EMAIL_USE_SSL: True
|
||||||
|
# EMAIL_HOST_USER: user
|
||||||
|
# EMAIL_HOST_PASSWORD: password
|
||||||
|
# DEFAULT_FROM_EMAIL: ${COMPOSE_PROJECT_NAME@example.com
|
||||||
|
# GOOGLE_MAPS_API_KEY: your_google_maps_api_key
|
||||||
|
# PUBLIC_UMAMI_SRC: https://cloud.umami.is/script.js # If you are using the hosted version of Umami
|
||||||
|
# PUBLIC_UMAMI_WEBSITE_ID:
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
DEBUG: false # Use to enable debugging
|
||||||
|
|
||||||
|
# Environment variables for the frontend service
|
||||||
|
x-env-frontend: &env-frontend
|
||||||
|
FRONTEND_PORT: 8015 # Don't forget to update CSRF_TRUSTED_ORIGINS in backend and FRONTEND_URL in backend and ORIGIN in frontend if you make changes to this.
|
||||||
|
PUBLIC_SERVER_URL: http://backend:8000 # PLEASE DON'T CHANGE :) - Should be the service name of the backend with port 8000, even if you change the port in the backend service. Only change if you are using a custom more complex setup.
|
||||||
|
ORIGIN: http://localhost:8015
|
||||||
|
BODY_SIZE_LIMIT: Infinity
|
||||||
|
|
||||||
services:
|
services:
|
||||||
web:
|
|
||||||
#build: ./frontend/
|
|
||||||
image: ghcr.io/seanmorley15/adventurelog-frontend:latest
|
|
||||||
container_name: adventurelog-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
env_file: .env
|
|
||||||
ports:
|
|
||||||
- "${FRONTEND_PORT:-8015}:3000"
|
|
||||||
depends_on:
|
|
||||||
- server
|
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgis/postgis:16-3.5
|
image: docker.io/postgis/postgis:16-3.5
|
||||||
container_name: adventurelog-db
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: .env
|
#env_file: .env # Disabled for security reasons, as all containers have access to these env vars.
|
||||||
|
environment: # Anything defined here (including the env-backend) overrides what's in the env_file.
|
||||||
|
<<: *env-common
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data/
|
- data:/var/lib/postgresql/data/
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
|
||||||
|
interval: 20s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
server:
|
frontend:
|
||||||
#build: ./backend/
|
#build: ./frontend/
|
||||||
image: ghcr.io/seanmorley15/adventurelog-backend:latest
|
image: localhost/adventurelog-frontend:testing
|
||||||
container_name: adventurelog-backend
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: .env
|
# env_file: .env # Disabled for security reasons, as all containers have access to these env vars.
|
||||||
|
environment: # Anything defined here (including the env-backend) overrides what's in the env_file.
|
||||||
|
<<: *env-frontend
|
||||||
ports:
|
ports:
|
||||||
- "${BACKEND_PORT:-8016}:80"
|
- "8015:3000"
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
backend:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "/nodejs/bin/node", "-e", "require('net').connect(3000).on('connect', () => process.exit(0)).on('error', () => process.exit(1))"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
start_period: 10s
|
||||||
|
# labels:
|
||||||
|
# Traefik example: Refer to https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/ for help on deploying Traefik.
|
||||||
|
# - "traefik.enable=true"
|
||||||
|
# - "traefik.http.routers.adventurelogweb.entrypoints=websecure"
|
||||||
|
# - "traefik.http.routers.adventurelogweb.rule=Host(`yourdomain.com`) && !(PathPrefix(`/media`) || PathPrefix(`/admin`) || PathPrefix(`/static`) || PathPrefix(`/accounts`))" # Replace with your domain
|
||||||
|
# - "traefik.http.routers.adventurelogweb.tls=true"
|
||||||
|
# - "traefik.http.routers.adventurelogweb.tls.certresolver=letsencrypt"
|
||||||
|
|
||||||
|
|
||||||
|
backend:
|
||||||
|
#build: ./backend/
|
||||||
|
image: localhost/adventurelog-backend:testing
|
||||||
|
restart: unless-stopped
|
||||||
|
# env_file: .env # Disabled for security reasons, as all containers have access to these env vars.
|
||||||
|
environment: # Anything defined here (including the env-backend) overrides what's in the env_file.
|
||||||
|
<<: *env-backend
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
ports:
|
||||||
|
- "8016:80"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- adventurelog_media:/code/media/
|
- media:/code/media/
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://localhost:80/"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
start_period: 20s
|
||||||
|
retries: 5
|
||||||
|
# labels:
|
||||||
|
# Traefik example: Refer to https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/ for help on deploying Traefik.
|
||||||
|
# - "traefik.enable=true"
|
||||||
|
# - "traefik.http.routers.adventurelogserver.entrypoints=websecure"
|
||||||
|
# - "traefik.http.routers.adventurelogserver.rule=Host(`yourdomain.com`) && (PathPrefix(`/media`) || PathPrefix(`/admin`) || PathPrefix(`/static`) || PathPrefix(`/accounts`))" # Replace with your domain
|
||||||
|
# - "traefik.http.routers.adventurelogserver.tls=true"
|
||||||
|
# - "traefik.http.routers.adventurelogserver.tls.certresolver=letsencrypt"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
data:
|
||||||
adventurelog_media:
|
media:
|
||||||
|
|
|
@ -45,8 +45,8 @@ The `.env` file contains all the configuration settings for your AdventureLog in
|
||||||
| Name | Required | Description | Default Value |
|
| Name | Required | Description | Default Value |
|
||||||
| ------------------- | -------- | --------------------- | ------------- |
|
| ------------------- | -------- | --------------------- | ------------- |
|
||||||
| `PGHOST` | Yes | Internal DB hostname. | `db` |
|
| `PGHOST` | Yes | Internal DB hostname. | `db` |
|
||||||
| `POSTGRES_DB` | Yes | DB name. | `database` |
|
| `POSTGRES_DB` | Yes | DB name. | `adventurelog` |
|
||||||
| `POSTGRES_USER` | Yes | DB user. | `adventure` |
|
| `POSTGRES_USER` | Yes | DB user. | `adventurelog` |
|
||||||
| `POSTGRES_PASSWORD` | Yes | DB password. | `changeme123` |
|
| `POSTGRES_PASSWORD` | Yes | DB password. | `changeme123` |
|
||||||
|
|
||||||
### 🔒 Backend (server)
|
### 🔒 Backend (server)
|
||||||
|
|
6
frontend/.dockerignore
Normal file
6
frontend/.dockerignore
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.env.example
|
||||||
|
.prettierignore
|
||||||
|
.prettierrc
|
||||||
|
.gitignore
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
|
@ -1,7 +0,0 @@
|
||||||
PUBLIC_SERVER_URL=http://127.0.0.1:8000
|
|
||||||
BODY_SIZE_LIMIT=Infinity
|
|
||||||
|
|
||||||
|
|
||||||
# OPTIONAL VARIABLES FOR UMAMI ANALYTICS
|
|
||||||
PUBLIC_UMAMI_SRC=
|
|
||||||
PUBLIC_UMAMI_WEBSITE_ID=
|
|
|
@ -1,49 +1,65 @@
|
||||||
# Use this image as the platform to build the app
|
# ----------------------
|
||||||
FROM node:22-alpine AS external-website
|
# Stage 1: Build the app
|
||||||
|
# ----------------------
|
||||||
|
FROM docker.io/node:22-alpine AS builder
|
||||||
|
|
||||||
|
ARG GIT_SHA=unknown
|
||||||
|
ARG GIT_TAG=latest
|
||||||
|
ARG BUILD_DATE=unknown
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . ./
|
||||||
|
# Install pnpm globally
|
||||||
|
RUN npm install -g pnpm && \
|
||||||
|
pnpm install --frozen-lockfile && \
|
||||||
|
rm -f .env && \
|
||||||
|
pnpm run build && \
|
||||||
|
mv /app/package.json /app/build/package.json;\
|
||||||
|
ls -lah .; \
|
||||||
|
ls -lah ./build
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Stage 2: Install Production Dependencies
|
||||||
|
# ----------------------------
|
||||||
|
FROM docker.io/node:22-alpine AS deps
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /app/build/package.json ./
|
||||||
|
RUN npm install --omit=dev && \
|
||||||
|
addgroup -g 349 adventurelog && \
|
||||||
|
adduser -D -u 349 -G adventurelog adventurelog && \
|
||||||
|
chown -R 349:349 /app
|
||||||
|
|
||||||
|
# ----------------------------
|
||||||
|
# Stage 3: Distroless Runtime
|
||||||
|
# ----------------------------
|
||||||
|
FROM gcr.io/distroless/nodejs20
|
||||||
|
|
||||||
# Metadata labels for the AdventureLog image
|
|
||||||
LABEL maintainer="Sean Morley" \
|
LABEL maintainer="Sean Morley" \
|
||||||
version="v0.10.0" \
|
|
||||||
description="AdventureLog — the ultimate self-hosted travel companion." \
|
|
||||||
org.opencontainers.image.title="AdventureLog" \
|
org.opencontainers.image.title="AdventureLog" \
|
||||||
org.opencontainers.image.description="AdventureLog is a self-hosted travel companion that helps you plan, track, and share your adventures." \
|
org.opencontainers.image.description="AdventureLog is a self-hosted travel companion that helps you plan, track, and share your adventures." \
|
||||||
org.opencontainers.image.version="v0.10.0" \
|
|
||||||
org.opencontainers.image.authors="Sean Morley" \
|
org.opencontainers.image.authors="Sean Morley" \
|
||||||
org.opencontainers.image.url="https://raw.githubusercontent.com/seanmorley15/AdventureLog/refs/heads/main/brand/banner.png" \
|
org.opencontainers.image.url="https://raw.githubusercontent.com/seanmorley15/AdventureLog/refs/heads/main/brand/banner.png" \
|
||||||
org.opencontainers.image.source="https://github.com/seanmorley15/AdventureLog" \
|
org.opencontainers.image.source="https://github.com/seanmorley15/AdventureLog" \
|
||||||
org.opencontainers.image.vendor="Sean Morley" \
|
org.opencontainers.image.vendor="Sean Morley" \
|
||||||
org.opencontainers.image.created="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
|
org.opencontainers.image.version="${GIT_TAG}" \
|
||||||
|
org.opencontainers.image.revision="${GIT_SHA}" \
|
||||||
|
org.opencontainers.image.created="${BUILD_DATE}" \
|
||||||
org.opencontainers.image.licenses="GPL-3.0"
|
org.opencontainers.image.licenses="GPL-3.0"
|
||||||
|
|
||||||
# The WORKDIR instruction sets the working directory for everything that will happen next
|
USER 349:349
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install pnpm globally first
|
COPY --from=builder /etc/passwd /etc/passwd
|
||||||
RUN npm install -g pnpm
|
COPY --from=builder /etc/group /etc/group
|
||||||
|
COPY --from=builder /app/build ./
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
|
||||||
# Copy package files first for better Docker layer caching
|
CMD ["index.js"]
|
||||||
COPY package.json pnpm-lock.yaml* ./
|
|
||||||
|
|
||||||
# Clean install all node modules using pnpm with frozen lockfile
|
|
||||||
RUN pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
# Copy the rest of the application files
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Remove the development .env file if present
|
|
||||||
RUN rm -f .env
|
|
||||||
|
|
||||||
# Build SvelteKit app
|
|
||||||
RUN pnpm run build
|
|
||||||
|
|
||||||
# Make startup script executable
|
|
||||||
RUN chmod +x ./startup.sh
|
|
||||||
|
|
||||||
# Change to non-root user for security
|
|
||||||
USER node:node
|
|
||||||
|
|
||||||
# Expose the port that the app is listening on
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
# Run startup.sh instead of the default command
|
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
|
||||||
CMD ["./startup.sh"]
|
CMD /nodejs/bin/node -e "require('net').connect(3000).on('connect', () => process.exit(0)).on('error', () => process.exit(1))"
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "The origin to be set is: $ORIGIN"
|
|
||||||
# Start the application
|
|
||||||
ORIGIN=$ORIGIN exec node build
|
|
|
@ -1,78 +1,63 @@
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: example-name
|
name: adventurelog
|
||||||
labels:
|
labels:
|
||||||
app: adventure
|
app: adventurelog
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: adventure
|
app: adventurelog
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
name: adventure
|
|
||||||
labels:
|
labels:
|
||||||
app: adventure
|
app: adventurelog
|
||||||
spec:
|
spec:
|
||||||
volumes:
|
volumes:
|
||||||
- name: adventure-journal
|
- name: media
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: adventure-journal-pvc
|
claimName: media-pvc
|
||||||
- name: adventure-journal-db
|
- name: data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: adventure-journal-db-pvc
|
claimName: data-pvc
|
||||||
containers:
|
containers:
|
||||||
- name: adventure-frontend
|
- name: frontend
|
||||||
image: ghcr.io/seanmorley15/adventurelog-frontend:latest
|
image: ghcr.io/seanmorley15/adventurelog-frontend:latest
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 3000
|
- containerPort: 3000
|
||||||
env:
|
env:
|
||||||
|
- name: FRONTEND_PORT
|
||||||
|
value: "8015"
|
||||||
- name: PUBLIC_SERVER_URL
|
- name: PUBLIC_SERVER_URL
|
||||||
value: "http://internally-and-externally.reachable.io:80"
|
value: "http://backend:8000"
|
||||||
- name: ORIGIN
|
- name: ORIGIN
|
||||||
value: "http://url-typed-into-browser.io:80"
|
value: "http://localhost:8015"
|
||||||
- name: BODY_SIZE_LIMIT
|
- name: BODY_SIZE_LIMIT
|
||||||
value: "Infinity"
|
value: "Infinity"
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["/nodejs/bin/node", "-e", "require('net').connect(3000).on('connect', () => process.exit(0)).on('error', () => process.exit(1))"]
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 3
|
||||||
|
|
||||||
- name: adventure-db
|
- name: backend
|
||||||
image: postgis/postgis:15-3.3
|
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
ports:
|
|
||||||
- containerPort: 5432
|
|
||||||
volumeMounts:
|
|
||||||
- name: adventure-journal-db
|
|
||||||
mountPath: /var/lib/postgresql/data
|
|
||||||
env:
|
|
||||||
- name: POSTGRES_DB
|
|
||||||
value: database
|
|
||||||
- name: PGDATA
|
|
||||||
value: /var/lib/postgresql/data/pgdata/subdir
|
|
||||||
- name: POSTGRES_USER
|
|
||||||
value: adventure
|
|
||||||
- name: POSTGRES_PASSWORD
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: adventurelog-secret
|
|
||||||
key: adventure-postgres-password
|
|
||||||
|
|
||||||
- name: adventure-backend
|
|
||||||
image: ghcr.io/seanmorley15/adventurelog-backend:latest
|
image: ghcr.io/seanmorley15/adventurelog-backend:latest
|
||||||
imagePullPolicy: IfNotPresent
|
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
- containerPort: 8000
|
- containerPort: 8000
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: adventure-journal
|
- name: media
|
||||||
mountPath: /code/media
|
mountPath: /code/media
|
||||||
env:
|
env:
|
||||||
- name: PGHOST
|
- name: PGHOST
|
||||||
value: "adventure-db-svc"
|
value: "db"
|
||||||
- name: PGDATABASE
|
- name: POSTGRES_DB
|
||||||
value: "database"
|
value: "adventurelog"
|
||||||
- name: PGUSER
|
- name: POSTGRES_USER
|
||||||
value: "adventure"
|
value: "adventurelog"
|
||||||
- name: PGPASSWORD
|
- name: PGPASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
|
@ -82,58 +67,101 @@ spec:
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: adventurelog-secret
|
name: adventurelog-secret
|
||||||
key: adventure-postgres-password
|
key: secret-key
|
||||||
- name: PUBLIC_URL
|
|
||||||
value: "http://internally-and-externally.reachable.io:80" # Match the outward port, used for the creation of image urls
|
|
||||||
- name: FRONTEND_URL
|
|
||||||
value: "http://url-typed-into-browser.io:80"
|
|
||||||
- name: CSRF_TRUSTED_ORIGINS
|
|
||||||
value: "http://url-typed-into-browser.io:80, http://internally-and-externally.reachable.io:80"
|
|
||||||
- name: DJANGO_ADMIN_USERNAME
|
- name: DJANGO_ADMIN_USERNAME
|
||||||
value: "admin"
|
value: "admin"
|
||||||
- name: DJANGO_ADMIN_PASSWORD
|
- name: DJANGO_ADMIN_PASSWORD
|
||||||
value: "admin"
|
value: "admin"
|
||||||
- name: DJANGO_ADMIN_EMAIL
|
- name: DJANGO_ADMIN_EMAIL
|
||||||
value: "admin@example.com"
|
value: "admin@example.com"
|
||||||
|
- name: BACKEND_PORT
|
||||||
|
value: "8016"
|
||||||
|
- name: PUBLIC_URL
|
||||||
|
value: "http://localhost:8016"
|
||||||
|
- name: FRONTEND_URL
|
||||||
|
value: "http://localhost:8015"
|
||||||
|
- name: CSRF_TRUSTED_ORIGINS
|
||||||
|
value: "http://localhost:8016,http://localhost:8015"
|
||||||
- name: DEBUG
|
- name: DEBUG
|
||||||
value: "True"
|
value: "false"
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 10
|
||||||
|
failureThreshold: 5
|
||||||
|
|
||||||
|
- name: db
|
||||||
|
image: postgis/postgis:16-3.5
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: "adventurelog"
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: "adventurelog"
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: adventurelog-secret
|
||||||
|
key: adventure-postgres-password
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["pg_isready", "-U", "adventurelog"]
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 20
|
||||||
|
timeoutSeconds: 10
|
||||||
|
failureThreshold: 5
|
||||||
restartPolicy: Always
|
restartPolicy: Always
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: adventure-db-svc
|
name: backend
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: adventure
|
app: adventurelog
|
||||||
ports:
|
ports:
|
||||||
- name: db
|
- name: http
|
||||||
protocol: TCP
|
port: 80
|
||||||
port: 5432
|
targetPort: 80
|
||||||
targetPort: 5432
|
- name: backend
|
||||||
|
port: 8000
|
||||||
|
targetPort: 8000
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: server
|
name: frontend
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: adventure
|
app: adventurelog
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
protocol: TCP
|
port: 3000
|
||||||
port: 80
|
targetPort: 3000
|
||||||
targetPort: 80
|
---
|
||||||
- name: base
|
apiVersion: v1
|
||||||
protocol: TCP
|
kind: Service
|
||||||
port: 8000
|
metadata:
|
||||||
targetPort: 8000
|
name: db
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: adventurelog
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: 5432
|
||||||
|
targetPort: 5432
|
||||||
---
|
---
|
||||||
# If you aren't automatically provisioning PVCs (i.e. with Longhorn, you'll need to also create the PV's)
|
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: adventure-journal-pvc
|
name: media-pvc
|
||||||
spec:
|
spec:
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
|
@ -144,10 +172,19 @@ spec:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: adventure-journal-db-pvc
|
name: data-pvc
|
||||||
spec:
|
spec:
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 10Gi
|
storage: 10Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: adventurelog-secret
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
adventure-postgres-password: changeme123
|
||||||
|
secret-key: changeme123
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue