diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..5ec34bf0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +#### Copy stage #### +FROM mensbeam/baseimage_alpine:latest as copy-stage + +RUN mkdir -p /copy/app/arsse +COPY dist/docker /copy +COPY arsse.php /copy/app/arsse/ +COPY composer.json /copy/app/arsse/ +COPY composer.lock /copy/app/arsse/ +COPY www /copy/app/arsse/www +COPY lib /copy/app/arsse/lib + +#### Runtime stage #### +FROM mensbeam/baseimage_alpine:latest + +RUN apk add --no-cache \ + composer \ + gnu-libiconv \ + libxml2 \ + nginx \ + php-fpm \ + php83-dom \ + php83-intl \ + php83-mysqli \ + php83-pcntl \ + php83-pdo_mysql \ + php83-pdo_pgsql \ + php83-pdo_sqlite \ + php83-pgsql \ + php83-posix \ + php83-sqlite3 + +COPY --from=copy-stage /copy/ / + +EXPOSE 80 443 +VOLUME /config \ No newline at end of file diff --git a/dist/docker/default/arsse/config.php b/dist/docker/default/arsse/config.php new file mode 100644 index 00000000..4c6addf8 --- /dev/null +++ b/dist/docker/default/arsse/config.php @@ -0,0 +1,6 @@ + "en", + 'dbDriver' => "sqlite3", + 'dbSQLite3File' => "/config/arsse/arsse.db", + 'dbAutoUpdate' => true +]; \ No newline at end of file diff --git a/dist/docker/default/nginx/fcgi.conf b/dist/docker/default/nginx/fcgi.conf new file mode 100644 index 00000000..4e2c4d84 --- /dev/null +++ b/dist/docker/default/nginx/fcgi.conf @@ -0,0 +1,17 @@ +fastcgi_pass_header Authorization; # required if the Arsse is to perform its own HTTP authentication +# Remove X-Powered-By, which is an information leak +fastcgi_hide_header X-Powered-By; +fastcgi_pass_request_body on; +fastcgi_pass_request_headers on; +fastcgi_intercept_errors off; +fastcgi_buffering off; +fastcgi_param REQUEST_METHOD $request_method; +fastcgi_param CONTENT_TYPE $content_type; +fastcgi_param CONTENT_LENGTH $content_length; +fastcgi_param REQUEST_URI $uri; +fastcgi_param QUERY_STRING $query_string; +fastcgi_param HTTPS $https if_not_empty; +fastcgi_param REMOTE_USER $remote_user; + +fastcgi_pass unix:/var/run/php/arsse.sock; +fastcgi_param SCRIPT_FILENAME /app/arsse/arsse.php; \ No newline at end of file diff --git a/dist/docker/default/nginx/hosts.conf b/dist/docker/default/nginx/hosts.conf new file mode 100644 index 00000000..51be149d --- /dev/null +++ b/dist/docker/default/nginx/hosts.conf @@ -0,0 +1,81 @@ +server { + server_name -; + listen 80; + listen [::]:80; + + #include /config/nginx/ssl.conf; + + # Automatic HTTPS redirection + uninitialized_variable_warn off; + if ($https = "on") { + set $tls_redir off; + } + if ($tls_redir = "") { + set $tls_redir on; + } + if ($tls_redir = "on") { + rewrite ^ https://$host$request_uri; + } + + root /app/arsse/www; + + location @arsse { + # HTTP authentication may be enabled for this location, though this may impact some features + include /config/nginx/fcgi.conf; + } + + location @arsse_public { + # HTTP authentication should not be enabled for this location + include /config/nginx/fcgi.conf; + } + + # Any provided static files + location / { + try_files $uri $uri/ =404; + } + + # Nextcloud News protocol + location /index.php/apps/news/api { + try_files $uri @arsse; + + location ~ ^/index\.php/apps/news/api/?$ { + try_files $uri @arsse_public; + } + } + + # Tiny Tiny RSS protocol + location /tt-rss/api { + try_files $uri @arsse; + } + + # Tiny Tiny RSS feed icons + location /tt-rss/feed-icons/ { + try_files $uri @arsse; + } + + # Tiny Tiny RSS special-feed icons; these are static files + location /tt-rss/images/ { + try_files $uri =404; + } + + # Fever protocol + location /fever/ { + try_files $uri @arsse; + } + + # Miniflux protocol + location /v1/ { + # If put behind HTTP authentication token login will not be possible + try_files $uri @arsse; + } + + # Miniflux version number + location /version { + try_files $uri @arsse_public; + } + + # Miniflux "health check" + location /healthcheck { + try_files $uri @arsse_public; + } +} \ No newline at end of file diff --git a/dist/docker/default/nginx/mime.types b/dist/docker/default/nginx/mime.types new file mode 100644 index 00000000..8d37c863 --- /dev/null +++ b/dist/docker/default/nginx/mime.types @@ -0,0 +1,98 @@ +types { + text/html html htm shtml; + text/css css; + text/xml xml; + image/gif gif; + image/jpeg jpeg jpg; + application/javascript js; + application/atom+xml atom; + application/rss+xml rss; + + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; + + image/avif avif; + image/png png; + image/svg+xml svg svgz; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/webp webp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; + + font/woff woff; + font/woff2 woff2; + + application/java-archive jar war ear; + application/json json; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.apple.mpegurl m3u8; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/vnd.ms-excel xls; + application/vnd.ms-fontobject eot; + application/vnd.ms-powerpoint ppt; + application/vnd.oasis.opendocument.graphics odg; + application/vnd.oasis.opendocument.presentation odp; + application/vnd.oasis.opendocument.spreadsheet ods; + application/vnd.oasis.opendocument.text odt; + application/vnd.openxmlformats-officedocument.presentationml.presentation + pptx; + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + xlsx; + application/vnd.openxmlformats-officedocument.wordprocessingml.document + docx; + application/vnd.wap.wmlc wmlc; + application/wasm wasm; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/xhtml+xml xhtml; + application/xspf+xml xspf; + application/zip zip; + + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream iso img; + application/octet-stream msi msp msm; + + audio/midi mid midi kar; + audio/mpeg mp3; + audio/ogg ogg; + audio/x-m4a m4a; + audio/x-realaudio ra; + + video/3gpp 3gpp 3gp; + video/mp2t ts; + video/mp4 mp4; + video/mpeg mpeg mpg; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-m4v m4v; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; +} diff --git a/dist/docker/default/nginx/nginx.conf b/dist/docker/default/nginx/nginx.conf new file mode 100644 index 00000000..b63a43eb --- /dev/null +++ b/dist/docker/default/nginx/nginx.conf @@ -0,0 +1,152 @@ +user ook; + +# Set number of worker processes automatically based on number of CPU cores. +include /config/nginx/worker_processes.conf; + +# Enables the use of JIT for regular expressions to speed-up their processing. +pcre_jit on; + +# Configures default error logger. +error_log /config/log/nginx/error.log; +# Includes files with directives to load dynamic modules. +include /etc/nginx/modules/*.conf; +# Include files with config snippets into the root context. +include /etc/nginx/conf.d/*.conf; + +events { + # The maximum number of simultaneous connections that can be opened by + # a worker process. + worker_connections 1024; +} + +http { + # Name servers used to resolve names of upstream servers into addresses. + # It's also needed when using tcpsocket and udpsocket in Lua modules. + include /config/nginx/resolver.conf; + + # Don't tell nginx version to the clients. Default is 'on'. + server_tokens off; + # Specifies the maximum accepted body size of a client request, as + # indicated by the request header Content-Length. If the stated content + # length is greater than this size, then the client receives the HTTP + # error code 413. Set to 0 to disable. Default is '1m'. + client_max_body_size 0; + # Sendfile copies data between one FD and other from within the kernel, + # which is more efficient than read() + write(). Default is off. + sendfile on; + # Causes nginx to attempt to send its HTTP response head in one packet, + # instead of using partial frames. Default is 'off'. + tcp_nopush on; + # Sends small packets as soon as they're available, decreasing latency at + # the cost of increased network overhead. Default is 'off'. + tcp_nodelay on; + # Specifies the maximum amount of time in seconds that a keep-alive + # connection will remain open if there are no new requests. Default is 75. + keepalive_timeout 65; + # Specifies the maximum amount of time in seconds that Nginx will wait for + # the client to send the entire request header. Default is 60. + send_timeout 20s; + + # Sets the default charset. Default is 'off'. + charset utf-8; + # Defines the source charset of a response. Default is null. + source_charset utf-8; + # Enables module processing in responses with the specified MIME types. + # Default is 'text/html text/xml text/plain text/vnd.wap.wml + # application/javascript application/rss+xml'. + charset_types + application/atom+xml + application/javascript + application/json + application/rss+xml + image/svg+xml + text/css + text/plain + text/vcard + text/xml + ; + + default_type application/octet-stream; + # Sets the maximum size of the hash table used for mapping MIME types to + # file extensions. Default is 512. + types_hash_max_size 2048; + # Includes mapping of file name extensions to MIME types of responses + # and defines the default type. + include /config/nginx/mime.types; + + # Enable gzipping of responses. + gzip on; + # Sets a gzip compression level of a response. Default is 1. + gzip_comp_level 9; + # Sets the minimum length of a response that will be gzipped. Default is 20. + gzip_min_length 256; + # Enables or disables gzipping of responses for proxied requests depending + # on the request and response. Default is 'off'. + gzip_proxied any; + # Sets the Vary HTTP header as defined in the RFC 2616. Default is 'off'. + gzip_vary on; + # Enables gzipping of responses for the specified MIME types in addition to + # “text/html”. Responses with the “text/html” type are always compressed. + # Default value is 'text/html'. + gzip_types + application/atom+xml + application/javascript + application/json + application/ld+json + application/manifest+json + application/rdf+xml + application/rss+xml + application/schema+json + application/vnd.geo+json + application/vnd.ms-fontobject + application/x-font-ttf + application/x-javascript + application/x-web-app-manifest+json + application/xhtml+xml + application/xml + font/eot + font/opentype + image/bmp + image/svg+xml + image/vnd.microsoft.icon + image/x-icon + text/cache-manifest + text/css + text/javascript + text/plain + text/vcard + text/vnd.rim.location.xloc + text/vtt + text/x-component + text/x-cross-domain-policy + text/xml + ; + + # Helper variable for proxying websockets. + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + # Sets the path, format, and configuration for a buffered log write. + access_log /config/log/nginx/access.log; + + # Additional configs. + #include /config/nginx/http.d/*.conf; + + # Fallback virtual server + server { + server_name ~^.*$; + listen 80; + + location / { + return 503; + } + } + + # Includes virtual hosts configs. + include /config/nginx/hosts.conf; +} + +daemon off; +pid /run/nginx.pid; diff --git a/dist/docker/default/nginx/ssl.conf b/dist/docker/default/nginx/ssl.conf new file mode 100644 index 00000000..f5c76451 --- /dev/null +++ b/dist/docker/default/nginx/ssl.conf @@ -0,0 +1,21 @@ +listen 443 ssl; +listen [::]:443 ssl; +http2 on; + +ssl_stapling on; +ssl_stapling_verify on; +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; # about 40000 sessions +ssl_session_tickets on; + +# 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-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; +ssl_prefer_server_ciphers on; + +ssl_certificate /config/keys/fullchain.cer; +ssl_certificate_key /config/keys/cert.key; +ssl_trusted_certificate /config/keys/cert.cer; diff --git a/dist/docker/etc/php83/php-fpm.conf b/dist/docker/etc/php83/php-fpm.conf new file mode 100644 index 00000000..6a435be8 --- /dev/null +++ b/dist/docker/etc/php83/php-fpm.conf @@ -0,0 +1,15 @@ +[global] +env[PATH] = /usr/local/bin:/usr/bin:/bin + +[arsse] +user = ook +group = ook +listen = /var/run/php/arsse.sock +listen.owner = ook +listen.group = ook +pm = dynamic +pm.max_children = 5 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +clear_env = no \ No newline at end of file diff --git a/dist/docker/etc/service/init-arsse/run b/dist/docker/etc/service/init-arsse/run new file mode 100644 index 00000000..33339968 --- /dev/null +++ b/dist/docker/etc/service/init-arsse/run @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +while ! grep -qF "init-config: done"; do + sleep 1 +done + +logger -t 'init-arsse' "start" >> /var/log/run-log + +chown -R ook:ook /app + +if [ ! -d '/app/arsse/vendor' ]; then + cd /app/arsse + composer install +fi + +logger -t 'init-arsse' "done" >> /var/log/run-log \ No newline at end of file diff --git a/dist/docker/etc/service/init-config/run b/dist/docker/etc/service/init-config/run new file mode 100644 index 00000000..320bbded --- /dev/null +++ b/dist/docker/etc/service/init-config/run @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +while ! grep -qF "init-user: done"; do + sleep 1 +done + +logger -t 'init-config' "start" >> /var/log/run-log + +if [ ! -d "/config/arsse" ] || [ ! "$(ls -A "/config/arsse")" ]; then + echo -n "[init-config] Copying defaults to /config/arsse..." + cp -R /default/arsse/. /config/arsse + chown -R ook:ook /config/arsse + echo " done" +fi +if [ ! -d "/config/nginx" ] || [ ! "$(ls -A "/config/nginx")" ]; then + echo -n "[init-config] Copying defaults to /config/nginx..." + cp -R /default/nginx/. /config/nginx + chown -R ook:ook /config/nginx + echo " done" +fi + +logger -t 'init-config' "done" >> /var/log/run-log \ No newline at end of file diff --git a/dist/docker/etc/service/nginx/run b/dist/docker/etc/service/nginx/run new file mode 100644 index 00000000..f0c2520e --- /dev/null +++ b/dist/docker/etc/service/nginx/run @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +while ! grep -qF "init-arsse: done"; do + sleep 1 +done + +logger -t 'nginx' "start" >> /var/log/run-log + +nginx -c /config/nginx/nginx.conf -g 'daemon off;' + +logger -t 'nginx' "done" >> /var/log/run-log \ No newline at end of file