From 384e3dce5ff75d7a92455f9bd1a5f4e07a20ae67 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Mon, 5 Dec 2022 22:39:45 -0800 Subject: code-host: migrate to simplevisor --- code-host/Dockerfile | 30 ++- code-host/Makefile | 12 +- code-host/code.crute.me | 100 ---------- code-host/code.ini | 12 ++ code-host/etc/service/nginx/log/run | 3 - code-host/etc/service/nginx/run | 23 --- code-host/etc/service/ssh/log/run | 3 - code-host/etc/service/ssh/run | 25 --- code-host/etc/service/uwsgi/log/run | 3 - code-host/etc/service/uwsgi/run | 23 --- code-host/etc/ssh/sshd_config | 65 ------ code-host/etc/uwsgi/code.ini | 12 -- code-host/nginx.conf | 386 ++++++++++++++++++++++++++++++++++++ code-host/simplevisor.json | 34 ++++ code-host/ssh-setup.sh | 22 ++ code-host/sshd_config | 65 ++++++ 16 files changed, 538 insertions(+), 280 deletions(-) delete mode 100644 code-host/code.crute.me create mode 100644 code-host/code.ini delete mode 100755 code-host/etc/service/nginx/log/run delete mode 100755 code-host/etc/service/nginx/run delete mode 100755 code-host/etc/service/ssh/log/run delete mode 100755 code-host/etc/service/ssh/run delete mode 100755 code-host/etc/service/uwsgi/log/run delete mode 100755 code-host/etc/service/uwsgi/run delete mode 100644 code-host/etc/ssh/sshd_config delete mode 100644 code-host/etc/uwsgi/code.ini create mode 100644 code-host/nginx.conf create mode 100644 code-host/simplevisor.json create mode 100755 code-host/ssh-setup.sh create mode 100644 code-host/sshd_config diff --git a/code-host/Dockerfile b/code-host/Dockerfile index d7392fe..b867c36 100644 --- a/code-host/Dockerfile +++ b/code-host/Dockerfile @@ -1,37 +1,33 @@ FROM alpine:edge LABEL maintainer="Mike Crute " -# locale-gen en_US.UTF-8 && \ - RUN set -euxo pipefail; \ apk --no-cache add \ bash \ cgit \ - dumb-init \ gitolite \ nginx \ openssh \ perl-json \ py3-pygments \ py3-docutils \ - runit \ - su-exec \ uwsgi \ uwsgi-cgi \ uwsgi-router_static \ + libcap \ ; \ - rm -rf /etc/nginx; \ - mkdir -p /srv/nginx-conf /logs; \ - ln -s /usr/bin/rst2html /usr/bin/rst2html.py; \ + mkdir -p /logs; \ + rm /etc/nginx/nginx.conf; \ + ln -sf /usr/bin/rst2html /usr/bin/rst2html.py; \ addgroup -g 1005 -S code; \ - adduser -u 1005 -s /bin/sh -S -h /srv/code -H -D -G code code; - -ADD etc/ /etc/ -ADD code.crute.me /srv/nginx-conf/ -ADD nginx_bootstrap / + adduser -u 1005 -s /bin/sh -S -h /srv/code -H -D -G code code; \ + setcap cap_net_bind_service=+ep /usr/sbin/sshd; -ENV ACTIVE_PROFILE INTERNAL -ENV NGINX_PP_DISABLE_SSL_DEFAULT true +ADD nginx.conf /etc/nginx/nginx.conf +ADD /simplevisor /simplevisor +ADD /simplevisor.json /simplevisor.json +ADD /ssh-setup.sh /ssh-setup.sh +ADD /code.ini /etc/uwsgi/code.ini +ADD /sshd_config /etc/ssh/sshd_config -STOPSIGNAL SIGHUP -CMD [ "/usr/bin/dumb-init", "/sbin/runsvdir", "/etc/service" ] +CMD [ "/simplevisor", "--no-vault" ] diff --git a/code-host/Makefile b/code-host/Makefile index 652bf8a..070ca73 100644 --- a/code-host/Makefile +++ b/code-host/Makefile @@ -1,13 +1,11 @@ -IMAGE=docker.crute.me/code-host:latest +VERSION=1.2.3-r3 +VERSION_TAG=$(VERSION) +IMAGE=docker.crute.me/code-host:$(VERSION_TAG) +LATEST=$(subst :$(VERSION_TAG),,$(IMAGE)):latest all: - @echo "Must update for new nginx minder"; exit 1 - cp ../nginx-common/main.go . - CGO_ENABLED=0 go build -o nginx_bootstrap main.go - rm -rf ./etc/nginx/ && cp -r ../nginx-common/conf ./etc/nginx/ docker pull alpine:edge docker build -t $(IMAGE) . - rm -rf ./etc/nginx/ main.go nginx_bootstrap all-no-cache: docker build --no-cache -t $(IMAGE) . @@ -21,3 +19,5 @@ run: publish: docker push $(IMAGE) + docker tag $(IMAGE) $(LATEST) + docker push $(LATEST) diff --git a/code-host/code.crute.me b/code-host/code.crute.me deleted file mode 100644 index 1937391..0000000 --- a/code-host/code.crute.me +++ /dev/null @@ -1,100 +0,0 @@ -# vi:ft=nginx -# preprocess: link_for INTERNAL - -# TODO: Consolidate these into one, they differ only by hostname and SSL cert -# This is like this because I'm not sure if redirects will work at all with -# git pulls and pretty much all repositories use code.crute.me not .us - -include includes/internal_ip_cgit_acl.conf; - -server { - listen *:443 ssl http2; - listen [::]:443 ssl http2; - - server_name code.crute.me; - access_log /logs/code.crute.me.log combined_host; - - include includes/hardened_ssl.conf; - include includes/hardened_headers.conf; - - ssl_certificate /srv/nginx-conf/ssl/letsencrypt_crute_me.pem; - ssl_certificate_key /srv/nginx-conf/ssl/letsencrypt_crute_me_key.pem; - - add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src https://wiki.crute.me/ 'self';" always; - - client_max_body_size 4G; - - # This is somewhat ugly and naive because it doesn't allow more than host/user/repo and some - # repos exist at deeper paths than that. This should be fixed and moved out of nginx at some - # point it's just quick and easy to put it here. - location ~ ^/(?[^/]*)/(?[^/]+)/?(?.*)?$ { - if ($arg_go-get = "1") { - add_header Content-Type text/plain; - return 200 ' - - -'; - } - - include uwsgi_params; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG $cgit_config; - uwsgi_pass uwsgi://127.0.0.1:9000; - } - - location / { - include uwsgi_params; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG $cgit_config; - uwsgi_pass uwsgi://127.0.0.1:9000; - } -} - -server { - listen *:443 ssl http2; - listen [::]:443 ssl http2; - - server_name code.crute.us; - access_log /logs/code.crute.me.log combined_host; - - include includes/hardened_ssl.conf; - include includes/hardened_headers.conf; - - ssl_certificate /srv/nginx-conf/ssl/letsencrypt_crute_us.pem; - ssl_certificate_key /srv/nginx-conf/ssl/letsencrypt_crute_us_key.pem; - - add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src https://wiki.crute.me/ 'self';" always; - - client_max_body_size 4G; - - # This is somewhat ugly and naive because it doesn't allow more than host/user/repo and some - # repos exist at deeper paths than that. This should be fixed and moved out of nginx at some - # point it's just quick and easy to put it here. - location ~ ^/(?[^/]*)/(?[^/]+)/?(?.*)?$ { - if ($arg_go-get = "1") { - add_header Content-Type text/plain; - return 200 ' - - -'; - } - - include uwsgi_params; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG $cgit_config; - uwsgi_pass uwsgi://127.0.0.1:9000; - } - - location / { - include uwsgi_params; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG $cgit_config; - uwsgi_pass uwsgi://127.0.0.1:9000; - } -} diff --git a/code-host/code.ini b/code-host/code.ini new file mode 100644 index 0000000..686fef8 --- /dev/null +++ b/code-host/code.ini @@ -0,0 +1,12 @@ +[uwsgi] +master = true +plugins = cgi, router_static +socket = [::]:9000 +uid = code +gid = code +workers = 2 +harakiri = 300 +offload-threads = 4 +cgi = /usr/share/webapps/cgit/cgit.cgi +route = /(cgit.css|cgit.png|favicon.ico|robots.txt) static:/usr/share/webapps/cgit/$1 +mime-file = /etc/mime.types diff --git a/code-host/etc/service/nginx/log/run b/code-host/etc/service/nginx/log/run deleted file mode 100755 index 6193824..0000000 --- a/code-host/etc/service/nginx/log/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -cat - diff --git a/code-host/etc/service/nginx/run b/code-host/etc/service/nginx/run deleted file mode 100755 index 79dcaf1..0000000 --- a/code-host/etc/service/nginx/run +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# runsv sends us a TERM but uwsgi will only shutdown cleanly -# if it receives an INT so we need to translate the signal -# properly for uwsgi -trap 'kill -INT $PID' TERM - -/nginx_bootstrap /usr/sbin/nginx -g "daemon off;" & - -PID=$! - -# wait for uwsgi, will get cancelled when runsv TERMs us and -# the trap will get executed next, unless something goes wrong -# and uwsgi fails then this wait will run -wait $PID - -# if something went wrong then unregister the trap because it -# won't have a target -trap - TERM - -# waiting on a dead process will return the return code of the -# processes original exit -wait $PID diff --git a/code-host/etc/service/ssh/log/run b/code-host/etc/service/ssh/log/run deleted file mode 100755 index 6193824..0000000 --- a/code-host/etc/service/ssh/log/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -cat - diff --git a/code-host/etc/service/ssh/run b/code-host/etc/service/ssh/run deleted file mode 100755 index 2677956..0000000 --- a/code-host/etc/service/ssh/run +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# Make host keys directory and generate keys if they don't exist at server -# startup time. -HOST_KEY_DIR="/srv/code/hostkeys" -if [ ! -d "$HOST_KEY_DIR" ]; then - mkdir "$HOST_KEY_DIR" - chmod 755 "$HOST_KEY_DIR" - chown code:code "$HOST_KEY_DIR" -fi - -RSA_KEY_FILE="/srv/code/hostkeys/rsa_key" -if [ ! -f "$RSA_KEY_FILE" ]; then - ssh-keygen -f "$RSA_KEY_FILE" -N '' -t rsa - chown code:code "$RSA_KEY_FILE" -fi - -ED25519_KEY_FILE="/srv/code/hostkeys/ed25519_key" -if [ ! -f "$ED25519_KEY_FILE" ]; then - ssh-keygen -f "$ED25519_KEY_FILE" -N '' -t ed25519 - chown code:code "$ED25519_KEY_FILE" -fi - -setcap cap_net_bind_service=+ep /usr/sbin/sshd -/sbin/su-exec code /usr/sbin/sshd -D -e diff --git a/code-host/etc/service/uwsgi/log/run b/code-host/etc/service/uwsgi/log/run deleted file mode 100755 index 6193824..0000000 --- a/code-host/etc/service/uwsgi/log/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -cat - diff --git a/code-host/etc/service/uwsgi/run b/code-host/etc/service/uwsgi/run deleted file mode 100755 index 30bfc38..0000000 --- a/code-host/etc/service/uwsgi/run +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# runsv sends us a TERM but uwsgi will only shutdown cleanly -# if it receives an INT so we need to translate the signal -# properly for uwsgi -trap 'kill -INT $PID' TERM - -/usr/sbin/uwsgi --ini /etc/uwsgi/code.ini & - -PID=$! - -# wait for uwsgi, will get cancelled when runsv TERMs us and -# the trap will get executed next, unless something goes wrong -# and uwsgi fails then this wait will run -wait $PID - -# if something went wrong then unregister the trap because it -# won't have a target -trap - TERM - -# waiting on a dead process will return the return code of the -# processes original exit -wait $PID diff --git a/code-host/etc/ssh/sshd_config b/code-host/etc/ssh/sshd_config deleted file mode 100644 index 9078d2e..0000000 --- a/code-host/etc/ssh/sshd_config +++ /dev/null @@ -1,65 +0,0 @@ -# vim:set ft=sshdconfig - -HostKey /srv/code/hostkeys/rsa_key -HostKey /srv/code/hostkeys/ed25519_key - -Protocol 2 - -Port 22 - -SyslogFacility AUTH -LogLevel INFO -StrictModes yes -PidFile none - -PubkeyAuthentication yes -HostbasedAuthentication no -IgnoreRhosts yes -PasswordAuthentication no -PermitEmptyPasswords no - -PermitRootLogin no -ChallengeResponseAuthentication no - -# Limit the number of authentication attemps per connection. SSH will log -# failues once attempts reach half this number so this should also log all -# authentication failures as well. -PermitTTY no -MaxAuthTries 2 - -# This turns off reverse lookups of the originating host which hang sshd -# on DNS timeouts when DNS is down. This also breaks "from=" lines in -# authorizd_keys files which must be converted to dotted quad ip addrs. -UseDNS no - -AcceptEnv LANG LC_* - -# Disconnect after this period of time if the user hasn't provided -# a correct password. -LoginGraceTime 120 - -# After 66 seconds of inactivity, request a keep-alive from the -# client. If they don't respond after ten requests, kill the -# connection. -ClientAliveInterval 66 -ClientAliveCountMax 10 - -# Allow up to 100 simultaneous unauthenticated connections. Any -# connections beyond that limit will be dropped. -MaxStartups 100 - -# The maxiumum number of sessions which can be served on one -# multi-plexing connection. ssh does not fail gracefully when this -# number is exceeded, so we keep it high. -MaxSessions 100 - -X11Forwarding no -PrintMotd no - -# Used hardened crypto algorithms -# Based on: https://stribika.github.io/2015/01/04/secure-secure-shell.html -# And also: https://access.redhat.com/discussions/3121481 -# And also: https://infosec.mozilla.org/guidelines/openssh -KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 -Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr -MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com diff --git a/code-host/etc/uwsgi/code.ini b/code-host/etc/uwsgi/code.ini deleted file mode 100644 index 686fef8..0000000 --- a/code-host/etc/uwsgi/code.ini +++ /dev/null @@ -1,12 +0,0 @@ -[uwsgi] -master = true -plugins = cgi, router_static -socket = [::]:9000 -uid = code -gid = code -workers = 2 -harakiri = 300 -offload-threads = 4 -cgi = /usr/share/webapps/cgit/cgit.cgi -route = /(cgit.css|cgit.png|favicon.ico|robots.txt) static:/usr/share/webapps/cgit/$1 -mime-file = /etc/mime.types diff --git a/code-host/nginx.conf b/code-host/nginx.conf new file mode 100644 index 0000000..9d61863 --- /dev/null +++ b/code-host/nginx.conf @@ -0,0 +1,386 @@ +daemon off; +user nginx; +worker_processes 1; + +error_log /dev/stdout warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + 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/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/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; + } + + default_type application/octet-stream; + + log_format combined_host '$host $remote_addr - $remote_user [$time_local] ' + '"$request" $status $body_bytes_sent ' + '"$http_referer" "$http_user_agent"'; + + access_log /logs/default_server.log combined_host; + + sendfile on; + tcp_nopush on; + server_tokens off; + + keepalive_timeout 128; + + # Try to avoid buffering requests to disk + client_body_buffer_size 1024k; + + gzip on; + gzip_proxied any; + gzip_disable "msie6"; + gzip_types application/javascript application/rss+xml application/x-javascript application/xhtml+xml application/xml image/svg+xml image/x-icon text/css text/javascript text/plain text/xml; + + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_dhparam /srv/nginx-conf/ssl/dhparam.pem; + + map $http_host $can_redirect { + hostnames; + + default 0; + crute.me 1; + *.crute.me 1; + crute.us 1; + *.crute.us 1; + } + + server { + listen *:80 default_server; + listen [::]:80 default_server; + + access_log /logs/default_http_vhost.log combined_host; + + location / { + if ($can_redirect) { + rewrite (.*) https://$http_host$1 permanent; + } + + default_type text/plain; + return 404 "not found"; + } + } + + # TODO: Consolidate these into one, they differ only by hostname and SSL cert + # This is like this because I'm not sure if redirects will work at all with + # git pulls and pretty much all repositories use code.crute.me not .us + + geo $cgit_config { + default "/srv/code/etc/cgit-public.cfg"; + + # Global V4 Internal Network + 172.16.0.0/16 "/srv/code/etc/cgit-private.cfg"; + # FKL1 V4 Internal network + 172.18.0.0/16 "/srv/code/etc/cgit-private.cfg"; + # SEA4 V4 Internal network + 172.19.0.0/16 "/srv/code/etc/cgit-private.cfg"; + # ORD1 V4 Internal network + 172.20.0.0/16 "/srv/code/etc/cgit-private.cfg"; + # Mobile V4 Internal network + 172.21.0.0/16 "/srv/code/etc/cgit-private.cfg"; + # PDX1 V6 Network + 2600:1f14:f39:e000::/56 "/srv/code/etc/cgit-private.cfg"; + # CMH1 V6 Network + 2600:1f16:33:500::/56 "/srv/code/etc/cgit-private.cfg"; + # SEA1 Internal V6 Network + 2602:0803:4070::/48 "/srv/code/etc/cgit-private.cfg"; + # SEA4 Internal V6 Network + 2602:0803:4072::/48 "/srv/code/etc/cgit-private.cfg"; + # SEA4 Remote Access VPN V6 Network + 2602:0803:4075::/48 "/srv/code/etc/cgit-private.cfg"; + # ORD1 Internal V6 Network + 2602:0803:4073::/48 "/srv/code/etc/cgit-private.cfg"; + # FKL1 Internal V6 Network + 2602:0803:4074::/48 "/srv/code/etc/cgit-private.cfg"; + # Mobile V6 Internal Network + 2602:0803:4076::/48 "/srv/code/etc/cgit-private.cfg"; + } + + server { + listen *:443 ssl http2; + listen [::]:443 ssl http2; + + server_name code.crute.me; + access_log /logs/code.crute.me.log combined_host; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:AES256+EECDH:AES256+EDH:!DHE-RSA-AES256-SHA256:!DHE-RSA-AES256-SHA:!aNULL"; + ssl_stapling on; + ssl_stapling_verify on; + resolver 8.8.4.4 8.8.8.8 valid=300s; + resolver_timeout 5s; + + add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Xss-Protection "1; mode=block" always; + add_header Referrer-Policy "same-origin" always; + + ssl_certificate /srv/nginx-conf/ssl/letsencrypt_crute_me.pem; + ssl_certificate_key /srv/nginx-conf/ssl/letsencrypt_crute_me_key.pem; + + add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src https://wiki.crute.me/ 'self';" always; + + client_max_body_size 4G; + + # This is somewhat ugly and naive because it doesn't allow more than host/user/repo and some + # repos exist at deeper paths than that. This should be fixed and moved out of nginx at some + # point it's just quick and easy to put it here. + location ~ ^/(?[^/]*)/(?[^/]+)/?(?.*)?$ { + if ($arg_go-get = "1") { + add_header Content-Type text/plain; + return 200 ' + + + '; + } + + uwsgi_param QUERY_STRING $query_string; + uwsgi_param REQUEST_METHOD $request_method; + uwsgi_param CONTENT_TYPE $content_type; + uwsgi_param CONTENT_LENGTH $content_length; + + uwsgi_param REQUEST_URI $request_uri; + uwsgi_param PATH_INFO $document_uri; + uwsgi_param DOCUMENT_ROOT $document_root; + uwsgi_param SERVER_PROTOCOL $server_protocol; + uwsgi_param REQUEST_SCHEME $scheme; + uwsgi_param HTTPS $https if_not_empty; + + uwsgi_param REMOTE_ADDR $remote_addr; + uwsgi_param REMOTE_PORT $remote_port; + uwsgi_param SERVER_PORT $server_port; + uwsgi_param SERVER_NAME $server_name; + + uwsgi_param HTTP_HOST $host; + uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for; + + uwsgi_modifier1 9; + uwsgi_param CGIT_CONFIG $cgit_config; + uwsgi_pass uwsgi://127.0.0.1:9000; + } + + location / { + uwsgi_param QUERY_STRING $query_string; + uwsgi_param REQUEST_METHOD $request_method; + uwsgi_param CONTENT_TYPE $content_type; + uwsgi_param CONTENT_LENGTH $content_length; + + uwsgi_param REQUEST_URI $request_uri; + uwsgi_param PATH_INFO $document_uri; + uwsgi_param DOCUMENT_ROOT $document_root; + uwsgi_param SERVER_PROTOCOL $server_protocol; + uwsgi_param REQUEST_SCHEME $scheme; + uwsgi_param HTTPS $https if_not_empty; + + uwsgi_param REMOTE_ADDR $remote_addr; + uwsgi_param REMOTE_PORT $remote_port; + uwsgi_param SERVER_PORT $server_port; + uwsgi_param SERVER_NAME $server_name; + + uwsgi_param HTTP_HOST $host; + uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for; + + uwsgi_modifier1 9; + uwsgi_param CGIT_CONFIG $cgit_config; + uwsgi_pass uwsgi://127.0.0.1:9000; + } + } + + server { + listen *:443 ssl http2; + listen [::]:443 ssl http2; + + server_name code.crute.us; + access_log /logs/code.crute.me.log combined_host; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:AES256+EECDH:AES256+EDH:!DHE-RSA-AES256-SHA256:!DHE-RSA-AES256-SHA:!aNULL"; + ssl_stapling on; + ssl_stapling_verify on; + resolver 8.8.4.4 8.8.8.8 valid=300s; + resolver_timeout 5s; + + add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Xss-Protection "1; mode=block" always; + add_header Referrer-Policy "same-origin" always; + + ssl_certificate /srv/nginx-conf/ssl/letsencrypt_crute_us.pem; + ssl_certificate_key /srv/nginx-conf/ssl/letsencrypt_crute_us_key.pem; + + add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src https://wiki.crute.me/ 'self';" always; + + client_max_body_size 4G; + + # This is somewhat ugly and naive because it doesn't allow more than host/user/repo and some + # repos exist at deeper paths than that. This should be fixed and moved out of nginx at some + # point it's just quick and easy to put it here. + location ~ ^/(?[^/]*)/(?[^/]+)/?(?.*)?$ { + if ($arg_go-get = "1") { + add_header Content-Type text/plain; + return 200 ' + + + '; + } + + uwsgi_param QUERY_STRING $query_string; + uwsgi_param REQUEST_METHOD $request_method; + uwsgi_param CONTENT_TYPE $content_type; + uwsgi_param CONTENT_LENGTH $content_length; + + uwsgi_param REQUEST_URI $request_uri; + uwsgi_param PATH_INFO $document_uri; + uwsgi_param DOCUMENT_ROOT $document_root; + uwsgi_param SERVER_PROTOCOL $server_protocol; + uwsgi_param REQUEST_SCHEME $scheme; + uwsgi_param HTTPS $https if_not_empty; + + uwsgi_param REMOTE_ADDR $remote_addr; + uwsgi_param REMOTE_PORT $remote_port; + uwsgi_param SERVER_PORT $server_port; + uwsgi_param SERVER_NAME $server_name; + + uwsgi_param HTTP_HOST $host; + uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for; + + uwsgi_modifier1 9; + uwsgi_param CGIT_CONFIG $cgit_config; + uwsgi_pass uwsgi://127.0.0.1:9000; + } + + location / { + uwsgi_param QUERY_STRING $query_string; + uwsgi_param REQUEST_METHOD $request_method; + uwsgi_param CONTENT_TYPE $content_type; + uwsgi_param CONTENT_LENGTH $content_length; + + uwsgi_param REQUEST_URI $request_uri; + uwsgi_param PATH_INFO $document_uri; + uwsgi_param DOCUMENT_ROOT $document_root; + uwsgi_param SERVER_PROTOCOL $server_protocol; + uwsgi_param REQUEST_SCHEME $scheme; + uwsgi_param HTTPS $https if_not_empty; + + uwsgi_param REMOTE_ADDR $remote_addr; + uwsgi_param REMOTE_PORT $remote_port; + uwsgi_param SERVER_PORT $server_port; + uwsgi_param SERVER_NAME $server_name; + + uwsgi_param HTTP_HOST $host; + uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for; + + uwsgi_modifier1 9; + uwsgi_param CGIT_CONFIG $cgit_config; + uwsgi_pass uwsgi://127.0.0.1:9000; + } + } +} diff --git a/code-host/simplevisor.json b/code-host/simplevisor.json new file mode 100644 index 0000000..4a252b3 --- /dev/null +++ b/code-host/simplevisor.json @@ -0,0 +1,34 @@ +{ + "env": { + "pass": [ + "PATH", + "HOSTNAME", + "SHLVL", + "HOME", + "PWD" + ] + }, + "jobs": { + "init": [ + { + "cmd": ["/ssh-setup.sh"], + "run-as": "root" + } + ], + "main": [ + { + "cmd": ["/usr/sbin/nginx"], + "run-as": "root" + }, + { + "cmd": ["/usr/sbin/sshd", "-D", "-e"], + "run-as": "code" + }, + { + "cmd": ["/usr/sbin/uwsgi", "--ini", "/etc/uwsgi/code.ini"], + "kill-signal": "INT", + "run-as": "root" + } + ] + } +} diff --git a/code-host/ssh-setup.sh b/code-host/ssh-setup.sh new file mode 100755 index 0000000..a896fb0 --- /dev/null +++ b/code-host/ssh-setup.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Make host keys directory and generate keys if they don't exist at server +# startup time. +HOST_KEY_DIR="/srv/code/hostkeys" +if [ ! -d "$HOST_KEY_DIR" ]; then + mkdir "$HOST_KEY_DIR" + chmod 755 "$HOST_KEY_DIR" + chown code:code "$HOST_KEY_DIR" +fi + +RSA_KEY_FILE="/srv/code/hostkeys/rsa_key" +if [ ! -f "$RSA_KEY_FILE" ]; then + ssh-keygen -f "$RSA_KEY_FILE" -N '' -t rsa + chown code:code "$RSA_KEY_FILE" +fi + +ED25519_KEY_FILE="/srv/code/hostkeys/ed25519_key" +if [ ! -f "$ED25519_KEY_FILE" ]; then + ssh-keygen -f "$ED25519_KEY_FILE" -N '' -t ed25519 + chown code:code "$ED25519_KEY_FILE" +fi diff --git a/code-host/sshd_config b/code-host/sshd_config new file mode 100644 index 0000000..9078d2e --- /dev/null +++ b/code-host/sshd_config @@ -0,0 +1,65 @@ +# vim:set ft=sshdconfig + +HostKey /srv/code/hostkeys/rsa_key +HostKey /srv/code/hostkeys/ed25519_key + +Protocol 2 + +Port 22 + +SyslogFacility AUTH +LogLevel INFO +StrictModes yes +PidFile none + +PubkeyAuthentication yes +HostbasedAuthentication no +IgnoreRhosts yes +PasswordAuthentication no +PermitEmptyPasswords no + +PermitRootLogin no +ChallengeResponseAuthentication no + +# Limit the number of authentication attemps per connection. SSH will log +# failues once attempts reach half this number so this should also log all +# authentication failures as well. +PermitTTY no +MaxAuthTries 2 + +# This turns off reverse lookups of the originating host which hang sshd +# on DNS timeouts when DNS is down. This also breaks "from=" lines in +# authorizd_keys files which must be converted to dotted quad ip addrs. +UseDNS no + +AcceptEnv LANG LC_* + +# Disconnect after this period of time if the user hasn't provided +# a correct password. +LoginGraceTime 120 + +# After 66 seconds of inactivity, request a keep-alive from the +# client. If they don't respond after ten requests, kill the +# connection. +ClientAliveInterval 66 +ClientAliveCountMax 10 + +# Allow up to 100 simultaneous unauthenticated connections. Any +# connections beyond that limit will be dropped. +MaxStartups 100 + +# The maxiumum number of sessions which can be served on one +# multi-plexing connection. ssh does not fail gracefully when this +# number is exceeded, so we keep it high. +MaxSessions 100 + +X11Forwarding no +PrintMotd no + +# Used hardened crypto algorithms +# Based on: https://stribika.github.io/2015/01/04/secure-secure-shell.html +# And also: https://access.redhat.com/discussions/3121481 +# And also: https://infosec.mozilla.org/guidelines/openssh +KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 +Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr +MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com -- cgit v1.2.3