From 87d9f16e874dc4897a3c5dde89462a89274b9632 Mon Sep 17 00:00:00 2001 From: Tommy Date: Sun, 4 Dec 2022 17:19:24 -0500 Subject: [PATCH] Initial upload Signed-off-by: Tommy --- README.md | 7 ++ docker-compose.yml | 81 ++++++++++++++++++++++++ style.css | 1 + swag/proxy-confs/miniflux.subdomain.conf | 39 ++++++++++++ swag/ssl.conf | 41 ++++++++++++ 5 files changed, 169 insertions(+) create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 style.css create mode 100644 swag/proxy-confs/miniflux.subdomain.conf create mode 100644 swag/ssl.conf diff --git a/README.md b/README.md new file mode 100644 index 0000000..816055b --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Miniflux-Docker-Compose +Miniflux Docker-Compose + +1. Update `docker-compose.yml` +2. Update the hostname in `swag/nginx/proxy-confs/miniflux.subdomain.conf` approprieately. +3. Run `docker-compose up` and make sure nothing errors out. You can use `docker-compose up -d` to start it in the background if you want. +4. (Optional) Apply `style.css` in the `Custom CSS` section in settings. This theme is from [reeseovine/miniflux-midnight](https://github.com/reeseovine/miniflux-midnight), I just removed the google remote google CSS lines as they are not necessary and cause issues with CSP. There is no license file in the repository or its upstream unfortunately. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bff79f4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,81 @@ +version: "3" + +services: + miniflux: + image: miniflux/miniflux:latest + container_name: miniflux + restart: unless-stopped + depends_on: + - postgres + environment: + - DATABASE_URL=postgres://miniflux:YOUR_POSTGRES_PASSWORD@postgres/miniflux?sslmode=disable + - RUN_MIGRATIONS=1 + - CREATE_ADMIN=1 + - ADMIN_USERNAME=admin + - ADMIN_PASSWORD=changeme + networks: + - miniflux + - postgres + user: "65534:65534" + read_only: true + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + + postgres: + image: postgres:15-alpine + container_name: postgres + restart: unless-stopped + environment: + - POSTGRES_USER=miniflux + - POSTGRES_PASSWORD=YOUR_POSTGRES_PASSWORD + volumes: + - postgres:/var/lib/postgresql/data + networks: + - postgres + healthcheck: + test: ["CMD", "pg_isready", "-U", "miniflux"] + interval: 15s + timeout: 5s + user: "70:70" + read_only: true + tmpfs: + - /var/run/postgresql:size=50M,mode=0770,uid=70,gid=70,noexec,nosuid,nodev + security_opt: + - no-new-privileges:true + cap_drop: + - ALL + + swag: + image: ghcr.io/linuxserver/swag + container_name: swag + restart: unless-stopped + environment: + - PUID=1000 + - PGID=1000 + - URL=yourdomain.tld + - SUBDOMAINS=rss + - VALIDATION=http + - EMAIL=contact@tommytran.io + - ONLY_SUBDOMAINS=true + volumes: + - ./swag:/config:Z + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - 443:443 + - 80:80 + networks: + - miniflux + security_opt: + - no-new-privileges:true + cap_add: + - NET_ADMIN + +networks: + miniflux: + postgres: + +volumes: + postgres: \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..52be70c --- /dev/null +++ b/style.css @@ -0,0 +1 @@ +:root{--color-white: #fff;--color-green: #2eb54d;--width-body: 900px;--item-title-link-line-height: 1.23;--entry-content-line-height: 1.5;--item-title-link-font-size: 28px;--font-size-smaller: 16px;--font-size-meta: var(--font-size-smaller);--font-size-larger: 20px;--font-size-body: 18px;--item-meta-color: #fff;--item-meta-li-color-hover: #fff;--entry-date-color: #fff;--input-placeholder-color: #fff;--entry-header-border-color: transparent;--pagination-border-color: transparent;--font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--body-color: #efefef;--body-background: #0d1118;--hr-border-color: #555;--title-color: var(--color-white);--link-color: var(--color-white);--link-focus-color: #ddd;--link-hover-color: #ddd;--header-list-border-color: #333;--header-link-color: #ddd;--header-link-focus-color: rgba(82, 168, 236, .85);--header-link-hover-color: rgba(82, 168, 236, .85);--header-active-link-color: #9b9494;--page-header-title-color: var(--color-white);--page-header-title-border-color: #333;--logo-color: #bbb;--logo-hover-color-span: #bbb;--table-border-color: #555;--table-th-background: #333;--table-th-color: var(--color-white);--table-tr-hover-background-color: #333;--table-tr-hover-color: var(--color-white);--button-primary-border-color: transparent;--button-primary-background: #000;--button-primary-color: #fff;--button-primary-focus-border-color: #888;--button-primary-focus-background: #555;--input-border: 0;--input-background: #000;--input-color: #fff;--input-focus-color: #fff;--input-focus-border-color: rgba(82, 168, 236, .8);--input-focus-box-shadow: 0;--alert-color: #efefef;--alert-background-color: transparent;--alert-border-color: transparent;--alert-success-color: var(--color-green);--alert-success-background-color: transparent;--alert-success-border-color: transparent;--alert-error-color: #efefef;--alert-error-background-color: #333;--alert-error-border-color: #888;--alert-info-color: #efefef;--alert-info-background-color: transparent;--alert-info-border-color: transparent;--panel-background: #333;--panel-border-color: #555;--panel-color: #9b9b9b;--modal-background: #333;--modal-color: #efefef;--modal-box-shadow: 0 0 10px rgba(82, 168, 236, .6);--pagination-link-color: var(--color-white);--category-color: #efefef;--category-background-color: #333;--category-border-color: #888;--category-link-color: #999;--category-link-hover-color: var(--color-white);--item-border-color: transparent;--item-padding: 10px;--item-title-link-font-weight: 700;--item-status-read-title-link-color: #aaa;--item-status-read-title-focus-color: rgba(82, 168, 236, .6);--item-meta-focus-color: var(--color-white);--item-meta-li-color: #888;--current-item-border-width: 2px;--current-item-border-color: transparent;--current-item-box-shadow: 0 0 8px rgba(82, 168, 236, .6);--entry-header-title-link-color: var(--color-white);--entry-content-font-family: var(--font-family);--entry-content-color: var(--color-white);--entry-content-code-color: var(--color-white);--entry-content-code-background: #000;--entry-content-code-border-color: transparent;--entry-content-quote-color: #777;--entry-content-abbr-border-color: #777;--entry-enclosure-border-color: #333;--parsing-error-color: #eee;--feed-parsing-error-background-color: transparent;--keyboard-shortcuts-li-color: #9b9b9b;--counter-color: #bbb;--feed-has-unread-background-color: #043004;--feed-has-unread-border-style: none}@media(max-width: 600px){:root{--item-title-link-font-size: 24px}}@media(max-width: 600px){:root{--item-padding: 15px}}.logo{color:var(--color-white);font-family:"Merriweather",serif;font-weight:700;font-style:italic;font-size:1.4em;line-height:.83;letter-spacing:0;margin-left:0;position:relative;transition:opacity .5s cubic-bezier(0.19, 1, 0.22, 1),background-color .2s cubic-bezier(0.19, 1, 0.22, 1)}@media(min-width: 600px){.logo{margin-right:24px}}.logo a{color:var(--color-white)}.logo a span{color:var(--color-green)}.logo a:hover,.logo a:hover span,.logo a:focus,.logo a:focus span{color:var(--color-white);opacity:.7}@media(max-width: 600px){.logo{margin-bottom:40px}}body{font-size:var(--font-size-body);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;max-width:var(--width-body);text-rendering:geometricPrecision}body main,body .header{padding-bottom:var(--item-padding);padding-left:var(--item-padding);padding-right:var(--item-padding);padding-top:var(--item-padding)}.header ul,.header li{list-style:none}.flash-message,.alert-success{padding-left:5px;padding-right:5px}.page-header>h1{padding-bottom:10px}.page-header>ul{list-style:none;margin-left:0;margin-top:10px;padding-left:0}.page-header>ul a{font-size:var(--font-size-larger);opacity:.5;text-decoration:none;transition:opacity .5s cubic-bezier(0.19, 1, 0.22, 1),background-color .2s cubic-bezier(0.19, 1, 0.22, 1)}.page-header>ul a:hover,.page-header>ul a:focus{opacity:1}.items{overflow:visible}body .item{display:grid;margin-bottom:20px;margin-top:30px;overflow:visible;padding-left:0;padding-right:0}.item-title img{display:none}.item-title{display:block;font-size:var(--item-title-link-font-size);line-height:var(--item-title-link-line-height)}.category{background-color:rgba(0,0,0,0);border:0;border-radius:0;clear:left;display:inline-block;float:left;font-size:inherit;margin-bottom:10px;margin-left:0;margin-right:10px;margin-top:10px;padding:0;white-space:normal}.category a{border:1px solid rgba(0,0,0,0);border-radius:2em;color:var(--category-color);font-size:12px;font-weight:500;line-height:18px;padding:2px 7px}.category a[href="/category/1/entries"]{background-color:#2e363e;border-color:#5b6876;color:#bbd5eb}.category a[href="/category/2/entries"]{background-color:#0d2816;border-color:#125c1a;color:#1fd622}.category a[href="/category/3/entries"]{background-color:#2e1528;border-color:#673d56;color:#e697bf}.category a[href="/category/4/entries"]{background-color:#1e2933;border-color:#3f5772;color:#80b5ea}.category a[href="/category/5/entries"]{background-color:#252c1d;border-color:#56723f;color:#b0ea80}.category a[href="/category/6/entries"]{background-color:#25181c;border-color:#723f53;color:#ea80a3}.category a[href="/category/7/entries"]{background-color:#28280d;border-color:#5c5512;color:#cad61f}.category a[href="/category/8/entries"]{background-color:#100d28;border-color:#292a81;color:#5654e0}.category a[href="/category/9/entries"]{background-color:#0d2328;border-color:#296c81;color:#54d4e0}.category a[href="/category/10/entries"]{background-color:#20280d;border-color:#628129;color:#b6e054}.item-meta li,.item-meta a{color:var(--item-meta-li-color)}.item-meta a{transition:color .5s cubic-bezier(0.19, 1, 0.22, 1),background-color .2s cubic-bezier(0.19, 1, 0.22, 1)}.item-meta a:hover,.item-meta a:focus{color:var(--item-meta-li-color-hover)}.item-meta .item-meta-info{margin-top:5px}.item-meta .item-meta-icons{clear:both;float:left;opacity:.7;transition:opacity .5s cubic-bezier(0.19, 1, 0.22, 1),background-color .2s cubic-bezier(0.19, 1, 0.22, 1)}.item-meta .item-meta-icons:hover,.item-meta .item-meta-icons:focus{opacity:1}.entry{padding:0}.entry-content{line-height:var(--entry-content-line-height);text-align:center}.entry-content img{margin:0 auto;border-radius:6px}.entry-content>*{text-align:initial}body .entry-header h1{margin:80px 0 20px}.entry-header{margin-bottom:40px;margin-top:60px;position:relative}.entry-header .entry-date{font-size:16px;font-style:normal;margin-bottom:-30px;margin-top:0;opacity:.4;text-align:end}.entry-header .entry-meta{display:flex;flex-wrap:wrap;margin-bottom:10px}.entry-header .entry-meta *{font-size:var(--font-size-meta)}.entry-header .entry-meta .category{float:none;margin-bottom:20px;margin-top:0;order:1;width:100%}.entry-header .entry-meta .category a{font-weight:500;line-height:18px;padding:4px 12px}.entry-header .entry-meta .entry-website{filter:grayscale(100%);order:2;position:absolute;right:0}.entry-header .entry-meta .entry-author{margin-left:0;margin-top:25px;order:3;position:absolute;right:0}@media(max-width: 600px){.entry-header,body .entry-header h1{margin-top:0}}.entry header h1 a:hover,.entry header h1 a:focus{color:var(--color-white)}.entry-website,.entry-author,.entry-date{color:var(--item-meta-color);opacity:.8}.entry-website a,.entry-author a,.entry-date a{color:var(--item-meta-color);opacity:1}.item-meta .icon,.entry-actions .icon{margin-right:5px}a:focus{outline:none}@media(prefers-reduced-motion: no-preference){.item.current-item,.item,:focus,*:focus,[data-whatinput=keyboard] :focus,[data-whatinput=keyboard] a:focus{outline-offset:5px;transition:outline-offset .25s ease}}.pagination-top{display:none}.pagination{padding:var(--item-padding)}body .pagination-bottom{margin-bottom:60px}body .pagination-bottom a{font-size:var(--font-size-smaller);text-decoration:none}.page-footer{margin-bottom:30px;margin-top:30px;padding-left:0;padding-right:0}.page-footer a{font-size:var(--font-size-larger);opacity:.5;text-decoration:none;transition:opacity .5s cubic-bezier(0.19, 1, 0.22, 1),background-color .2s cubic-bezier(0.19, 1, 0.22, 1)}.page-footer a:hover,.page-footer a:focus{opacity:1}.page-header li,.page-footer li{list-style:none}body .page-header ul,body .page-footer ul{margin-left:0}.entry-content pre,.entry-content code{border-radius:6px}.entry-content pre code{font-size:var(--font-size-smaller)}.entry-content pre{line-height:1.33;padding:15px}.feed-entries-counter{font-size:var(--font-size-smaller);margin-left:5px;opacity:.5;position:relative;top:12px}input[type=search],input[type=url],input[type=password],input[type=text],input[type=number],select,textarea{background-color:var(--input-background);border:0;border-radius:0;color:var(--input-color);padding:10px}.button-primary{border:0;border-radius:0;padding:10px 20px}article.feed-parsing-error{border-color:rgba(0,0,0,0)}.parsing-error{margin-top:10px}.item.current-item{border:1px dotted var(--item-border-color);box-shadow:none;display:grid;margin-bottom:20px;margin-top:30px;outline-offset:20px;overflow:visible;padding-bottom:var(--item-padding);padding-left:0;padding-right:0;padding-top:var(--item-padding)}.item.current-item *:focus{outline:none}.header a{align-items:center;display:inline-flex;gap:.2rem}.header .logo a{display:inline-block}.unread-counter-wrapper,.error-feeds-counter-wrapper{visibility:hidden}.unread-counter,.error-feeds-counter{visibility:visible}.header a .unread-counter,.header a .error-feeds-counter{align-items:center;border-radius:50%;color:#fff !important;display:inline-flex;font-size:11px;font-weight:700;height:22px;justify-content:center;line-height:1.5;width:22px}.header a .error-feeds-counter{background-color:#d96d6d}.header a .unread-counter{background-color:var(--color-green)}/*# sourceMappingURL=style.css.map */ \ No newline at end of file diff --git a/swag/proxy-confs/miniflux.subdomain.conf b/swag/proxy-confs/miniflux.subdomain.conf new file mode 100644 index 0000000..ba2a00b --- /dev/null +++ b/swag/proxy-confs/miniflux.subdomain.conf @@ -0,0 +1,39 @@ +## Version 2022/09/08 +# make sure that your dns has a cname set for miniflux + +server { + listen 443 ssl; + listen [::]:443 ssl; + + server_name rss.*; + + include /config/nginx/ssl.conf; + + client_max_body_size 0; + + # enable for ldap auth (requires ldap-location.conf in the location block) + #include /config/nginx/ldap-server.conf; + + # enable for Authelia (requires authelia-location.conf in the location block) + #include /config/nginx/authelia-server.conf; + + location / { + # enable the next two lines for http auth + #auth_basic "Restricted"; + #auth_basic_user_file /config/nginx/.htpasswd; + + # enable for ldap auth (requires ldap-server.conf in the server block) + #include /config/nginx/ldap-location.conf; + + # enable for Authelia (requires authelia-server.conf in the server block) + #include /config/nginx/authelia-location.conf; + + include /config/nginx/proxy.conf; + include /config/nginx/resolver.conf; + set $upstream_app miniflux; + set $upstream_port 8080; + set $upstream_proto http; + proxy_pass $upstream_proto://$upstream_app:$upstream_port; + + } +} \ No newline at end of file diff --git a/swag/ssl.conf b/swag/ssl.conf new file mode 100644 index 0000000..760d269 --- /dev/null +++ b/swag/ssl.conf @@ -0,0 +1,41 @@ + Version 2022/08/20 - Changelog: https://github.com/linuxserver/docker-baseimage-alpine-nginx/commits/master/root/defaults/nginx/ssl.conf.sample + +### Mozilla Recommendations +# generated 2022-08-05, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration +# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6 + +ssl_certificate /config/keys/cert.crt; +ssl_certificate_key /config/keys/cert.key; +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; # about 40000 sessions +ssl_session_tickets off; + +# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam +ssl_dhparam /config/nginx/dhparams.pem; + +# intermediate configuration +ssl_protocols TLSv1.2 TLSv1.3; +ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256; +ssl_prefer_server_ciphers on; + +# HSTS (ngx_http_headers_module is required) (63072000 seconds) +#add_header Strict-Transport-Security "max-age=63072000" always; + +# OCSP stapling +ssl_stapling on; +ssl_stapling_verify on; + +# verify chain of trust of OCSP response using Root CA and Intermediate certs +ssl_trusted_certificate /config/keys/cert.crt; + +# Optional additional headers +add_header Content-Security-Policy "default-src 'none'; frame-src *; img-src *; manifest-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; frame-ancestors 'self'; block-all-mixed-content; base-uri 'none'"; +add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), clipboard-read=(), display-capture=(), document-domain=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), interest-cohort=(), magnetometer=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), usb=(), sync-xhr=(), xr-spatial-tracking=()"; +add_header Referrer-Policy "same-origin" always; +add_header X-Content-Type-Options "nosniff" always; +#add_header X-UA-Compatible "IE=Edge" always; +add_header X-XSS-Protection "0" always; +add_header Cross-Origin-Resource-Policy cross-origin; +#add_header Cross-Origin-Embedder-Policy require-corp; +add_header Cross-Origin-Opener-Policy same-origin; +add_header Expect-CT "enforce, max-age=63072000"; \ No newline at end of file