Skip to content

Instantly share code, notes, and snippets.

@schneefux
Last active November 4, 2018 20:43
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schneefux/22b75d2bd3e4e754ba1684f1d1e93271 to your computer and use it in GitHub Desktop.
Save schneefux/22b75d2bd3e4e754ba1684f1d1e93271 to your computer and use it in GitHub Desktop.
Nextcloud with Let's encrypt, nginx and uwsgi on NixOS
# requires https://github.com/NixOS/nixpkgs/pull/19139
# alternatively, use uwsgi-cgi or phpfpm
security.acme.preliminarySelfsigned = true;
security.acme.certs = {
${config.networking.domain} = {
webroot = "/var/www/challenges";
extraDomains = {
"cloud.${config.networking.domain}" = null;
};
email = "admin@${config.networking.domain}";
postRun = ''
systemctl reload nginx.service
'';
group = "ssl";
allowKeysForGroup = true;
};
};
users.groups.ssl = {};
users.users.nginx.extraGroups = [ "ssl" ];
# generate fresh DH params every day
systemd.services.gendhparams = {
description = "DHParam generator";
after = [ "basic.target" ];
script = ''
FILE=`mktemp`
${pkgs.openssl.bin}/bin/openssl dhparam -out $FILE 2048 && \
chmod 640 $FILE && \
mv -f $FILE ${config.security.acme.directory}/${config.networking.domain}/dhparams.pem
'';
serviceConfig.User = "root";
};
systemd.timers.gendhparams = {
enable = true;
description = "DHParam generator timer";
wantedBy = [ "timers.target" ];
partOf = [ "gendhparams.service" ];
timerConfig = {
RandomizedDelaySec = "1h";
OnCalendar = "daily";
Persistent = true;
};
};
services.mysql = {
enable = true;
package = pkgs.mysql;
};
# Nextcloud system cron
users.users.nginx.useDefaultShell = true;
systemd.services.nextcloudcron = {
description = "Nextcloud cron";
after = [ "network.target" ];
script = ''
${pkgs.php}/bin/php ${pkgs.nextcloud}/cron.php
${pkgs.nextcloud-news-updater}/bin/nextcloud-news-updater -t 2 -i 30 --mode singlerun ${pkgs.nextcloud}
'';
environment = { NEXTCLOUD_CONFIG_DIR = "/var/lib/nextcloud/config"; };
serviceConfig.User = "nginx";
};
systemd.timers.nextcloudcron = {
enable = true;
description = "Nextcloud cron timer";
wantedBy = [ "timers.target" ];
partOf = [ "Nextcloudcron.service" ];
timerConfig = {
RandomizedDelaySec = "5min";
OnCalendar = "*-*-* *:00,30:00"; # every 1/2h
Persistent = true;
};
};
# web server
services.nginx = {
enable = true;
httpConfig = ''
error_log stderr;
include ${pkgs.nginx}/conf/mime.types;
gzip on;
gzip_buffers 16 8k;
gzip_comp_level 6;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_proxied any;
gzip_vary on;
gzip_types
text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml
text/javascript application/javascript application/x-javascript
text/x-json application/json application/x-web-app-manifest+json
text/css text/plain text/x-component
font/opentype application/x-font-ttf application/vnd.ms-fontobject
image/x-icon;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header Public-Key-Pins 'pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; pin-sha256="sRHdihwgkaib1P1gxX8HFszlD+7/gTfNvuAybgLPNis="; max-age=5184000; includeSubDomains'; # Let's Encrypt HKPK
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_certificate ${config.security.acme.directory}/${config.networking.domain}/fullchain.pem;
ssl_certificate_key ${config.security.acme.directory}/${config.networking.domain}/key.pem;
ssl_trusted_certificate ${config.security.acme.directory}/${config.networking.domain}/fullchain.pem;
ssl_dhparam ${config.security.acme.directory}/${config.networking.domain}/dhparams.pem;
server {
listen 80;
listen [::]:80;
server_name cloud.${config.networking.domain};
location /.well-known/acme-challenge {
root /var/www/challenges/;
}
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name cloud.${config.networking.domain};
root ${pkgs.nextcloud};
client_max_body_size 10G;
gzip off;
rewrite ^/caldav(.*)$ /remote.php/caldav$1 redirect;
rewrite ^/carddav(.*)$ /remote.php/carddav$1 redirect;
rewrite ^/webdav(.*)$ /remote.php/webdav$1 redirect;
index index.php;
error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location ~ ^/(?:\.htaccess|config|db_structure\.xml|README){
deny all;
}
location / {
rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
rewrite ^/.well-known/carddav /remote.php/carddav/ redirect;
rewrite ^/.well-known/caldav /remote.php/caldav/ redirect;
rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;
try_files $uri $uri/ =404;
}
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
include ${pkgs.nginx}/conf/uwsgi_params;
uwsgi_modifier1 14;
uwsgi_hide_header X-Frame-Options;
uwsgi_hide_header X-XSS-Protection;
uwsgi_hide_header X-Content-Type-Options;
uwsgi_hide_header X-Robots-Tag;
uwsgi_param MOD_X_ACCEL_REDIRECT_ENABLED on;
uwsgi_pass unix:/run/uwsgi/php.sock;
}
location ~* \.(?:css|js)$ {
add_header Cache-Control "public, max-age=7200";
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
access_log off;
}
location ~* \.(?:jpg|jpeg|gif|bmp|ico|png|swf)$ {
access_log off;
}
location ^~ /data {
internal;
}
location ^~ /apps {
alias /var/lib/nextcloud/apps;
}
}
'';
};
services.uwsgi = {
enable = true;
user = "nginx";
group = "nginx";
instance = {
type = "emperor";
vassals = {
php = {
type = "normal";
socket = "/run/uwsgi/php.sock";
master = true;
vacuum = true;
processes = 16;
cheaper = 1;
php-sapi-name = "apache"; # opcode caching tweak
php-allowed-ext = [ ".php" ".inc" ];
socket-modifier1 = 14;
php-index = "index.php";
php-set = "date.timezone=Europe/Berlin";
env = [
"NEXTCLOUD_CONFIG_DIR=/var/lib/nextcloud/config"
];
plugins = [ "php" ];
};
};
};
plugins = [ "php" ];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment