Add actions
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
# Production configuration for deploy/compose.yml + compose.prod.yml.
|
||||
# Copy to deploy/.env.prod, then:
|
||||
#
|
||||
# 1. replace every `example.com` with your domain,
|
||||
# 1. replace every `*.example.com` with your actual domains (each service
|
||||
# below has its own, independent domain — they don't need to share a
|
||||
# root, e.g. for DNS providers that don't allow multi-level
|
||||
# subdomains),
|
||||
# 2. replace every CHANGE_ME with a strong random value
|
||||
# (`openssl rand -hex 24`),
|
||||
# 3. point these DNS records at the server, all proxied/TLS-terminated the
|
||||
# same way: example.com, www, api, auth, stream, s3.
|
||||
# 3. point each *_DOMAIN below at the server, proxied/TLS-terminated the
|
||||
# same way.
|
||||
#
|
||||
# Requires ../../../Infrastructure running first, on the same Docker host,
|
||||
# with its own `infra-net` network already created. See
|
||||
@@ -14,12 +17,18 @@
|
||||
|
||||
DOTNET_ENVIRONMENT=Production
|
||||
|
||||
# --- Domain ------------------------------------------------------------------
|
||||
# ROOT_DOMAIN drives the nginx vhosts; the URLs below must agree with it.
|
||||
ROOT_DOMAIN=example.com
|
||||
PUBLIC_WEB_URL=https://example.com
|
||||
PUBLIC_API_URL=https://api.example.com
|
||||
PUBLIC_STREAM_URL=https://stream.example.com
|
||||
# --- Domains -------------------------------------------------------------
|
||||
# Each *_DOMAIN drives its own nginx vhost (deploy/nginx/templates); the
|
||||
# PUBLIC_*_URL/S3_PUBLIC_URL below must agree with it (https://<domain>).
|
||||
WEB_DOMAIN=musify.example.com
|
||||
API_DOMAIN=musifyapi.example.com
|
||||
STREAM_DOMAIN=musifystream.example.com
|
||||
AUTH_DOMAIN=auth.example.com
|
||||
S3_DOMAIN=s3.example.com
|
||||
|
||||
PUBLIC_WEB_URL=https://musify.example.com
|
||||
PUBLIC_API_URL=https://musifyapi.example.com
|
||||
PUBLIC_STREAM_URL=https://musifystream.example.com
|
||||
PUBLIC_AUTH_URL=https://auth.example.com
|
||||
S3_PUBLIC_URL=https://s3.example.com
|
||||
|
||||
|
||||
+63
-4
@@ -125,14 +125,19 @@ cp deploy/.env.prod.example deploy/.env.prod
|
||||
|
||||
Fill it in:
|
||||
|
||||
1. Replace every `example.com` with your domain and every `CHANGE_ME` with a
|
||||
random value (`openssl rand -hex 24`). `chmod 600 deploy/.env.prod`.
|
||||
1. Replace every `*.example.com` with your actual domains and every
|
||||
`CHANGE_ME` with a random value (`openssl rand -hex 24`). Each of
|
||||
`WEB_DOMAIN`/`API_DOMAIN`/`STREAM_DOMAIN`/`AUTH_DOMAIN`/`S3_DOMAIN` is
|
||||
independent — they don't need to share a root domain (e.g.
|
||||
`musify.example.com` + `musifyapi.example.com`, or sibling subdomains of
|
||||
a domain whose DNS provider doesn't allow multi-level subdomains).
|
||||
`chmod 600 deploy/.env.prod`.
|
||||
2. Drop **`deploy/nginx/certs/origin.pem` and `origin.key`**, the origin
|
||||
certificate nginx serves. The stack assumes Cloudflare in *Full (strict)*
|
||||
mode in front of it, so a Cloudflare Origin Certificate is enough; any
|
||||
certificate valid for the five hostnames works.
|
||||
3. Point `example.com`, `www`, `api`, `auth`, `stream` and `s3` at the server,
|
||||
proxied and TLS-terminated the same way.
|
||||
3. Point the five `*_DOMAIN` values at the server, proxied and
|
||||
TLS-terminated the same way.
|
||||
|
||||
Then:
|
||||
|
||||
@@ -150,6 +155,60 @@ an update once the stack already exists).
|
||||
Only nginx publishes ports (80/443). Every other Musify service, and all of
|
||||
Infrastructure's, is reachable only on the internal `infra-net` network.
|
||||
|
||||
### Continuous deployment
|
||||
|
||||
`.gitea/workflows/ci-cd.yml` runs the backend and web-player checks on every
|
||||
push/PR, and on a successful push to `master` deploys automatically. The
|
||||
deploy job runs on `gitea-runner`, the existing self-hosted Gitea Actions
|
||||
runner on the production host itself (`gitea.ikerdemo.cat`, in
|
||||
`~/gitea/docker-compose.yml`), which also carries a `production:host`
|
||||
label registered directly in `~/gitea/runner-data/.runner` (act_runner
|
||||
reads `labels` from that file on every start, not from
|
||||
`GITEA_RUNNER_LABELS`, once a runner is already registered). Running in
|
||||
native mode means the label's steps execute inside the runner container
|
||||
itself rather than spinning up a fresh one — that container has
|
||||
`/var/run/docker.sock` mounted, so `docker`/`docker compose` there still
|
||||
control the host's real Docker daemon (sibling containers, "Docker outside
|
||||
of Docker"). Its compose service also bind-mounts `/home/ubuntu/deploys`
|
||||
into itself at the *same* path, which matters because compose's own
|
||||
relative bind mounts (`./keys`, `./nginx/...`) are resolved by the host
|
||||
daemon against that literal path — mounting it anywhere else would silently
|
||||
bind the wrong (empty) directory.
|
||||
|
||||
`DEPLOY_PATH` (hardcoded in the workflow as `/home/ubuntu/deploys/musify`)
|
||||
is a persistent clone on that host, reused instead of a fresh checkout each
|
||||
run since `deploy/.env.prod` is untracked and only lives there.
|
||||
`/home/ubuntu/deploys/SharedServices` is the sibling clone of the
|
||||
`Infrastructure`/`SharedServices` repo, already running (`infra-net`
|
||||
created); its `.env.prod` shares the Postgres/RabbitMQ/S3 credentials with
|
||||
Musify's own `deploy/.env.prod` by design (see that repo's README).
|
||||
|
||||
**Pending DNS on the registered domains:** `deploy/.env.prod`'s five
|
||||
`*_DOMAIN` values are set (`musify.ikerdemo.cat`, `musifyapi.ikerdemo.cat`,
|
||||
`musifystream.ikerdemo.cat`, `auth.ikerdemo.cat`, `s3.ikerdemo.cat` —
|
||||
siblings, not `api.musify.ikerdemo.cat`, because the DNS provider here
|
||||
doesn't allow multi-level subdomains), but no DNS record points any of them
|
||||
at the server yet, so:
|
||||
|
||||
- `zitadel-init` and `seaweedfs-init` (they verify themselves through the
|
||||
public `auth.`/`s3.` URLs) fail every deploy until those two resolve and
|
||||
are actually reachable — the workflow tolerates this on purpose, see its
|
||||
comments. Until then, `api`/`worker` build and start but can't do
|
||||
anything OIDC- or storage-dependent (`AUTH_CLIENT_ID`/`WEB_CLIENT_ID`/
|
||||
`WEB_CLIENT_SECRET` in `.env.prod` stay blank); `gateway`/`web-player`
|
||||
are unaffected.
|
||||
- The `nginx` service from `compose.prod.yml` is intentionally **not**
|
||||
brought up by the deploy job: it would try to publish host ports 80/443,
|
||||
which `gitea-nginx` already owns for `gitea.ikerdemo.cat` (certbot). Once
|
||||
the five DNS records above exist, merge Musify's vhosts
|
||||
(`deploy/nginx/templates`) into `~/gitea/nginx/conf.d` instead — same
|
||||
nginx, additional `server_name` blocks proxying to Musify's containers
|
||||
over `infra-net` — rather than running a second nginx that would conflict
|
||||
on those ports. That also needs a certificate valid for the 5 hostnames
|
||||
(the existing setup uses certbot/Let's Encrypt, not the Cloudflare Origin
|
||||
cert `compose.prod.yml`'s nginx assumes — reconcile whichever way when
|
||||
that's set up).
|
||||
|
||||
---
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -33,7 +33,11 @@ services:
|
||||
environment:
|
||||
# The entrypoint renders /etc/nginx/templates/*.template with envsubst.
|
||||
# The filter keeps it from eating nginx's own $host / $remote_addr.
|
||||
MUSIFY_ROOT_DOMAIN: ${ROOT_DOMAIN}
|
||||
MUSIFY_WEB_DOMAIN: ${WEB_DOMAIN}
|
||||
MUSIFY_API_DOMAIN: ${API_DOMAIN}
|
||||
MUSIFY_STREAM_DOMAIN: ${STREAM_DOMAIN}
|
||||
MUSIFY_AUTH_DOMAIN: ${AUTH_DOMAIN}
|
||||
MUSIFY_S3_DOMAIN: ${S3_DOMAIN}
|
||||
MUSIFY_MAX_UPLOAD_SIZE: ${MAX_UPLOAD_SIZE:-1024m}
|
||||
NGINX_ENVSUBST_FILTER: ^MUSIFY_
|
||||
ports:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Musify edge. The nginx entrypoint renders this with envsubst into
|
||||
# /etc/nginx/conf.d/default.conf (replacing the image's stock file) using the
|
||||
# MUSIFY_* variables set in compose.prod.yml.
|
||||
# MUSIFY_* variables set in compose.prod.yml. Each vhost has its own,
|
||||
# independent domain (see deploy/.env.prod.example) — they don't need to
|
||||
# share a root domain.
|
||||
#
|
||||
# Cloudflare (Full strict) terminates the public edge; this box only needs to
|
||||
# serve the Cloudflare Origin Certificate in nginx/certs/. Each vhost proxies to
|
||||
@@ -17,9 +19,8 @@ map $http_upgrade $connection_upgrade {
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${MUSIFY_ROOT_DOMAIN} www.${MUSIFY_ROOT_DOMAIN}
|
||||
api.${MUSIFY_ROOT_DOMAIN} auth.${MUSIFY_ROOT_DOMAIN}
|
||||
stream.${MUSIFY_ROOT_DOMAIN} s3.${MUSIFY_ROOT_DOMAIN};
|
||||
server_name ${MUSIFY_WEB_DOMAIN} ${MUSIFY_API_DOMAIN}
|
||||
${MUSIFY_AUTH_DOMAIN} ${MUSIFY_STREAM_DOMAIN} ${MUSIFY_S3_DOMAIN};
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
@@ -28,7 +29,7 @@ server {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name ${MUSIFY_ROOT_DOMAIN};
|
||||
server_name ${MUSIFY_WEB_DOMAIN};
|
||||
client_max_body_size ${MUSIFY_MAX_UPLOAD_SIZE};
|
||||
|
||||
ssl_certificate /etc/nginx/certs/origin.pem;
|
||||
@@ -44,18 +45,7 @@ server {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name www.${MUSIFY_ROOT_DOMAIN};
|
||||
|
||||
ssl_certificate /etc/nginx/certs/origin.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/origin.key;
|
||||
|
||||
return 301 https://${MUSIFY_ROOT_DOMAIN}$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name api.${MUSIFY_ROOT_DOMAIN};
|
||||
server_name ${MUSIFY_API_DOMAIN};
|
||||
|
||||
ssl_certificate /etc/nginx/certs/origin.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/origin.key;
|
||||
@@ -71,7 +61,7 @@ server {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name stream.${MUSIFY_ROOT_DOMAIN};
|
||||
server_name ${MUSIFY_STREAM_DOMAIN};
|
||||
|
||||
ssl_certificate /etc/nginx/certs/origin.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/origin.key;
|
||||
@@ -87,7 +77,7 @@ server {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name auth.${MUSIFY_ROOT_DOMAIN};
|
||||
server_name ${MUSIFY_AUTH_DOMAIN};
|
||||
|
||||
ssl_certificate /etc/nginx/certs/origin.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/origin.key;
|
||||
@@ -104,7 +94,7 @@ server {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name s3.${MUSIFY_ROOT_DOMAIN};
|
||||
server_name ${MUSIFY_S3_DOMAIN};
|
||||
client_max_body_size ${MUSIFY_MAX_UPLOAD_SIZE};
|
||||
|
||||
ssl_certificate /etc/nginx/certs/origin.pem;
|
||||
|
||||
Reference in New Issue
Block a user