Fix CORS handling and real IP logging
This commit is contained in:
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,19 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.4.5 (2025-10-30)
|
||||||
|
|
||||||
|
* Serve photos UI on the primary hostname and mount other apps on `accounts/auth/cast/albums/family.<root-domain>`
|
||||||
|
* Enable multiDomain in the manifest so aliases can be set in Cloudron UI
|
||||||
|
* Simplified documentation for S3 setup and alias domains
|
||||||
|
* Fix CORS responses for auth subdomains and forward real client IPs from Cloudron proxy
|
||||||
|
|
||||||
|
## 0.4.4 (2025-10-30)
|
||||||
|
|
||||||
|
* Restore Cloudflare R2 path-style URLs and simplify to a single hot-storage data center
|
||||||
|
* Serve the frontend apps on dedicated subdomains (photos/accounts/auth/cast/albums/family)
|
||||||
|
* Startup script now regenerates Caddy and Museum configs for the new host layout
|
||||||
|
* Added post-install checklist entries and updated docs for required DNS records
|
||||||
|
|
||||||
## 0.4.3 (2025-10-29)
|
## 0.4.3 (2025-10-29)
|
||||||
|
|
||||||
* Always regenerate Museum configuration on startup to pick up S3 credential changes
|
* Always regenerate Museum configuration on startup to pick up S3 credential changes
|
||||||
|
|||||||
240
start.sh
240
start.sh
@@ -50,14 +50,61 @@ fi
|
|||||||
touch "$STARTUP_FLAG"
|
touch "$STARTUP_FLAG"
|
||||||
trap 'rm -f "$STARTUP_FLAG"' EXIT
|
trap 'rm -f "$STARTUP_FLAG"' EXIT
|
||||||
|
|
||||||
BASE_URL="${CLOUDRON_APP_ORIGIN:-https://$CLOUDRON_APP_FQDN}"
|
APP_FQDN="${CLOUDRON_APP_DOMAIN:-${CLOUDRON_APP_FQDN:-localhost}}"
|
||||||
|
BASE_URL="${CLOUDRON_APP_ORIGIN:-https://$APP_FQDN}"
|
||||||
BASE_URL="${BASE_URL%/}"
|
BASE_URL="${BASE_URL%/}"
|
||||||
RP_ID="${CLOUDRON_APP_FQDN:-${CLOUDRON_APP_DOMAIN:-localhost}}"
|
|
||||||
API_ORIGIN="${BASE_URL}/api"
|
ROOT_DOMAIN="$APP_FQDN"
|
||||||
|
if [ "$APP_FQDN" != "localhost" ] && expr "$APP_FQDN" : '.*\..*' >/dev/null; then
|
||||||
|
ROOT_DOMAIN="${APP_FQDN#*.}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PHOTOS_HOST="$APP_FQDN"
|
||||||
|
ACCOUNTS_HOST="$APP_FQDN"
|
||||||
|
AUTH_HOST="$APP_FQDN"
|
||||||
|
CAST_HOST="$APP_FQDN"
|
||||||
|
ALBUMS_HOST="$APP_FQDN"
|
||||||
|
FAMILY_HOST="$APP_FQDN"
|
||||||
|
|
||||||
|
USE_SUBDOMAIN_ROUTING=false
|
||||||
|
if [ "$APP_FQDN" != "localhost" ] && [ "$ROOT_DOMAIN" != "$APP_FQDN" ]; then
|
||||||
|
ACCOUNTS_HOST="accounts.${ROOT_DOMAIN}"
|
||||||
|
AUTH_HOST="auth.${ROOT_DOMAIN}"
|
||||||
|
CAST_HOST="cast.${ROOT_DOMAIN}"
|
||||||
|
ALBUMS_HOST="albums.${ROOT_DOMAIN}"
|
||||||
|
FAMILY_HOST="family.${ROOT_DOMAIN}"
|
||||||
|
USE_SUBDOMAIN_ROUTING=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
PHOTOS_URL="https://${PHOTOS_HOST}"
|
||||||
|
if [ "$USE_SUBDOMAIN_ROUTING" = true ]; then
|
||||||
|
ACCOUNTS_URL="https://${ACCOUNTS_HOST}"
|
||||||
|
AUTH_URL="https://${AUTH_HOST}"
|
||||||
|
CAST_URL="https://${CAST_HOST}"
|
||||||
|
FAMILY_URL="https://${FAMILY_HOST}"
|
||||||
|
ALBUMS_URL="https://${ALBUMS_HOST}"
|
||||||
|
else
|
||||||
|
ACCOUNTS_URL="${BASE_URL}/accounts"
|
||||||
|
AUTH_URL="${BASE_URL}/auth"
|
||||||
|
CAST_URL="${BASE_URL}/cast"
|
||||||
|
FAMILY_URL="${BASE_URL}/family"
|
||||||
|
ALBUMS_URL="${BASE_URL}/albums"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$APP_FQDN" != "localhost" ]; then
|
||||||
|
API_BASE="https://${APP_FQDN}"
|
||||||
|
else
|
||||||
|
API_BASE="$BASE_URL"
|
||||||
|
fi
|
||||||
|
API_ORIGIN="${API_BASE}/api"
|
||||||
|
RP_ID="$PHOTOS_HOST"
|
||||||
|
|
||||||
log INFO "Application base URL: $BASE_URL"
|
log INFO "Application base URL: $BASE_URL"
|
||||||
log INFO "Relying party ID: $RP_ID"
|
log INFO "Relying party ID: $RP_ID"
|
||||||
log INFO "API origin: $API_ORIGIN"
|
log INFO "API origin: $API_ORIGIN"
|
||||||
|
if [ "$USE_SUBDOMAIN_ROUTING" = true ]; then
|
||||||
|
log INFO "Serving frontend hosts: photos=${PHOTOS_HOST}, accounts=${ACCOUNTS_HOST}, auth=${AUTH_HOST}, cast=${CAST_HOST}"
|
||||||
|
fi
|
||||||
|
|
||||||
S3_CONFIG_FILE="$CONFIG_DIR/s3.env"
|
S3_CONFIG_FILE="$CONFIG_DIR/s3.env"
|
||||||
if [ ! -f "$S3_CONFIG_FILE" ]; then
|
if [ ! -f "$S3_CONFIG_FILE" ]; then
|
||||||
@@ -299,13 +346,13 @@ http:
|
|||||||
use-tls: false
|
use-tls: false
|
||||||
|
|
||||||
apps:
|
apps:
|
||||||
public-albums: "$BASE_URL/albums"
|
public-albums: "$ALBUMS_URL"
|
||||||
public-locker: "$BASE_URL/photos"
|
public-locker: "$PHOTOS_URL"
|
||||||
accounts: "$BASE_URL/accounts"
|
accounts: "$ACCOUNTS_URL"
|
||||||
cast: "$BASE_URL/cast"
|
cast: "$CAST_URL"
|
||||||
family: "$BASE_URL/family"
|
family: "$FAMILY_URL"
|
||||||
custom-domain:
|
custom-domain:
|
||||||
cname: "${CLOUDRON_APP_DOMAIN:-localhost}"
|
cname: "${APP_FQDN}"
|
||||||
|
|
||||||
db:
|
db:
|
||||||
host: ${CLOUDRON_POSTGRESQL_HOST}
|
host: ${CLOUDRON_POSTGRESQL_HOST}
|
||||||
@@ -356,7 +403,7 @@ internal:
|
|||||||
webauthn:
|
webauthn:
|
||||||
rpid: "$RP_ID"
|
rpid: "$RP_ID"
|
||||||
rporigins:
|
rporigins:
|
||||||
- "$BASE_URL"
|
- "$PHOTOS_URL"
|
||||||
|
|
||||||
key:
|
key:
|
||||||
encryption: $MASTER_KEY
|
encryption: $MASTER_KEY
|
||||||
@@ -377,7 +424,7 @@ oidc:
|
|||||||
issuer: "${CLOUDRON_OIDC_IDENTIFIER}"
|
issuer: "${CLOUDRON_OIDC_IDENTIFIER}"
|
||||||
client_id: "${CLOUDRON_OIDC_CLIENT_ID}"
|
client_id: "${CLOUDRON_OIDC_CLIENT_ID}"
|
||||||
client_secret: "${CLOUDRON_OIDC_CLIENT_SECRET}"
|
client_secret: "${CLOUDRON_OIDC_CLIENT_SECRET}"
|
||||||
redirect_url: "$BASE_URL/api/v1/session/callback"
|
redirect_url: "$API_BASE/api/v1/session/callback"
|
||||||
EOF_CFG
|
EOF_CFG
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -453,14 +500,14 @@ if [ -d "$WEB_RUNTIME_DIR" ]; then
|
|||||||
FRONTEND_REPLACEMENTS=(
|
FRONTEND_REPLACEMENTS=(
|
||||||
"ENTE_API_ORIGIN_PLACEHOLDER|$API_ORIGIN"
|
"ENTE_API_ORIGIN_PLACEHOLDER|$API_ORIGIN"
|
||||||
"https://api.ente.io|$API_ORIGIN"
|
"https://api.ente.io|$API_ORIGIN"
|
||||||
"https://accounts.ente.io|$BASE_URL/accounts"
|
"https://accounts.ente.io|$ACCOUNTS_URL"
|
||||||
"https://auth.ente.io|$BASE_URL/auth"
|
"https://auth.ente.io|$AUTH_URL"
|
||||||
"https://cast.ente.io|$BASE_URL/cast"
|
"https://cast.ente.io|$CAST_URL"
|
||||||
"https://photos.ente.io|$BASE_URL/photos"
|
"https://photos.ente.io|$PHOTOS_URL"
|
||||||
"https://web.ente.io|$BASE_URL/photos"
|
"https://web.ente.io|$PHOTOS_URL"
|
||||||
"https://albums.ente.io|$BASE_URL/albums"
|
"https://albums.ente.io|$ALBUMS_URL"
|
||||||
"https://family.ente.io|$BASE_URL/family"
|
"https://family.ente.io|$FAMILY_URL"
|
||||||
"https://ente.io|$BASE_URL"
|
"https://ente.io|$PHOTOS_URL"
|
||||||
)
|
)
|
||||||
OLD_IFS="$IFS"
|
OLD_IFS="$IFS"
|
||||||
for entry in "${FRONTEND_REPLACEMENTS[@]}"; do
|
for entry in "${FRONTEND_REPLACEMENTS[@]}"; do
|
||||||
@@ -483,10 +530,14 @@ chown -R cloudron:cloudron "$DATA_DIR/home"
|
|||||||
chmod 700 "$DATA_DIR/home"
|
chmod 700 "$DATA_DIR/home"
|
||||||
|
|
||||||
log INFO "Rendering Caddy configuration"
|
log INFO "Rendering Caddy configuration"
|
||||||
|
if [ "$USE_SUBDOMAIN_ROUTING" = true ]; then
|
||||||
cat > "$CADDY_CONFIG" <<EOF_CADDY
|
cat > "$CADDY_CONFIG" <<EOF_CADDY
|
||||||
{
|
{
|
||||||
admin off
|
admin off
|
||||||
auto_https off
|
auto_https off
|
||||||
|
servers {
|
||||||
|
trusted_proxies static private_ranges
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:3080 {
|
:3080 {
|
||||||
@@ -499,33 +550,44 @@ cat > "$CADDY_CONFIG" <<EOF_CADDY
|
|||||||
|
|
||||||
@options {
|
@options {
|
||||||
method OPTIONS
|
method OPTIONS
|
||||||
|
header Origin *
|
||||||
}
|
}
|
||||||
handle @options {
|
handle @options {
|
||||||
header Access-Control-Allow-Origin "*"
|
header Access-Control-Allow-Origin "{http.request.header.Origin}"
|
||||||
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
header Access-Control-Allow-Headers "*"
|
header Access-Control-Allow-Headers "*"
|
||||||
|
header Access-Control-Allow-Credentials "true"
|
||||||
header Access-Control-Max-Age "3600"
|
header Access-Control-Max-Age "3600"
|
||||||
|
header Vary "Origin"
|
||||||
respond 204
|
respond 204
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_path /api/* {
|
handle_path /api/* {
|
||||||
reverse_proxy localhost:8080 {
|
reverse_proxy localhost:8080 {
|
||||||
header_up Host {http.request.host}
|
header_up Host {http.request.host}
|
||||||
header_up X-Real-IP {http.request.header.X-Real-IP}
|
header_up X-Real-IP {http.request.header.X-Forwarded-For}
|
||||||
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
||||||
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
||||||
}
|
}
|
||||||
header Access-Control-Allow-Origin "*"
|
@api_cors {
|
||||||
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
header Origin *
|
||||||
header Access-Control-Allow-Headers "*"
|
}
|
||||||
header Access-Control-Allow-Credentials "true"
|
header -Access-Control-Allow-Origin
|
||||||
|
header -Access-Control-Allow-Credentials
|
||||||
|
header @api_cors {
|
||||||
|
Access-Control-Allow-Origin {http.request.header.Origin}
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers "*"
|
||||||
|
Access-Control-Allow-Credentials "true"
|
||||||
|
Vary "Origin"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handle /health {
|
handle /health {
|
||||||
rewrite * /ping
|
rewrite * /ping
|
||||||
reverse_proxy localhost:8080 {
|
reverse_proxy localhost:8080 {
|
||||||
header_up Host {http.request.host}
|
header_up Host {http.request.host}
|
||||||
header_up X-Real-IP {http.request.header.X-Real-IP}
|
header_up X-Real-IP {http.request.header.X-Forwarded-For}
|
||||||
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
||||||
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
||||||
}
|
}
|
||||||
@@ -534,7 +596,130 @@ cat > "$CADDY_CONFIG" <<EOF_CADDY
|
|||||||
handle /ping {
|
handle /ping {
|
||||||
reverse_proxy localhost:8080 {
|
reverse_proxy localhost:8080 {
|
||||||
header_up Host {http.request.host}
|
header_up Host {http.request.host}
|
||||||
header_up X-Real-IP {http.request.header.X-Real-IP}
|
header_up X-Real-IP {http.request.header.X-Forwarded-For}
|
||||||
|
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
||||||
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /public/* {
|
||||||
|
reverse_proxy localhost:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
@photos_host host ${PHOTOS_HOST}
|
||||||
|
handle @photos_host {
|
||||||
|
root * $WEB_RUNTIME_DIR/photos
|
||||||
|
try_files {path} {path}/index.html /photos/index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
@accounts_host host ${ACCOUNTS_HOST}
|
||||||
|
handle @accounts_host {
|
||||||
|
root * $WEB_RUNTIME_DIR/accounts
|
||||||
|
try_files {path} {path}/index.html /accounts/index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
@auth_host host ${AUTH_HOST}
|
||||||
|
handle @auth_host {
|
||||||
|
root * $WEB_RUNTIME_DIR/auth
|
||||||
|
try_files {path} {path}/index.html /auth/index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
@cast_host host ${CAST_HOST}
|
||||||
|
handle @cast_host {
|
||||||
|
root * $WEB_RUNTIME_DIR/cast
|
||||||
|
try_files {path} {path}/index.html /cast/index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
@albums_host host ${ALBUMS_HOST}
|
||||||
|
handle @albums_host {
|
||||||
|
root * $WEB_RUNTIME_DIR/albums
|
||||||
|
try_files {path} {path}/index.html /albums/index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
@family_host host ${FAMILY_HOST}
|
||||||
|
handle @family_host {
|
||||||
|
root * $WEB_RUNTIME_DIR/family
|
||||||
|
try_files {path} {path}/index.html /family/index.html
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
|
||||||
|
handle {
|
||||||
|
respond "Not Found" 404
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF_CADDY
|
||||||
|
else
|
||||||
|
cat > "$CADDY_CONFIG" <<EOF_CADDY
|
||||||
|
{
|
||||||
|
admin off
|
||||||
|
auto_https off
|
||||||
|
servers {
|
||||||
|
trusted_proxies static private_ranges
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:3080 {
|
||||||
|
log {
|
||||||
|
level INFO
|
||||||
|
output stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
encode gzip
|
||||||
|
|
||||||
|
@options {
|
||||||
|
method OPTIONS
|
||||||
|
header Origin *
|
||||||
|
}
|
||||||
|
handle @options {
|
||||||
|
header Access-Control-Allow-Origin "{http.request.header.Origin}"
|
||||||
|
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
header Access-Control-Allow-Headers "*"
|
||||||
|
header Access-Control-Allow-Credentials "true"
|
||||||
|
header Access-Control-Max-Age "3600"
|
||||||
|
header Vary "Origin"
|
||||||
|
respond 204
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /api/* {
|
||||||
|
reverse_proxy localhost:8080 {
|
||||||
|
header_up Host {http.request.host}
|
||||||
|
header_up X-Real-IP {http.request.header.X-Forwarded-For}
|
||||||
|
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
||||||
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
||||||
|
}
|
||||||
|
@api_cors {
|
||||||
|
header Origin *
|
||||||
|
}
|
||||||
|
header -Access-Control-Allow-Origin
|
||||||
|
header -Access-Control-Allow-Credentials
|
||||||
|
header @api_cors {
|
||||||
|
Access-Control-Allow-Origin {http.request.header.Origin}
|
||||||
|
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
||||||
|
Access-Control-Allow-Headers "*"
|
||||||
|
Access-Control-Allow-Credentials "true"
|
||||||
|
Vary "Origin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /health {
|
||||||
|
rewrite * /ping
|
||||||
|
reverse_proxy localhost:8080 {
|
||||||
|
header_up Host {http.request.host}
|
||||||
|
header_up X-Real-IP {http.request.header.X-Forwarded-For}
|
||||||
|
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
||||||
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /ping {
|
||||||
|
reverse_proxy localhost:8080 {
|
||||||
|
header_up Host {http.request.host}
|
||||||
|
header_up X-Real-IP {http.request.header.X-Forwarded-For}
|
||||||
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
header_up X-Forwarded-For {http.request.header.X-Forwarded-For}
|
||||||
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
header_up X-Forwarded-Proto {http.request.header.X-Forwarded-Proto}
|
||||||
}
|
}
|
||||||
@@ -598,6 +783,7 @@ cat > "$CADDY_CONFIG" <<EOF_CADDY
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF_CADDY
|
EOF_CADDY
|
||||||
|
fi
|
||||||
|
|
||||||
chown cloudron:cloudron "$CADDY_CONFIG"
|
chown cloudron:cloudron "$CADDY_CONFIG"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user