chg: pkg: implement CD script to Gitea and add docs to the process #4
Some checks failed
Deploy to Production / deploy (push) Has been cancelled
Some checks failed
Deploy to Production / deploy (push) Has been cancelled
This commit is contained in:
@@ -10,10 +10,9 @@ APP_SECRET=changethis
|
|||||||
###< symfony/framework-bundle ###
|
###< symfony/framework-bundle ###
|
||||||
|
|
||||||
###> doctrine/doctrine-bundle ###
|
###> doctrine/doctrine-bundle ###
|
||||||
# Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
# Docker PostgreSQL is exposed on port 15432 — use that for bare-metal dev.
|
||||||
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
|
# Replace POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB with the values from your .env.
|
||||||
# Configure your db driver and server_version in config/packages/doctrine.yaml
|
DATABASE_URL=postgresql://POSTGRES_USER:POSTGRES_PASSWORD@127.0.0.1:15432/POSTGRES_DB?serverVersion=18&charset=utf8
|
||||||
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
|
|
||||||
###< doctrine/doctrine-bundle ###
|
###< doctrine/doctrine-bundle ###
|
||||||
|
|
||||||
###> google/recaptcha ###
|
###> google/recaptcha ###
|
||||||
|
|||||||
19
.gitea/workflows/deploy.yml
Normal file
19
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
name: Deploy to Production
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: self-hosted
|
||||||
|
steps:
|
||||||
|
- name: Deploy
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
cd "${{ vars.PROD_APP_DIR }}"
|
||||||
|
git fetch --tags
|
||||||
|
git checkout "${{ gitea.ref_name }}"
|
||||||
|
printf '%s' '${{ secrets.PROD_ENV_FILE }}' > .env
|
||||||
|
docker compose up -d --build
|
||||||
@@ -9,7 +9,7 @@ COPY vite.config.js ./
|
|||||||
COPY assets/ assets/
|
COPY assets/ assets/
|
||||||
COPY public/ public/
|
COPY public/ public/
|
||||||
|
|
||||||
RUN bun run build && cp -r node_modules/@fortawesome/fontawesome-free/webfonts public/build/webfonts
|
RUN bun run build
|
||||||
|
|
||||||
FROM dunglas/frankenphp:latest
|
FROM dunglas/frankenphp:latest
|
||||||
|
|
||||||
|
|||||||
106
README.md
106
README.md
@@ -154,6 +154,7 @@ services:
|
|||||||
mail:
|
mail:
|
||||||
image: mailhog/mailhog:latest
|
image: mailhog/mailhog:latest
|
||||||
ports:
|
ports:
|
||||||
|
- "1025:1025"
|
||||||
- "8025:8025"
|
- "8025:8025"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -174,6 +175,111 @@ Open the web UI at **http://localhost:8025** to inspect them.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Deploying to production
|
||||||
|
|
||||||
|
Releases are automated via Gitea Actions. Pushing a tag that starts with `v` (e.g. `v2026.01`) triggers the workflow at `.gitea/workflows/deploy.yml`.
|
||||||
|
The job runs on a **self-hosted runner** installed on the production server — the server only needs an outbound connection to Gitea, no open SSH port required.
|
||||||
|
The `app` image is rebuilt with the new code; the database and storage containers are untouched so all data is preserved.
|
||||||
|
|
||||||
|
### Gitea repository variables and secrets
|
||||||
|
|
||||||
|
**Variable** (plaintext, editable — **Repository → Settings → Variables**):
|
||||||
|
|
||||||
|
| Variable | Value |
|
||||||
|
|---|---|
|
||||||
|
| `PROD_APP_DIR` | Absolute path on the server (e.g. `/var/www/mineseeker`) |
|
||||||
|
|
||||||
|
**Secret** (encrypted, write-only — **Repository → Settings → Secrets**):
|
||||||
|
|
||||||
|
| Secret | Value |
|
||||||
|
|---|---|
|
||||||
|
| `PROD_ENV_FILE` | Full content of the production `.env` file (see below) |
|
||||||
|
|
||||||
|
The workflow writes `PROD_ENV_FILE` to `.env` on every deploy, so you never need to manage the file on the server manually. To update a credential, overwrite the secret in Gitea and push a new tag.
|
||||||
|
|
||||||
|
#### `PROD_ENV_FILE` contents
|
||||||
|
|
||||||
|
Paste the filled-in `.env` file as the secret value:
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
APP_ENV=prod
|
||||||
|
APP_SECRET="<openssl rand -hex 32>"
|
||||||
|
|
||||||
|
DATABASE_URL=postgresql://POSTGRES_USER:POSTGRES_PASSWORD@db:5432/POSTGRES_DB?serverVersion=18&charset=utf8
|
||||||
|
|
||||||
|
POSTGRES_USER=mineseeker
|
||||||
|
POSTGRES_PASSWORD="<strong password>"
|
||||||
|
POSTGRES_DB=mineseeker
|
||||||
|
POSTGRES_VERSION=18
|
||||||
|
|
||||||
|
MINIO_ROOT_USER=mineseeker
|
||||||
|
MINIO_ROOT_PASSWORD="<strong password>"
|
||||||
|
MINIO_ENDPOINT=http://minio:9000
|
||||||
|
MINIO_PUBLIC_URL=https://minio.mineseeker.hu
|
||||||
|
|
||||||
|
MAILER_DSN=smtp://mail:25?verify_peer=0
|
||||||
|
MAIL_DOMAIN=mineseeker.hu
|
||||||
|
|
||||||
|
RECAPTCHA_SITE_KEY="<your reCAPTCHA v3 site key>"
|
||||||
|
RECAPTCHA_SECRET_KEY="<your reCAPTCHA v3 secret key>"
|
||||||
|
|
||||||
|
MERCURE_URL=https://mineseeker.hu/.well-known/mercure
|
||||||
|
MERCURE_PUBLIC_URL=https://mineseeker.hu/.well-known/mercure
|
||||||
|
MERCURE_JWT_SECRET="<generated by make mercure-jwt>"
|
||||||
|
MERCURE_JWT_TOKEN="<generated by make mercure-jwt>"
|
||||||
|
MERCURE_SUBSCRIBER_JWT="<generated by make mercure-jwt>"
|
||||||
|
|
||||||
|
APP_PUBLIC_HOSTNAME=mineseeker.hu
|
||||||
|
WEBAUTHN_RP_ID=mineseeker.hu
|
||||||
|
WEBAUTHN_ORIGIN=https://mineseeker.hu
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production server: one-time setup
|
||||||
|
|
||||||
|
The server needs Docker, Git, and a self-hosted `act_runner` registered against the Gitea repository. Bun and Composer run inside the multi-stage Dockerfile, so they are not needed on the server.
|
||||||
|
|
||||||
|
#### 1. Clone the repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://gitea.mineseeker.hu/youruser/mineseeker.git /var/www/mineseeker
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Generate Mercure JWT tokens (run once locally)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer install # only needed for this step
|
||||||
|
make mercure-jwt
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the three printed values into the `PROD_ENV_FILE` secret.
|
||||||
|
|
||||||
|
#### 5. First deploy
|
||||||
|
|
||||||
|
Trigger it by pushing the first tag:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git tag v2026.01
|
||||||
|
git push origin v2026.01
|
||||||
|
```
|
||||||
|
|
||||||
|
This writes `.env`, builds the Docker image, starts all services, runs migrations, and initialises the MinIO buckets automatically via `minio_init`.
|
||||||
|
|
||||||
|
#### 6. Verify
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps # all services should be healthy/running
|
||||||
|
docker compose logs app # look for "Starting FrankenPHP"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Releasing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git tag v2026.01
|
||||||
|
git push origin v2026.01
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
LGPL-3.0 — see [LICENSE](LICENSE) for details.
|
LGPL-3.0 — see [LICENSE](LICENSE) for details.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
container_name: '${APP_NAME}-app'
|
||||||
ports:
|
ports:
|
||||||
- "10080:80"
|
- "10080:80"
|
||||||
environment:
|
environment:
|
||||||
@@ -42,6 +43,7 @@ services:
|
|||||||
minio:
|
minio:
|
||||||
image: minio/minio:RELEASE.2025-09-07T16-13-09Z-cpuv1
|
image: minio/minio:RELEASE.2025-09-07T16-13-09Z-cpuv1
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
container_name: '${APP_NAME}-minio'
|
||||||
command: server /data --console-address ":9001"
|
command: server /data --console-address ":9001"
|
||||||
ports:
|
ports:
|
||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
@@ -60,6 +62,7 @@ services:
|
|||||||
minio_init:
|
minio_init:
|
||||||
image: minio/minio:RELEASE.2025-09-07T16-13-09Z-cpuv1
|
image: minio/minio:RELEASE.2025-09-07T16-13-09Z-cpuv1
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
container_name: '${APP_NAME}-minio-init'
|
||||||
depends_on:
|
depends_on:
|
||||||
minio:
|
minio:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@@ -72,6 +75,7 @@ services:
|
|||||||
mail:
|
mail:
|
||||||
image: boky/postfix:latest
|
image: boky/postfix:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
container_name: '${APP_NAME}-mail'
|
||||||
environment:
|
environment:
|
||||||
ALLOWED_SENDER_DOMAINS: ${MAIL_DOMAIN:-localhost}
|
ALLOWED_SENDER_DOMAINS: ${MAIL_DOMAIN:-localhost}
|
||||||
RELAYHOST: ${MAIL_RELAYHOST:-}
|
RELAYHOST: ${MAIL_RELAYHOST:-}
|
||||||
@@ -82,6 +86,7 @@ services:
|
|||||||
db:
|
db:
|
||||||
image: postgres:${POSTGRES_VERSION:-latest}-alpine
|
image: postgres:${POSTGRES_VERSION:-latest}-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
container_name: '${APP_NAME}-db'
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_USER}
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"watch": "vite build --watch",
|
"watch": "vite build --watch",
|
||||||
"build": "vite build",
|
"build": "vite build && cp -r node_modules/@fortawesome/fontawesome-free/webfonts public/build/webfonts",
|
||||||
"lint": "eslint assets/js/"
|
"lint": "eslint assets/js/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user