Migrate services to rspace.online domains and fix Traefik routing
- Add separate routers for rspace.online aliases (collab, ipfs, ipfs-api) instead of || syntax to avoid priority conflicts - Fix healthcheck quoting for Node.js v23 TypeScript-style parsing - Update IPFS client defaults from jeffemmett.com to rspace.online - Add rspace.online CORS origins to collab-server Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b19d2c1ad7
commit
6291b2cb2d
|
|
@ -3,7 +3,9 @@
|
|||
#
|
||||
# Deploy: scp to Netcup /opt/apps/collab-server/, docker compose up -d
|
||||
# Requires: Traefik proxy network
|
||||
# DNS: collab.jeffemmett.com, ipfs.jeffemmett.com, ipfs-api.jeffemmett.com
|
||||
# DNS: collab.jeffemmett.com / collab.rspace.online
|
||||
# ipfs.jeffemmett.com / ipfs.rspace.online
|
||||
# ipfs-api.jeffemmett.com / ipfs-api.rspace.online
|
||||
|
||||
services:
|
||||
collab-server:
|
||||
|
|
@ -17,7 +19,7 @@ services:
|
|||
NODE_ENV: production
|
||||
MONGODB_URI: mongodb://collab-mongo:27017/collaboration
|
||||
REDIS_ENABLED: "false"
|
||||
CORS_ORIGINS: "https://rnotes.jeffemmett.com,https://rspace.jeffemmett.com,http://localhost:3000,http://localhost:5173"
|
||||
CORS_ORIGINS: "https://rnotes.jeffemmett.com,https://rspace.jeffemmett.com,https://collab.rspace.online,https://ipfs.rspace.online,https://collab.jeffemmett.com,http://localhost:3000,http://localhost:5173"
|
||||
SERVER_DID: "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
|
||||
RATE_LIMIT_WINDOW_MS: 900000
|
||||
RATE_LIMIT_MAX: 100
|
||||
|
|
@ -26,14 +28,21 @@ services:
|
|||
- collab-internal
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# Primary domain
|
||||
- "traefik.http.routers.collab.rule=Host(`collab.jeffemmett.com`)"
|
||||
- "traefik.http.routers.collab.entrypoints=web"
|
||||
- "traefik.http.routers.collab.service=collab"
|
||||
# rspace.online alias
|
||||
- "traefik.http.routers.collab-rspace.rule=Host(`collab.rspace.online`)"
|
||||
- "traefik.http.routers.collab-rspace.entrypoints=web"
|
||||
- "traefik.http.routers.collab-rspace.service=collab"
|
||||
# Shared service
|
||||
- "traefik.http.services.collab.loadbalancer.server.port=5001"
|
||||
depends_on:
|
||||
collab-mongo:
|
||||
condition: service_started
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "fetch('http://localhost:5001/health').then(r => process.exit(r.ok ? 0 : 1))"]
|
||||
test: ["CMD-SHELL", "node -e \"fetch('http://localhost:5001/health').then(r=>process.exit(r.ok?0:1))\""]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
|
@ -60,19 +69,30 @@ services:
|
|||
- collab-internal
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
# IPFS Gateway (public, read-only)
|
||||
# IPFS Gateway — primary domain
|
||||
- "traefik.http.routers.ipfs-gw.rule=Host(`ipfs.jeffemmett.com`)"
|
||||
- "traefik.http.routers.ipfs-gw.entrypoints=web"
|
||||
- "traefik.http.routers.ipfs-gw.service=ipfs-gw"
|
||||
# IPFS Gateway — rspace.online alias
|
||||
- "traefik.http.routers.ipfs-gw-rspace.rule=Host(`ipfs.rspace.online`)"
|
||||
- "traefik.http.routers.ipfs-gw-rspace.entrypoints=web"
|
||||
- "traefik.http.routers.ipfs-gw-rspace.service=ipfs-gw"
|
||||
# Shared gateway service
|
||||
- "traefik.http.services.ipfs-gw.loadbalancer.server.port=8080"
|
||||
# IPFS API (private, Headscale-only access via IP allowlist)
|
||||
# IPFS API — primary domain
|
||||
- "traefik.http.routers.ipfs-api.rule=Host(`ipfs-api.jeffemmett.com`)"
|
||||
- "traefik.http.routers.ipfs-api.entrypoints=web"
|
||||
- "traefik.http.routers.ipfs-api.service=ipfs-api"
|
||||
- "traefik.http.routers.ipfs-api.middlewares=ipfs-api-ipallow"
|
||||
# IPFS API — rspace.online alias
|
||||
- "traefik.http.routers.ipfs-api-rspace.rule=Host(`ipfs-api.rspace.online`)"
|
||||
- "traefik.http.routers.ipfs-api-rspace.entrypoints=web"
|
||||
- "traefik.http.routers.ipfs-api-rspace.service=ipfs-api"
|
||||
- "traefik.http.routers.ipfs-api-rspace.middlewares=ipfs-api-ipallow"
|
||||
# Shared API service
|
||||
- "traefik.http.services.ipfs-api.loadbalancer.server.port=5001"
|
||||
# Restrict API to Headscale mesh + Cloudflare tunnel IPs
|
||||
- "traefik.http.middlewares.ipfs-api-ipallow.ipallowlist.sourcerange=100.64.0.0/10,127.0.0.1/32,172.16.0.0/12"
|
||||
- "traefik.http.routers.ipfs-api.middlewares=ipfs-api-ipallow"
|
||||
healthcheck:
|
||||
test: ["CMD", "ipfs", "id"]
|
||||
interval: 30s
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export class PinataBackend implements IPFSBackend {
|
|||
|
||||
constructor(jwt: string, gateway?: string) {
|
||||
this.jwt = jwt
|
||||
this.gateway = gateway ?? 'https://ipfs.jeffemmett.com/ipfs'
|
||||
this.gateway = gateway ?? 'https://ipfs.rspace.online/ipfs'
|
||||
}
|
||||
|
||||
async upload(data: Uint8Array, filename: string): Promise<string> {
|
||||
|
|
@ -101,8 +101,8 @@ export class KuboBackend implements IPFSBackend {
|
|||
|
||||
/** Create KuboBackend from environment variables */
|
||||
static fromEnv(): KuboBackend {
|
||||
const apiUrl = process.env.IPFS_API_URL || 'https://ipfs-api.jeffemmett.com'
|
||||
const gatewayUrl = process.env.IPFS_GATEWAY_URL || 'https://ipfs.jeffemmett.com'
|
||||
const apiUrl = process.env.IPFS_API_URL || 'https://ipfs-api.rspace.online'
|
||||
const gatewayUrl = process.env.IPFS_GATEWAY_URL || 'https://ipfs.rspace.online'
|
||||
const authToken = process.env.IPFS_AUTH_TOKEN
|
||||
return new KuboBackend(apiUrl, gatewayUrl, authToken)
|
||||
}
|
||||
|
|
@ -213,7 +213,7 @@ export class EncryptedIPFSClient {
|
|||
* Generate an IPFS gateway URL (returns encrypted content — client must decrypt)
|
||||
*/
|
||||
gatewayUrl(cid: string, gateway?: string): string {
|
||||
return `${gateway ?? 'https://ipfs.jeffemmett.com/ipfs'}/${cid}`
|
||||
return `${gateway ?? 'https://ipfs.rspace.online/ipfs'}/${cid}`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ export function createImageAttrs(
|
|||
alt?: string
|
||||
): IPFSImageAttrs {
|
||||
return {
|
||||
src: `${gateway ?? 'https://ipfs.jeffemmett.com/ipfs'}/${metadata.cid}`,
|
||||
src: `${gateway ?? 'https://ipfs.rspace.online/ipfs'}/${metadata.cid}`,
|
||||
cid: metadata.cid,
|
||||
encKey: metadata.encryptionKey,
|
||||
alt: alt ?? metadata.filename,
|
||||
|
|
@ -253,8 +253,8 @@ export function createImageAttrs(
|
|||
|
||||
/** Create an EncryptedIPFSClient using the self-hosted kubo node */
|
||||
export function createSelfHostedClient(
|
||||
apiUrl = 'https://ipfs-api.jeffemmett.com',
|
||||
gatewayUrl = 'https://ipfs.jeffemmett.com'
|
||||
apiUrl = 'https://ipfs-api.rspace.online',
|
||||
gatewayUrl = 'https://ipfs.rspace.online'
|
||||
): EncryptedIPFSClient {
|
||||
return new EncryptedIPFSClient(new KuboBackend(apiUrl, gatewayUrl))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue