diff --git a/lemmy.yml b/lemmy.yml index 2c6a7aa..37f4009 100644 --- a/lemmy.yml +++ b/lemmy.yml @@ -90,8 +90,6 @@ - block: - set_fact: lemmy_port: "{{ 32767 |random(start=1024) }}" - lemmy_ui_port: "{{ 32767 |random(start=1024) }}" - pictrs_port: "{{ 32767 |random(start=1024) }}" - name: add template files template: @@ -102,6 +100,9 @@ - src: "templates/docker-compose.yml" dest: "{{lemmy_base_dir}}/{{domain}}/docker-compose.yml" mode: "0600" + - src: "templates/nginx_internal.conf" + dest: "{{lemmy_base_dir}}/{{domain}}/nginx_internal.conf" + mode: "0644" - src: "templates/nginx.conf" dest: "/etc/nginx/sites-available/{{domain}}.conf" mode: "0644" diff --git a/templates/docker-compose.yml b/templates/docker-compose.yml index ce5ea96..39fba74 100644 --- a/templates/docker-compose.yml +++ b/templates/docker-compose.yml @@ -1,56 +1,114 @@ -version: '2' +version: "3.7" +x-logging: &default-logging + driver: "json-file" + options: + max-size: "50m" + max-file: "4" + +networks: + # communication to web and clients + lemmyexternalproxy: + # communication between lemmy services + lemmyinternal: + driver: bridge + internal: true services: + proxy: + image: nginx:1-alpine + networks: + - lemmyinternal + - lemmyexternalproxy + ports: + # actual and only port facing any connection from outside + # Note, change the left number if port 1236 is already in use on your system + # You could use port 80 if you won't use a reverse proxy + - "{{ lemmy_port }}:8536" + volumes: + - ./nginx_internal.conf:/etc/nginx/nginx.conf:ro,Z + restart: always + logging: *default-logging + depends_on: + - pictrs + - lemmy-ui + lemmy: image: {{ lemmy_docker_image }} - ports: - - "127.0.0.1:{{ lemmy_port }}:8536" + hostname: lemmy + networks: + - lemmyinternal + - lemmyexternalproxy restart: always + logging: *default-logging environment: - - RUST_LOG="warn,lemmy_server=info,lemmy_api=info,lemmy_api_common=info,lemmy_api_crud=info,lemmy_apub=info,lemmy_db_queries=info,lemmy_db_schema=info,lemmy_db_views=info,lemmy_db_views_actor=info,lemmy_db_views_moderator=info,lemmy_routes=info,lemmy_utils=info,lemmy_websocket=info" + - RUST_LOG="warn" volumes: - - ./lemmy.hjson:/config/config.hjson + - ./lemmy.hjson:/config/config.hjson:Z depends_on: - postgres - pictrs lemmy-ui: image: {{ lemmy_docker_ui_image }} - ports: - - "127.0.0.1:{{ lemmy_ui_port }}:1234" - restart: always + networks: + - lemmyinternal environment: - LEMMY_UI_LEMMY_INTERNAL_HOST=lemmy:8536 - LEMMY_UI_LEMMY_EXTERNAL_HOST={{ domain }} - LEMMY_UI_HTTPS=true volumes: - ./volumes/lemmy-ui/extra_themes:/app/extra_themes - depends_on: + depends_on: - lemmy + restart: always + logging: *default-logging + + pictrs: + image: asonix/pictrs:0.4.0-rc.7 + # this needs to match the pictrs url in lemmy.hjson + hostname: pictrs + # we can set options to pictrs like this, here we set max. image size and forced format for conversion + # entrypoint: /sbin/tini -- /usr/local/bin/pict-rs -p /mnt -m 4 --image-format webp + networks: + - lemmyinternal + environment: + - PICTRS_OPENTELEMETRY_URL=http://otel:4137 + - PICTRS__API_KEY=API_KEY + - RUST_LOG=debug + - RUST_BACKTRACE=full + - PICTRS__MEDIA__VIDEO_CODEC=vp9 + - PICTRS__MEDIA__GIF__MAX_WIDTH=256 + - PICTRS__MEDIA__GIF__MAX_HEIGHT=256 + - PICTRS__MEDIA__GIF__MAX_AREA=65536 + - PICTRS__MEDIA__GIF__MAX_FRAME_COUNT=400 + user: 991:991 + volumes: + - ./volumes/pictrs:/mnt:Z + restart: always + logging: *default-logging + deploy: + resources: + limits: + memory: 690m postgres: image: postgres:15-alpine + hostname: postgres + networks: + - lemmyinternal environment: - POSTGRES_USER=lemmy - POSTGRES_PASSWORD={{ postgres_password }} - POSTGRES_DB=lemmy volumes: - - ./volumes/postgres:/var/lib/postgresql/data + - ./volumes/postgres:/var/lib/postgresql/data:Z - ./customPostgresql.conf:/etc/postgresql.conf restart: always - - pictrs: - image: asonix/pictrs:0.3.1 - user: 991:991 - ports: - - "127.0.0.1:{{ pictrs_port }}:8080" - volumes: - - ./volumes/pictrs:/mnt - restart: always - mem_limit: 690m + logging: *default-logging postfix: image: mwader/postfix-relay environment: - POSTFIX_myhostname={{ domain }} restart: "always" + logging: *default-logging diff --git a/templates/nginx.conf b/templates/nginx.conf index d26b801..9a97966 100644 --- a/templates/nginx.conf +++ b/templates/nginx.conf @@ -20,84 +20,12 @@ server { ssl_certificate /etc/letsencrypt/live/{{domain}}/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/{{domain}}/privkey.pem; - # Various TLS hardening settings - # https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers on; - ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; - ssl_session_timeout 10m; - ssl_session_cache shared:SSL:10m; - ssl_session_tickets on; - ssl_stapling on; - ssl_stapling_verify on; - - # Hide nginx version - server_tokens off; - - # Enable compression for JS/CSS/HTML bundle, for improved client load times. - # It might be nice to compress JSON, but leaving that out to protect against potential - # compression+encryption information leak attacks like BREACH. - gzip on; - gzip_types text/css application/javascript image/svg+xml; - gzip_vary on; - - # Only connect to this site via HTTPS for the two years - add_header Strict-Transport-Security "max-age=63072000"; - - # Various content security headers - add_header Referrer-Policy "same-origin"; - add_header X-Content-Type-Options "nosniff"; - add_header X-Frame-Options "DENY"; - add_header X-XSS-Protection "1; mode=block"; - - # Upload limit for pictrs - client_max_body_size 20M; - - # frontend location / { - # The default ports: - # lemmy_ui_port: 1235 - # lemmy_port: 8536 - - set $proxpass "http://0.0.0.0:{{lemmy_ui_port}}"; - if ($http_accept ~ "^application/.*$") { - set $proxpass "http://0.0.0.0:{{lemmy_port}}"; - } - if ($request_method = POST) { - set $proxpass "http://0.0.0.0:{{lemmy_port}}"; - } - proxy_pass $proxpass; - - rewrite ^(.+)/+$ $1 permanent; - - # Send actual client IP upstream - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - - # backend - location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) { proxy_pass http://0.0.0.0:{{lemmy_port}}; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; - - # Rate limit - limit_req zone={{domain}}_ratelimit burst=30 nodelay; - - # Add IP forwarding headers - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } - - - # Redirect pictshare images to pictrs - location ~ /pictshare/(.*)$ { - return 301 /pictrs/image/$1; - } - } access_log /var/log/nginx/access.log combined; diff --git a/templates/nginx_internal.conf b/templates/nginx_internal.conf new file mode 100644 index 0000000..02e7345 --- /dev/null +++ b/templates/nginx_internal.conf @@ -0,0 +1,72 @@ +worker_processes auto; +events { + worker_connections 1024; +} +http { + upstream lemmy { + # this needs to map to the lemmy (server) docker service hostname + server "lemmy:8536"; + } + upstream lemmy-ui { + # this needs to map to the lemmy-ui docker service hostname + server "lemmy-ui:1234"; + } + + server { + # this is the port inside docker, not the public one yet + listen 1236; + listen 8536; + # change if needed, this is facing the public web + server_name localhost; + server_tokens off; + + gzip on; + gzip_types text/css application/javascript image/svg+xml; + gzip_vary on; + + # Upload limit, relevant for pictrs + client_max_body_size 20M; + + add_header X-Frame-Options SAMEORIGIN; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + + # frontend general requests + location / { + # distinguish between ui requests and backend + # don't change lemmy-ui or lemmy here, they refer to the upstream definitions on top + set $proxpass "http://lemmy-ui"; + + if ($http_accept = "application/activity+json") { + set $proxpass "http://lemmy"; + } + if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") { + set $proxpass "http://lemmy"; + } + if ($request_method = POST) { + set $proxpass "http://lemmy"; + } + proxy_pass $proxpass; + + rewrite ^(.+)/+$ $1 permanent; + # Send actual client IP upstream + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + # backend + location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) { + proxy_pass "http://lemmy"; + # proxy common stuff + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Send actual client IP upstream + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } +}