From 1a3d05ffc31761ef594e6e31815987de605740ff Mon Sep 17 00:00:00 2001 From: Zack Pollard Date: Fri, 24 Jun 2022 04:18:50 +0100 Subject: [PATCH] chore: improve default setup (#234) * chore: remove UPLOAD_LOCATION as it isn't used in the server * docker: remove network in docker compose as docker creates one by default * nginx: update reverse proxy to put web at root and api at /api * docker: remove unneeded exposed ports and docker network Align dev setup with prod, but with ports exposed for direct connection Most communication between services happens on the internal network, so we don't need to expose all these services. With the nginx changes, the api and web panel are both server through the reverse proxy on / for web and /api for the API. The only service that should expose ports is nginx as that is the entrypoint to the application. * chore: remove CORS now we serve the api on /api in the default setup * docs: update README.md to include /api * Fixed docket-compose file for dev environment and websocket on web and mobile Co-authored-by: Alex Tran --- README.md | 8 +- docker/.env.example | 2 +- docker/.env.test | 2 +- docker/docker-compose.dev.yml | 24 +---- docker/docker-compose.gpu.yml | 92 ------------------- docker/docker-compose.staging.yml | 24 ----- docker/docker-compose.test.yml | 12 +-- docker/docker-compose.yml | 22 ----- docker/settings/nginx-conf/nginx.conf | 29 +++++- .../shared/providers/websocket.provider.dart | 17 ++-- server/apps/immich/src/config/app.config.ts | 1 - server/apps/immich/src/main.ts | 6 +- web/package.json | 2 +- web/src/lib/constants.ts | 2 +- web/src/lib/stores/websocket.ts | 26 ++++-- 15 files changed, 67 insertions(+), 202 deletions(-) delete mode 100644 docker/docker-compose.gpu.yml diff --git a/README.md b/README.md index 08485affca..a1261ccba4 100644 --- a/README.md +++ b/README.md @@ -143,8 +143,8 @@ MAPBOX_KEY= # This is the URL of your vm/server where you host Immich, so that the web frontend # know where can it make the request to. # For example: If your server IP address is 10.1.11.50, the environment variable will -# be VITE_SERVER_ENDPOINT=http://10.1.11.50:2283 -VITE_SERVER_ENDPOINT=http://192.168.1.216:2283 +# be VITE_SERVER_ENDPOINT=http://10.1.11.50:2283/api +VITE_SERVER_ENDPOINT=http://192.168.1.216:2283/api ``` ## Step 2: Start the server @@ -167,11 +167,11 @@ To *update* docker-compose with newest image (if you have started the docker-com docker-compose -f ./docker/docker-compose.yml pull && docker-compose -f ./docker/docker-compose.yml up ``` -The server will be running at `http://your-ip:2283` through `Nginx` +The server will be running at `http://your-ip:2283/api` through `Nginx` ## Step 3: Register User -Access the web interface at `http://your-ip:2285` to register an admin account. +Access the web interface at `http://your-ip:2283` to register an admin account.

diff --git a/docker/.env.example b/docker/.env.example index e9f12364ab..35cc56f104 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -57,7 +57,7 @@ MAPBOX_KEY= # This is the URL of your vm/server where you host Immich, so that the web frontend # know where can it make the request to. # For example: If your server IP address is 10.1.11.50, the environment variable will -# be VITE_SERVER_ENDPOINT=http://10.1.11.50:2283 +# be VITE_SERVER_ENDPOINT=http://10.1.11.50:2283/api # !CAUTION! THERE IS NO FORWARD SLASH AT THE END VITE_SERVER_ENDPOINT= diff --git a/docker/.env.test b/docker/.env.test index 7171aa3822..95b4f25a53 100644 --- a/docker/.env.test +++ b/docker/.env.test @@ -19,4 +19,4 @@ ENABLE_MAPBOX=false # WEB MAPBOX_KEY= -VITE_SERVER_ENDPOINT=http://localhost:2283 \ No newline at end of file +VITE_SERVER_ENDPOINT=http://localhost:2283/api \ No newline at end of file diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 34635f6971..bb095cd0fc 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -2,7 +2,7 @@ version: "3.8" services: immich-server: - image: immich-server-dev:1.9.0 + image: immich-server-dev:latest build: context: ../server dockerfile: Dockerfile @@ -20,11 +20,9 @@ services: depends_on: - redis - database - networks: - - immich-network immich-machine-learning: - image: immich-machine-learning-dev:1.9.0 + image: immich-machine-learning-dev:latest build: context: ../machine-learning dockerfile: Dockerfile @@ -41,11 +39,9 @@ services: - NODE_ENV=development depends_on: - database - networks: - - immich-network immich-microservices: - image: immich-microservices:1.9.0 + image: immich-microservices:latest build: context: ../server dockerfile: Dockerfile @@ -61,8 +57,6 @@ services: depends_on: - database - immich-server - networks: - - immich-network immich-web: image: immich-web-dev:1.9.0 @@ -74,20 +68,16 @@ services: env_file: - .env ports: - - 3002:3002 + - 3002:3000 - 24678:24678 volumes: - ../web:/usr/src/app - /usr/src/app/node_modules - networks: - - immich-network restart: always redis: container_name: immich_redis image: redis:6.2 - networks: - - immich-network database: container_name: immich_postgres @@ -103,8 +93,6 @@ services: - pgdata:/var/lib/postgresql/data ports: - 5432:5432 - networks: - - immich-network nginx: container_name: proxy_nginx @@ -116,12 +104,8 @@ services: - 2284:443 logging: driver: none - networks: - - immich-network depends_on: - immich-server -networks: - immich-network: volumes: pgdata: diff --git a/docker/docker-compose.gpu.yml b/docker/docker-compose.gpu.yml deleted file mode 100644 index e085c4d48f..0000000000 --- a/docker/docker-compose.gpu.yml +++ /dev/null @@ -1,92 +0,0 @@ -version: "3.8" - -services: - immich-server: - image: immich-server-dev:1.9.0 - build: - context: ../server - dockerfile: Dockerfile - command: npm run start:dev - expose: - - "3000" - volumes: - - ../server:/usr/src/app - - ${UPLOAD_LOCATION}:/usr/src/app/upload - - /usr/src/app/node_modules - env_file: - - .env - depends_on: - - redis - - database - networks: - - immich-network - - immich-microservices: - image: immich-microservices-dev:1.9.0 - build: - context: ../microservices - dockerfile: Dockerfile - command: npm run start:dev - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: 1 - capabilities: [ gpu ] - expose: - - "3001" - volumes: - - ../microservices:/usr/src/app - - ${UPLOAD_LOCATION}:/usr/src/app/upload - - /usr/src/app/node_modules - env_file: - - .env - depends_on: - - database - - immich_server - networks: - - immich-network - - redis: - container_name: immich_redis - image: redis:6.2 - networks: - - immich-network - - database: - container_name: immich_postgres - image: postgres:14 - env_file: - - .env - environment: - POSTGRES_PASSWORD: ${DB_PASSWORD} - POSTGRES_USER: ${DB_USERNAME} - POSTGRES_DB: ${DB_DATABASE_NAME} - PG_DATA: /var/lib/postgresql/data - volumes: - - pgdata:/var/lib/postgresql/data - ports: - - 5432:5432 - networks: - - immich-network - - nginx: - container_name: proxy_nginx - image: nginx:latest - volumes: - - ./settings/nginx-conf:/etc/nginx/conf.d - ports: - - 2283:80 - - 2284:443 - logging: - driver: none - networks: - - immich-network - depends_on: - - immich-server - -networks: - immich-network: -volumes: - pgdata: diff --git a/docker/docker-compose.staging.yml b/docker/docker-compose.staging.yml index 55b442d832..57dab629c8 100644 --- a/docker/docker-compose.staging.yml +++ b/docker/docker-compose.staging.yml @@ -4,8 +4,6 @@ services: immich-server: image: altran1502/immich-server:staging entrypoint: ["/bin/sh", "./start-server.sh"] - expose: - - "3000" volumes: - ${UPLOAD_LOCATION}:/usr/src/app/upload env_file: @@ -15,8 +13,6 @@ services: depends_on: - redis - database - networks: - - immich-network restart: always immich-microservices: @@ -31,15 +27,11 @@ services: depends_on: - redis - database - networks: - - immich-network restart: always immich-machine-learning: image: altran1502/immich-machine-learning:staging entrypoint: ["/bin/sh", "./entrypoint.sh"] - expose: - - "3001" volumes: - ${UPLOAD_LOCATION}:/usr/src/app/upload env_file: @@ -48,8 +40,6 @@ services: - NODE_ENV=production depends_on: - database - networks: - - immich-network restart: always immich-web: @@ -57,17 +47,11 @@ services: entrypoint: ["/bin/sh", "./entrypoint.sh"] env_file: - .env - ports: - - 2285:3000 - networks: - - immich-network restart: always redis: container_name: immich_redis image: redis:6.2 - networks: - - immich-network restart: always database: @@ -82,10 +66,6 @@ services: PG_DATA: /var/lib/postgresql/data volumes: - pgdata:/var/lib/postgresql/data - ports: - - 5432:5432 - networks: - - immich-network restart: always nginx: @@ -98,13 +78,9 @@ services: - 2284:443 logging: driver: none - networks: - - immich-network depends_on: - immich-server restart: always -networks: - immich-network: volumes: pgdata: diff --git a/docker/docker-compose.test.yml b/docker/docker-compose.test.yml index 603e05d601..fd28ec33b6 100644 --- a/docker/docker-compose.test.yml +++ b/docker/docker-compose.test.yml @@ -2,7 +2,7 @@ version: "3.8" services: immich_server_test: - image: immich-server-dev:1.9.0 + image: immich-server-dev:latest build: context: ../server dockerfile: Dockerfile @@ -19,15 +19,10 @@ services: depends_on: - redis - database - networks: - - immich_network_test - redis: container_name: immich_redis_test image: redis:6.2 - networks: - - immich_network_test database: container_name: immich_postgres_test @@ -43,8 +38,3 @@ services: - /var/lib/postgresql/data ports: - 5432:5432 - networks: - - immich_network_test - -networks: - immich_network_test: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 8792aae007..38a98a41a3 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -4,8 +4,6 @@ services: immich-server: image: altran1502/immich-server:latest entrypoint: ["/bin/sh", "./start-server.sh"] - expose: - - "3000" volumes: - ${UPLOAD_LOCATION}:/usr/src/app/upload env_file: @@ -15,8 +13,6 @@ services: depends_on: - redis - database - networks: - - immich-network restart: always immich-microservices: @@ -31,15 +27,11 @@ services: depends_on: - redis - database - networks: - - immich-network restart: always immich-machine-learning: image: altran1502/immich-machine-learning:latest entrypoint: ["/bin/sh", "./entrypoint.sh"] - expose: - - "3001" volumes: - ${UPLOAD_LOCATION}:/usr/src/app/upload env_file: @@ -48,8 +40,6 @@ services: - NODE_ENV=production depends_on: - database - networks: - - immich-network restart: always immich-web: @@ -57,17 +47,11 @@ services: entrypoint: ["/bin/sh", "./entrypoint.sh"] env_file: - .env - ports: - - 2285:3000 - networks: - - immich-network restart: always redis: container_name: immich_redis image: redis:6.2 - networks: - - immich-network restart: always database: @@ -82,8 +66,6 @@ services: PG_DATA: /var/lib/postgresql/data volumes: - pgdata:/var/lib/postgresql/data - networks: - - immich-network restart: always nginx: @@ -96,13 +78,9 @@ services: - 2284:443 logging: driver: none - networks: - - immich-network depends_on: - immich-server restart: always -networks: - immich-network: volumes: pgdata: diff --git a/docker/settings/nginx-conf/nginx.conf b/docker/settings/nginx-conf/nginx.conf index 92bca82162..722cd5103f 100644 --- a/docker/settings/nginx-conf/nginx.conf +++ b/docker/settings/nginx-conf/nginx.conf @@ -19,6 +19,33 @@ server { listen 80; access_log off; + location /api { + + # Compression + gzip_static on; + gzip_min_length 1000; + gzip_comp_level 2; + + proxy_buffering off; + proxy_buffer_size 16k; + proxy_busy_buffers_size 24k; + proxy_buffers 64 4k; + proxy_force_ranges on; + + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + + rewrite /api/(.*) /$1 break; + + proxy_pass http://immich-server:3000; + } + location / { # Compression @@ -41,6 +68,6 @@ server { proxy_set_header Connection "upgrade"; proxy_set_header Host $host; - proxy_pass http://immich-server:3000; + proxy_pass http://immich-web:3000; } } diff --git a/mobile/lib/shared/providers/websocket.provider.dart b/mobile/lib/shared/providers/websocket.provider.dart index e514a8286e..e837eb983e 100644 --- a/mobile/lib/shared/providers/websocket.provider.dart +++ b/mobile/lib/shared/providers/websocket.provider.dart @@ -29,16 +29,13 @@ class WebscoketState { } @override - String toString() => - 'WebscoketState(socket: $socket, isConnected: $isConnected)'; + String toString() => 'WebscoketState(socket: $socket, isConnected: $isConnected)'; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is WebscoketState && - other.socket == socket && - other.isConnected == isConnected; + return other is WebscoketState && other.socket == socket && other.isConnected == isConnected; } @override @@ -46,8 +43,7 @@ class WebscoketState { } class WebsocketNotifier extends StateNotifier { - WebsocketNotifier(this.ref) - : super(WebscoketState(socket: null, isConnected: false)) { + WebsocketNotifier(this.ref) : super(WebscoketState(socket: null, isConnected: false)) { debugPrint("Init websocket instance"); } @@ -62,10 +58,10 @@ class WebsocketNotifier extends StateNotifier { try { debugPrint("[WEBSOCKET] Attempting to connect to ws"); // Configure socket transports must be sepecified - Socket socket = io( - endpoint, + endpoint.toString().replaceAll('/api', ''), OptionBuilder() + .setPath('/api/socket.io') .setTransports(['websocket']) .enableReconnection() .enableForceNew() @@ -126,7 +122,6 @@ class WebsocketNotifier extends StateNotifier { } } -final websocketProvider = - StateNotifierProvider((ref) { +final websocketProvider = StateNotifierProvider((ref) { return WebsocketNotifier(ref); }); diff --git a/server/apps/immich/src/config/app.config.ts b/server/apps/immich/src/config/app.config.ts index b792245f3b..b2509db908 100644 --- a/server/apps/immich/src/config/app.config.ts +++ b/server/apps/immich/src/config/app.config.ts @@ -9,7 +9,6 @@ export const immichAppConfig: ConfigModuleOptions = { DB_USERNAME: Joi.string().required(), DB_PASSWORD: Joi.string().required(), DB_DATABASE_NAME: Joi.string().required(), - UPLOAD_LOCATION: Joi.string().required(), JWT_SECRET: Joi.string().required(), ENABLE_MAPBOX: Joi.boolean().required().valid(true, false), MAPBOX_KEY: Joi.any().when('ENABLE_MAPBOX', { diff --git a/server/apps/immich/src/main.ts b/server/apps/immich/src/main.ts index a61c78caf5..4d62c5576b 100644 --- a/server/apps/immich/src/main.ts +++ b/server/apps/immich/src/main.ts @@ -7,10 +7,12 @@ import { RedisIoAdapter } from './middlewares/redis-io.adapter.middleware'; async function bootstrap() { const app = await NestFactory.create(AppModule); - app.enableCors(); - app.set('trust proxy'); + if (process.env.NODE_ENV === 'development') { + app.enableCors(); + } + app.useWebSocketAdapter(new RedisIoAdapter(app)); await app.listen(3000, () => { diff --git a/web/package.json b/web/package.json index 4a4ea786a0..c494c69118 100644 --- a/web/package.json +++ b/web/package.json @@ -2,7 +2,7 @@ "name": "web", "version": "0.0.1", "scripts": { - "dev": "svelte-kit dev --host 0.0.0.0 --port 3002", + "dev": "svelte-kit dev --host 0.0.0.0", "build": "svelte-kit build", "package": "svelte-kit package", "preview": "svelte-kit preview", diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index c9e952536f..2a403bfb31 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -1 +1 @@ -export const serverEndpoint = import.meta.env.VITE_SERVER_ENDPOINT \ No newline at end of file +export const serverEndpoint: string = import.meta.env.VITE_SERVER_ENDPOINT; diff --git a/web/src/lib/stores/websocket.ts b/web/src/lib/stores/websocket.ts index d37f220922..ae1def81a2 100644 --- a/web/src/lib/stores/websocket.ts +++ b/web/src/lib/stores/websocket.ts @@ -4,17 +4,23 @@ import type { ImmichAsset } from '../models/immich-asset'; import { assets } from './assets'; export const openWebsocketConnection = (accessToken: string) => { - const websocket = io(serverEndpoint, { - transports: ['polling'], - reconnection: true, - forceNew: true, - autoConnect: true, - extraHeaders: { - Authorization: 'Bearer ' + accessToken, - }, - }); + const websocketEndpoint = serverEndpoint.replace('/api', ''); + try { + const websocket = io(websocketEndpoint, { + path: '/api/socket.io', + transports: ['polling'], + reconnection: true, + forceNew: true, + autoConnect: true, + extraHeaders: { + Authorization: 'Bearer ' + accessToken, + }, + }); - listenToEvent(websocket); + listenToEvent(websocket); + } catch (e) { + console.log('Cannot connect to websocket ', e); + } }; const listenToEvent = (socket: Socket) => {