feat: initial amzebs config
This commit is contained in:
74
hosts/amzebs-01/configuration.nix
Normal file
74
hosts/amzebs-01/configuration.nix
Normal file
@@ -0,0 +1,74 @@
|
||||
{ config, lib, pkgs, ... }: {
|
||||
imports = [
|
||||
./utils/bento.nix
|
||||
./utils/modules/sops.nix
|
||||
./utils/modules/nginx.nix
|
||||
|
||||
./modules/mysql.nix
|
||||
./modules/web/stack.nix
|
||||
|
||||
./utils/modules/autoupgrade.nix
|
||||
./utils/modules/promtail
|
||||
./utils/modules/borgbackup.nix
|
||||
|
||||
./hardware-configuration.nix
|
||||
|
||||
./sites
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
vim
|
||||
screen
|
||||
php82
|
||||
];
|
||||
|
||||
time.timeZone = "Europe/Vienna";
|
||||
|
||||
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||
sops.defaultSopsFile = ./secrets.yaml;
|
||||
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
options = "--delete-older-than 60d";
|
||||
};
|
||||
|
||||
boot.tmp.cleanOnBoot = true;
|
||||
zramSwap.enable = true;
|
||||
|
||||
networking.hostName = "amzebs-01";
|
||||
networking.domain = "cloonar.com";
|
||||
|
||||
services.openssh.enable = true;
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDN/2SAFm50kraB1fepAizox/QRXxB7WbqVbH+5OPalDT47VIJGNKOKhixQoqhABHxEoLxdf/C83wxlCVlPV9poLfDgVkA3Lyt5r3tSFQ6QjjOJAgchWamMsxxyGBedhKvhiEzcr/Lxytnoz3kjDG8fqQJwEpdqMmJoMUfyL2Rqp16u+FQ7d5aJtwO8EUqovhMaNO7rggjPpV/uMOg+tBxxmscliN7DLuP4EMTA/FwXVzcFNbOx3K9BdpMRAaSJt4SWcJO2cS2KHA5n/H+PQI7nz5KN3Yr/upJN5fROhi/SHvK39QOx12Pv7FCuWlc+oR68vLaoCKYhnkl3DnCfc7A7"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFshMhXwS0FQFPlITipshvNKrV8sA52ZFlnaoHd1thKg"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRQuPqH5fdX3KEw7DXzWEdO3AlUn1oSmtJtHB71ICoH Generated By Termius"
|
||||
];
|
||||
|
||||
programs.ssh = {
|
||||
knownHosts = {
|
||||
"git.cloonar.com" = {
|
||||
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDlUj7eEfS/4+z/3IhFhOTXAfpGEpNv6UWuYSL5OAhus";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# backups - adjust repo for this host
|
||||
borgbackup.repo = "u149513-sub10@u149513-sub10.your-backup.de:borg";
|
||||
|
||||
# Use HTTP-01 challenge for Let's Encrypt (not DNS)
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.defaults.email = "admin+acme@cloonar.com";
|
||||
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [ 22 80 443 ];
|
||||
|
||||
# Allow MariaDB access only from specific IP
|
||||
extraCommands = ''
|
||||
iptables -A nixos-fw -p tcp --dport 3306 -s 77.119.230.30 -j nixos-fw-accept
|
||||
'';
|
||||
};
|
||||
|
||||
system.stateVersion = "23.11";
|
||||
}
|
||||
27
hosts/amzebs-01/hardware-configuration.nix
Normal file
27
hosts/amzebs-01/hardware-configuration.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
# Hardware configuration for amzebs-01
|
||||
# This is a template - update with actual hardware configuration after installation
|
||||
{ modulesPath, ... }:
|
||||
{
|
||||
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
|
||||
|
||||
boot.loader.grub = {
|
||||
efiSupport = true;
|
||||
efiInstallAsRemovable = true;
|
||||
device = "nodev";
|
||||
configurationLimit = 2;
|
||||
};
|
||||
|
||||
# Update these with actual device UUIDs and paths after installation
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/CHANGEME";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
fileSystems."/" = {
|
||||
device = "/dev/sda1";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "xen_blkfront" ];
|
||||
boot.initrd.kernelModules = [ "nvme" ];
|
||||
}
|
||||
29
hosts/amzebs-01/modules/mysql.nix
Normal file
29
hosts/amzebs-01/modules/mysql.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{ pkgs, config, ... }:
|
||||
{
|
||||
|
||||
services.mysql = {
|
||||
enable = true;
|
||||
package = pkgs.mariadb;
|
||||
settings = {
|
||||
mysqld = {
|
||||
max_allowed_packet = "64M";
|
||||
transaction_isolation = "READ-COMMITTED";
|
||||
binlog_format = "ROW";
|
||||
# Allow remote connections
|
||||
bind-address = "0.0.0.0";
|
||||
};
|
||||
};
|
||||
|
||||
# Create read-only user for remote access on initial MySQL setup
|
||||
initialScript = pkgs.writeShellScript "mysql-init.sql" ''
|
||||
PASSWORD=$(cat ${config.sops.secrets.mysql-readonly-password.path})
|
||||
${pkgs.mariadb}/bin/mysql -u root <<EOF
|
||||
CREATE USER IF NOT EXISTS 'api_ebs_amz_at_ro'@'%' IDENTIFIED BY '$PASSWORD';
|
||||
GRANT SELECT ON api_ebs_amz_at.* TO 'api_ebs_amz_at_ro'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
|
||||
services.mysqlBackup.enable = true;
|
||||
}
|
||||
321
hosts/amzebs-01/modules/web/stack.nix
Normal file
321
hosts/amzebs-01/modules/web/stack.nix
Normal file
@@ -0,0 +1,321 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.services.webstack;
|
||||
|
||||
instanceOpts = { name, ... }:
|
||||
{
|
||||
options = {
|
||||
user = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
User of the typo3 instance. Defaults to attribute name in instances.
|
||||
'';
|
||||
example = "example.org";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Domain of the typo3 instance. Defaults to attribute name in instances.
|
||||
'';
|
||||
example = "example.org";
|
||||
};
|
||||
|
||||
domainAliases = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "www.example.org" "example.org" ];
|
||||
description = lib.mdDoc ''
|
||||
Additional domains served by this typo3 instance.
|
||||
'';
|
||||
};
|
||||
|
||||
phpPackage = mkOption {
|
||||
type = types.package;
|
||||
example = literalExpression "pkgs.php";
|
||||
description = lib.mdDoc ''
|
||||
Which PHP package to use in this typo3 instance.
|
||||
'';
|
||||
};
|
||||
|
||||
phpOptions = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
"Options appended to the PHP configuration file {file}`php.ini` used for this PHP-FPM pool."
|
||||
'';
|
||||
};
|
||||
|
||||
enableMysql = mkEnableOption (lib.mdDoc "MySQL Database");
|
||||
enableDefaultLocations = mkEnableOption (lib.mdDoc "Create default nginx location directives") // { default = true; };
|
||||
enablePhp = mkEnableOption (lib.mdDoc "PHP-FPM support") // { default = true; };
|
||||
|
||||
authorizedKeys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Authorized keys for the typo3 instance ssh user.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^/(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ /$1.$3 last;
|
||||
}
|
||||
'';
|
||||
description = lib.mdDoc ''
|
||||
These lines go to the end of the vhost verbatim.
|
||||
'';
|
||||
};
|
||||
|
||||
locations = mkOption {
|
||||
type = types.attrsOf (types.submodule (import <nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix> {
|
||||
inherit lib config;
|
||||
}));
|
||||
default = {};
|
||||
example = literalExpression ''
|
||||
{
|
||||
"/" = {
|
||||
proxyPass = "http://localhost:3000";
|
||||
};
|
||||
};
|
||||
'';
|
||||
description = lib.mdDoc "Declarative location config";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
options.services.webstack = {
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/www";
|
||||
description = lib.mdDoc ''
|
||||
The data directory for MySQL.
|
||||
|
||||
::: {.note}
|
||||
If left as the default value of `/var/www` this directory will automatically be created before the web
|
||||
server starts, otherwise you are responsible for ensuring the directory exists with appropriate ownership and permissions.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
instances = mkOption {
|
||||
type = types.attrsOf (types.submodule instanceOpts);
|
||||
default = {};
|
||||
description = lib.mdDoc "Create vhosts for typo3";
|
||||
example = literalExpression ''
|
||||
{
|
||||
"typo3.example.com" = {
|
||||
domain = "example.com";
|
||||
domainAliases = [ "www.example.com" ];
|
||||
phpPackage = pkgs.php81;
|
||||
authorizedKeys = [
|
||||
"ssh-rsa AZA=="
|
||||
];
|
||||
};
|
||||
};
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
systemd.services = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
in
|
||||
nameValuePair "phpfpm-${domain}" {
|
||||
serviceConfig = {
|
||||
ProtectHome = lib.mkForce "tmpfs";
|
||||
BindPaths = "BindPaths=/var/www/${domain}:/var/www/${domain}";
|
||||
};
|
||||
}
|
||||
) (lib.filterAttrs (name: opts: opts.enablePhp) cfg.instances);
|
||||
|
||||
services.phpfpm.pools = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair domain {
|
||||
user = user;
|
||||
settings = {
|
||||
"listen.owner" = config.services.nginx.user;
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = 32;
|
||||
"pm.max_requests" = 500;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 2;
|
||||
"pm.max_spare_servers" = 5;
|
||||
"php_admin_value[error_log]" = "syslog";
|
||||
"php_admin_value[max_execution_time]" = 240;
|
||||
"php_admin_value[max_input_vars]" = 1500;
|
||||
"access.log" = "/var/log/$pool.access.log";
|
||||
};
|
||||
phpOptions = instanceOpts.phpOptions;
|
||||
phpPackage = instanceOpts.phpPackage;
|
||||
phpEnv."PATH" = pkgs.lib.makeBinPath [ instanceOpts.phpPackage ];
|
||||
}
|
||||
) (lib.filterAttrs (name: opts: opts.enablePhp) cfg.instances);
|
||||
|
||||
};
|
||||
|
||||
|
||||
config.services.nginx.virtualHosts = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair domain {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
acmeRoot = null;
|
||||
root = cfg.dataDir + "/" + domain + "/public";
|
||||
|
||||
locations = lib.mkMerge [
|
||||
instanceOpts.locations
|
||||
(mkIf instanceOpts.enableDefaultLocations {
|
||||
"/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
# Cache.appcache, your document html and data
|
||||
"~* \\.(?:manifest|appcache|html?|xml|json)$".extraConfig = ''
|
||||
expires -1;
|
||||
# access_log logs/static.log; # I don't usually include a static log
|
||||
'';
|
||||
|
||||
"~* \\.(jpe?g|png)$".extraConfig = ''
|
||||
set $red Z;
|
||||
|
||||
if ($http_accept ~* "webp") {
|
||||
set $red A;
|
||||
}
|
||||
|
||||
if (-f $document_root/webp/$request_uri.webp) {
|
||||
set $red "''${red}B";
|
||||
}
|
||||
|
||||
if ($red = "AB") {
|
||||
add_header Vary Accept;
|
||||
rewrite ^ /webp/$request_uri.webp;
|
||||
}
|
||||
'';
|
||||
|
||||
# Cache Media: images, icons, video, audio, HTC
|
||||
"~* \\.(?:css|js|jpg|jpeg|gif|png|webp|avif|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|woff2)$".extraConfig = ''
|
||||
expires 1y;
|
||||
access_log off;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Feed
|
||||
"~* \\.(?:rss|atom)$".extraConfig = ''
|
||||
expires 1h;
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
"/".extraConfig = ''
|
||||
index index.php index.html;
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
})
|
||||
(mkIf instanceOpts.enablePhp {
|
||||
"~ [^/]\\.php(/|$)".extraConfig = ''
|
||||
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
|
||||
if (!-f $document_root$fastcgi_script_name) {
|
||||
return 404;
|
||||
}
|
||||
include ${pkgs.nginx}/conf/fastcgi_params;
|
||||
include ${pkgs.nginx}/conf/fastcgi.conf;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_buffers 8 16k;
|
||||
fastcgi_connect_timeout 240s;
|
||||
fastcgi_read_timeout 240s;
|
||||
fastcgi_send_timeout 240s;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools."${domain}".socket};
|
||||
fastcgi_index index.php;
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
extraConfig = instanceOpts.extraConfig;
|
||||
|
||||
|
||||
# locations = mapAttrs' (location: locationOpts:
|
||||
# nameValuePair location locationOpts) instanceOpts.locations;
|
||||
|
||||
}
|
||||
) cfg.instances;
|
||||
|
||||
config.users.users = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
nameValuePair user {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
home = "/var/www/" + domain;
|
||||
homeMode= "770";
|
||||
group = config.services.nginx.group;
|
||||
openssh.authorizedKeys.keys = instanceOpts.authorizedKeys;
|
||||
}
|
||||
) cfg.instances;
|
||||
config.users.groups = mapAttrs' (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in nameValuePair user {}) cfg.instances;
|
||||
|
||||
config.services.mysql.ensureUsers = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
mkIf instanceOpts.enableMysql {
|
||||
name = user;
|
||||
ensurePermissions = {
|
||||
"${user}.*" = "ALL PRIVILEGES";
|
||||
};
|
||||
}) cfg.instances;
|
||||
|
||||
config.services.mysql.ensureDatabases = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
mkIf instanceOpts.enableMysql user
|
||||
) cfg.instances;
|
||||
config.services.mysqlBackup.databases = mapAttrsToList (instance: instanceOpts:
|
||||
let
|
||||
domain = if instanceOpts.domain != null then instanceOpts.domain else instance;
|
||||
user = if instanceOpts.user != null
|
||||
then instanceOps.user
|
||||
else builtins.replaceStrings ["." "-"] ["_" "_"] domain;
|
||||
in
|
||||
mkIf instanceOpts.enableMysql user
|
||||
) cfg.instances;
|
||||
}
|
||||
18
hosts/amzebs-01/secrets.yaml
Normal file
18
hosts/amzebs-01/secrets.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
# SOPS encrypted secrets for amzebs-01
|
||||
# Edit with: nix-shell -p sops --run 'sops hosts/amzebs-01/secrets.yaml'
|
||||
#
|
||||
# Required secrets:
|
||||
# - borg-passphrase: Backup encryption passphrase
|
||||
# - borg-ssh-key: SSH private key for backup server access
|
||||
# - mysql-readonly-password: Password for read-only MySQL user (api_ebs_amz_at_ro)
|
||||
#
|
||||
# To initialize this file, first ensure the host SSH key exists, then run:
|
||||
# sops hosts/amzebs-01/secrets.yaml
|
||||
|
||||
# Placeholder structure (will be encrypted after initialization):
|
||||
borg-passphrase: CHANGEME
|
||||
borg-ssh-key: |
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
CHANGEME
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
mysql-readonly-password: CHANGEME
|
||||
37
hosts/amzebs-01/sites/api.ebs.amz.at.nix
Normal file
37
hosts/amzebs-01/sites/api.ebs.amz.at.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
{
|
||||
services.webstack.instances."api.ebs.amz.at" = {
|
||||
enableDefaultLocations = false;
|
||||
enableMysql = true;
|
||||
authorizedKeys = [
|
||||
# Add deployment SSH key here
|
||||
];
|
||||
extraConfig = ''
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
|
||||
index index.php;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
error_page 404 /index.php;
|
||||
'';
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
locations."/robots.txt".extraConfig = ''
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
'';
|
||||
|
||||
locations."/".extraConfig = ''
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
phpPackage = pkgs.php82.withExtensions ({ enabled, all }:
|
||||
enabled ++ [ all.imagick ]);
|
||||
};
|
||||
|
||||
# Use HTTP-01 challenge for Let's Encrypt
|
||||
services.nginx.virtualHosts."api.ebs.amz.at".acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
|
||||
}
|
||||
37
hosts/amzebs-01/sites/api.ebs.cloonar.dev.nix
Normal file
37
hosts/amzebs-01/sites/api.ebs.cloonar.dev.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
{
|
||||
services.webstack.instances."api.ebs.cloonar.dev" = {
|
||||
enableDefaultLocations = false;
|
||||
enableMysql = true;
|
||||
authorizedKeys = [
|
||||
# Add deployment SSH key here
|
||||
];
|
||||
extraConfig = ''
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
|
||||
index index.php;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
error_page 404 /index.php;
|
||||
'';
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
locations."/robots.txt".extraConfig = ''
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
'';
|
||||
|
||||
locations."/".extraConfig = ''
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
phpPackage = pkgs.php82.withExtensions ({ enabled, all }:
|
||||
enabled ++ [ all.imagick ]);
|
||||
};
|
||||
|
||||
# Use HTTP-01 challenge for Let's Encrypt
|
||||
services.nginx.virtualHosts."api.ebs.cloonar.dev".acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
|
||||
}
|
||||
37
hosts/amzebs-01/sites/api.stage.ebs.amz.at.nix
Normal file
37
hosts/amzebs-01/sites/api.stage.ebs.amz.at.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
{
|
||||
services.webstack.instances."api.stage.ebs.amz.at" = {
|
||||
enableDefaultLocations = false;
|
||||
enableMysql = true;
|
||||
authorizedKeys = [
|
||||
# Add deployment SSH key here
|
||||
];
|
||||
extraConfig = ''
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
|
||||
index index.php;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
error_page 404 /index.php;
|
||||
'';
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
locations."/robots.txt".extraConfig = ''
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
'';
|
||||
|
||||
locations."/".extraConfig = ''
|
||||
try_files $uri $uri/ /index.php$is_args$args;
|
||||
'';
|
||||
phpPackage = pkgs.php82.withExtensions ({ enabled, all }:
|
||||
enabled ++ [ all.imagick ]);
|
||||
};
|
||||
|
||||
# Use HTTP-01 challenge for Let's Encrypt
|
||||
services.nginx.virtualHosts."api.stage.ebs.amz.at".acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
|
||||
}
|
||||
13
hosts/amzebs-01/sites/default.nix
Normal file
13
hosts/amzebs-01/sites/default.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{ ... }: {
|
||||
imports = [
|
||||
# Enabled vhosts (cloonar.dev)
|
||||
./api.ebs.cloonar.dev.nix
|
||||
./ebs.cloonar.dev.nix
|
||||
|
||||
# Disabled vhosts (amz.at) - uncomment to enable
|
||||
# ./api.ebs.amz.at.nix
|
||||
# ./api.stage.ebs.amz.at.nix
|
||||
# ./ebs.amz.at.nix
|
||||
# ./stage.ebs.amz.at.nix
|
||||
];
|
||||
}
|
||||
49
hosts/amzebs-01/sites/ebs.amz.at.nix
Normal file
49
hosts/amzebs-01/sites/ebs.amz.at.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
domain = "ebs.amz.at";
|
||||
dataDir = "/var/www/${domain}";
|
||||
in {
|
||||
services.nginx.virtualHosts."${domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# Use HTTP-01 challenge for Let's Encrypt
|
||||
acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
|
||||
root = "${dataDir}";
|
||||
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
# React client-side routing support
|
||||
locations."/".extraConfig = ''
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
'';
|
||||
|
||||
# Cache static assets
|
||||
locations."~* \\.(js|jpg|gif|png|webp|css|woff2|svg|ico)$".extraConfig = ''
|
||||
expires 365d;
|
||||
add_header Pragma "public";
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Deny PHP execution
|
||||
locations."~ [^/]\\.php(/|$)".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
|
||||
users.users."${domain}" = {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
home = dataDir;
|
||||
homeMode = "770";
|
||||
group = "nginx";
|
||||
openssh.authorizedKeys.keys = [
|
||||
# Add deployment SSH key here
|
||||
];
|
||||
};
|
||||
|
||||
users.groups.${domain} = {};
|
||||
}
|
||||
49
hosts/amzebs-01/sites/ebs.cloonar.dev.nix
Normal file
49
hosts/amzebs-01/sites/ebs.cloonar.dev.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
domain = "ebs.cloonar.dev";
|
||||
dataDir = "/var/www/${domain}";
|
||||
in {
|
||||
services.nginx.virtualHosts."${domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# Use HTTP-01 challenge for Let's Encrypt
|
||||
acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
|
||||
root = "${dataDir}";
|
||||
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
# React client-side routing support
|
||||
locations."/".extraConfig = ''
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
'';
|
||||
|
||||
# Cache static assets
|
||||
locations."~* \\.(js|jpg|gif|png|webp|css|woff2|svg|ico)$".extraConfig = ''
|
||||
expires 365d;
|
||||
add_header Pragma "public";
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Deny PHP execution
|
||||
locations."~ [^/]\\.php(/|$)".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
|
||||
users.users."${domain}" = {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
home = dataDir;
|
||||
homeMode = "770";
|
||||
group = "nginx";
|
||||
openssh.authorizedKeys.keys = [
|
||||
# Add deployment SSH key here
|
||||
];
|
||||
};
|
||||
|
||||
users.groups.${domain} = {};
|
||||
}
|
||||
49
hosts/amzebs-01/sites/stage.ebs.amz.at.nix
Normal file
49
hosts/amzebs-01/sites/stage.ebs.amz.at.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
domain = "stage.ebs.amz.at";
|
||||
dataDir = "/var/www/${domain}";
|
||||
in {
|
||||
services.nginx.virtualHosts."${domain}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
# Use HTTP-01 challenge for Let's Encrypt
|
||||
acmeRoot = lib.mkForce "/var/lib/acme/acme-challenge";
|
||||
root = "${dataDir}";
|
||||
|
||||
locations."/favicon.ico".extraConfig = ''
|
||||
log_not_found off;
|
||||
access_log off;
|
||||
'';
|
||||
|
||||
# React client-side routing support
|
||||
locations."/".extraConfig = ''
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
'';
|
||||
|
||||
# Cache static assets
|
||||
locations."~* \\.(js|jpg|gif|png|webp|css|woff2|svg|ico)$".extraConfig = ''
|
||||
expires 365d;
|
||||
add_header Pragma "public";
|
||||
add_header Cache-Control "public";
|
||||
'';
|
||||
|
||||
# Deny PHP execution
|
||||
locations."~ [^/]\\.php(/|$)".extraConfig = ''
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
|
||||
users.users."${domain}" = {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
home = dataDir;
|
||||
homeMode = "770";
|
||||
group = "nginx";
|
||||
openssh.authorizedKeys.keys = [
|
||||
# Add deployment SSH key here
|
||||
];
|
||||
};
|
||||
|
||||
users.groups.${domain} = {};
|
||||
}
|
||||
1
hosts/amzebs-01/utils
Symbolic link
1
hosts/amzebs-01/utils
Symbolic link
@@ -0,0 +1 @@
|
||||
../../utils
|
||||
Reference in New Issue
Block a user