mirror of https://gitlab.com/curben/blog
post(nixos-caddy): update to NixOS 20.09 & caddy 2.1
This commit is contained in:
parent
62ebd35ae1
commit
a1c0b6b1d0
|
@ -133,7 +133,7 @@ shred -uz configuration.7z configuration.nix
|
||||||
|
|
||||||
Following is my "configuration.nix". I'll show you how to secure NixOS using hashed password, firewall, DNS-over-TLS and USBGuard in my next post. After that, I'll show you how to setup Caddy and Tor (they are disabled for now).
|
Following is my "configuration.nix". I'll show you how to secure NixOS using hashed password, firewall, DNS-over-TLS and USBGuard in my next post. After that, I'll show you how to setup Caddy and Tor (they are disabled for now).
|
||||||
|
|
||||||
```
|
``` nix /etc/nixos/configuration.nix
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
title: "Setup Caddy as a reverse proxy on NixOS (Part 2: Hardening)"
|
title: "Setup Caddy as a reverse proxy on NixOS (Part 2: Hardening)"
|
||||||
excerpt: "Part 2: Securing NixOS"
|
excerpt: "Part 2: Securing NixOS"
|
||||||
date: 2020-03-04
|
date: 2020-03-04
|
||||||
updated: 2020-04-22
|
updated: 2020-11-09
|
||||||
tags:
|
tags:
|
||||||
- server
|
- server
|
||||||
- linux
|
- linux
|
||||||
|
@ -10,6 +10,8 @@ tags:
|
||||||
- nixos
|
- nixos
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> 9 Nov 2020: Updated to NixOS 20.09 syntax.
|
||||||
|
|
||||||
In this post, I show you how I securely configure the NixOS, the server OS behind this website.
|
In this post, I show you how I securely configure the NixOS, the server OS behind this website.
|
||||||
|
|
||||||
This post is Part 2 of a series of articles that show you how I set up Caddy and Tor hidden service on NixOS:
|
This post is Part 2 of a series of articles that show you how I set up Caddy and Tor hidden service on NixOS:
|
||||||
|
@ -38,13 +40,13 @@ In NixOS, instead of using `useradd` and `passwd` to manage users, you could als
|
||||||
|
|
||||||
First, I disabled `useradd` and `passwd`.
|
First, I disabled `useradd` and `passwd`.
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
users.mutableUsers = false;
|
users.mutableUsers = false;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Disable root
|
## Disable root
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
users.root.hashedPassword = "*";
|
users.root.hashedPassword = "*";
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ users.root.hashedPassword = "*";
|
||||||
|
|
||||||
User's password can be configured by `users.<name>.password`, obviously this means the password is stored in plain text. Even if you lock down `configuration.nix` with `chmod 600` (which I did), "it is (still) world-readable in the Nix store". The safer way is to store in a hashed form,
|
User's password can be configured by `users.<name>.password`, obviously this means the password is stored in plain text. Even if you lock down `configuration.nix` with `chmod 600` (which I did), "it is (still) world-readable in the Nix store". The safer way is to store in a hashed form,
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
users.<name>.hashedPassword = "xxxx";
|
users.<name>.hashedPassword = "xxxx";
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@ Note that the hash is still world-readable. A more secure option is to use `user
|
||||||
|
|
||||||
You might be wondering why not just `passwordFile` during installation. The issue is that, in the live CD environment, the "/etc/" folder refers to the live CD's not the actual one which is located in "/mnt/etc/". I mean, you _could_ try "/mnt/etc/nixos/nixos.password", but you gotta remember to update the option after reboot otherwise you would get locked out. "./nixos.password" value doesn't work because `passwordFile` option doesn't support relative path, it must be a full path. Hence, I have use `hashedPassword` during the initial setup and then switch to `passwordFile`. Remember to remove the `hashedPassword` option once you have set up `passwordFile`.
|
You might be wondering why not just `passwordFile` during installation. The issue is that, in the live CD environment, the "/etc/" folder refers to the live CD's not the actual one which is located in "/mnt/etc/". I mean, you _could_ try "/mnt/etc/nixos/nixos.password", but you gotta remember to update the option after reboot otherwise you would get locked out. "./nixos.password" value doesn't work because `passwordFile` option doesn't support relative path, it must be a full path. Hence, I have use `hashedPassword` during the initial setup and then switch to `passwordFile`. Remember to remove the `hashedPassword` option once you have set up `passwordFile`.
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
passwordFile = "/etc/nixos/nixos.password";
|
passwordFile = "/etc/nixos/nixos.password";
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
|
extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
|
||||||
|
@ -84,7 +86,7 @@ For separation of privilege, each service is launched with different user under
|
||||||
|
|
||||||
Combining with the previous user configs, I ended up with:
|
Combining with the previous user configs, I ended up with:
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
users = {
|
users = {
|
||||||
mutableUsers = false;
|
mutableUsers = false;
|
||||||
|
|
||||||
|
@ -144,7 +146,7 @@ $ google-authenticator
|
||||||
|
|
||||||
Once the secret is generated, TOTP can be enabled using the following config. I configured it to require OTP when login and sudo, in addition to password.
|
Once the secret is generated, TOTP can be enabled using the following config. I configured it to require OTP when login and sudo, in addition to password.
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
## Requires OTP to login & sudo
|
## Requires OTP to login & sudo
|
||||||
security.pam = {
|
security.pam = {
|
||||||
services.login.googleAuthenticator.enable = true;
|
services.login.googleAuthenticator.enable = true;
|
||||||
|
@ -158,7 +160,7 @@ Since DNS is not encrypted in transit, it risks being tampered. To resolve that,
|
||||||
|
|
||||||
I use Cloudflare DNS simply because I'm already using its CDN, using other alternatives wouldn't have the privacy benefit since Cloudflare already knows that a visitor is browsing this website though its CDN. Refer to stubby.yml for a full list of supported servers.
|
I use Cloudflare DNS simply because I'm already using its CDN, using other alternatives wouldn't have the privacy benefit since Cloudflare already knows that a visitor is browsing this website though its CDN. Refer to stubby.yml for a full list of supported servers.
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
## DNS-over-TLS
|
## DNS-over-TLS
|
||||||
services.stubby = {
|
services.stubby = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -181,7 +183,7 @@ I use Cloudflare DNS simply because I'm already using its CDN, using other alter
|
||||||
|
|
||||||
Then I point systemd's resolved to stubby. I do configure it to fallback to unencrypted DNS if stubby is not responsive (which does happen). Whether you need an unsecured fallback depends on your cost-benefit. For me, the cost of the site being inaccessible (due to unresponsive stubby) outweighs the benefit of having enforced encryption (my setup is opportunistic).
|
Then I point systemd's resolved to stubby. I do configure it to fallback to unencrypted DNS if stubby is not responsive (which does happen). Whether you need an unsecured fallback depends on your cost-benefit. For me, the cost of the site being inaccessible (due to unresponsive stubby) outweighs the benefit of having enforced encryption (my setup is opportunistic).
|
||||||
|
|
||||||
```
|
``` nix
|
||||||
networking.nameservers = [ "::1" "127.0.0.1" ];
|
networking.nameservers = [ "::1" "127.0.0.1" ];
|
||||||
services.resolved = {
|
services.resolved = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -201,7 +203,7 @@ By default, Linux program cannot bind to port <=1024 for security reason. If a p
|
||||||
|
|
||||||
In my case, I configure iptables to port forward 443 to 4430, so any traffic that hits 443 will be redirected to 4430. Both ports need to be opened, but I do configure my dedicated firewall (separate from the web server) to allow port 443 only.
|
In my case, I configure iptables to port forward 443 to 4430, so any traffic that hits 443 will be redirected to 4430. Both ports need to be opened, but I do configure my dedicated firewall (separate from the web server) to allow port 443 only.
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
## Port forwarding
|
## Port forwarding
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -225,7 +227,7 @@ In the config, you can also specify the time that the server will reboot. I reco
|
||||||
|
|
||||||
(For more advanced usage of `dates`, see [`systemd.time`](https://jlk.fjfi.cvut.cz/arch/manpages/man/systemd.time.7#CALENDAR_EVENTS))
|
(For more advanced usage of `dates`, see [`systemd.time`](https://jlk.fjfi.cvut.cz/arch/manpages/man/systemd.time.7#CALENDAR_EVENTS))
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
system.autoUpgrade = {
|
system.autoUpgrade = {
|
||||||
enable = true;
|
enable = true;
|
||||||
allowReboot = true;
|
allowReboot = true;
|
||||||
|
@ -239,16 +241,14 @@ In the config, you can also specify the time that the server will reboot. I reco
|
||||||
I use USBGuard utility to allow or deny USB devices. In a virtual server environment, I only need to use the virtualised USB keyboard. Configuration is easy and straightforward. First, I generate a policy (with root privilege) to allow all currently connected devices:
|
I use USBGuard utility to allow or deny USB devices. In a virtual server environment, I only need to use the virtualised USB keyboard. Configuration is easy and straightforward. First, I generate a policy (with root privilege) to allow all currently connected devices:
|
||||||
|
|
||||||
```
|
```
|
||||||
# usbguard generate-policy > /var/lib/usbguard/rules.conf
|
$ sudo usbguard generate-policy > /var/lib/usbguard/rules.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, I just simply enable the service:
|
Then, I just simply enable the service:
|
||||||
|
|
||||||
``` js
|
``` nix
|
||||||
services.usbguard = {
|
# Load "/var/lib/usbguard/rules.conf" by default
|
||||||
enable = true;
|
services.usbguard.enable = true;
|
||||||
ruleFile = "/var/lib/usbguard/rules.conf";
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Once enabled, any device not whitelisted in the policy will not be accessible.
|
Once enabled, any device not whitelisted in the policy will not be accessible.
|
||||||
|
@ -306,12 +306,12 @@ Kernel compiled with additional security-oriented patch set. [More details](http
|
||||||
|
|
||||||
_NixOS [defaults](https://nixos.wiki/wiki/Linux_kernel) to the latest LTS kernel_
|
_NixOS [defaults](https://nixos.wiki/wiki/Linux_kernel) to the latest LTS kernel_
|
||||||
|
|
||||||
```
|
``` nix
|
||||||
# Latest LTS kernel
|
# Latest LTS kernel
|
||||||
boot.kernelPackages = pkgs.linuxPackages_hardened;
|
boot.kernelPackages = pkgs.linuxPackages_hardened;
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
``` nix
|
||||||
# Latest kernel
|
# Latest kernel
|
||||||
boot.kernelPackages = pkgs.linuxPackages_latest_hardened;
|
boot.kernelPackages = pkgs.linuxPackages_latest_hardened;
|
||||||
```
|
```
|
||||||
|
@ -320,11 +320,13 @@ _NixOS [defaults](https://nixos.wiki/wiki/Linux_kernel) to the latest LTS kernel
|
||||||
|
|
||||||
Since my web server has limited disk space, it needs to run [garbage collector](https://nixos.org/nixos/manual/index.html#sec-nix-gc) from time to time.
|
Since my web server has limited disk space, it needs to run [garbage collector](https://nixos.org/nixos/manual/index.html#sec-nix-gc) from time to time.
|
||||||
|
|
||||||
```
|
Since [unattended upgrade](#Unattended-upgrade) is executed on 00:00, I delay garbage collection to 01:00 to avoid time conflict. The order doesn't matter, but there should be at least 15 minutes buffer.
|
||||||
|
|
||||||
|
``` nix
|
||||||
## Garbage collector
|
## Garbage collector
|
||||||
nix.gc = {
|
nix.gc = {
|
||||||
automatic = true;
|
automatic = true;
|
||||||
# Every Monday 00:00
|
# Every Monday 01:00 (UTC)
|
||||||
dates = "weekly UTC";
|
dates = "Monday 01:00 UTC";
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
title: "Setup Caddy as a reverse proxy on NixOS (Part 3: Caddy)"
|
title: "Setup Caddy as a reverse proxy on NixOS (Part 3: Caddy)"
|
||||||
excerpt: "Part 3: Configure Caddy"
|
excerpt: "Part 3: Configure Caddy"
|
||||||
date: 2020-03-14
|
date: 2020-03-14
|
||||||
updated: 2020-09-09
|
updated: 2020-11-09
|
||||||
tags:
|
tags:
|
||||||
- server
|
- server
|
||||||
- linux
|
- linux
|
||||||
|
@ -10,6 +10,8 @@ tags:
|
||||||
- nixos
|
- nixos
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> 9 Nov 2020: Updated to Caddy 2.1 syntax. Refer to {% post_link caddy-upgrade-v2-proxy 'this article' %} for upgrade guide.
|
||||||
|
|
||||||
In this segment, I show you how I set up this website (mdleom.com) to reverse proxy to curben.netlify.app using Caddy on NixOS (see above diagram). If you're not using NixOS, simply skip to the [Caddyfile](#Caddyfile) section.
|
In this segment, I show you how I set up this website (mdleom.com) to reverse proxy to curben.netlify.app using Caddy on NixOS (see above diagram). If you're not using NixOS, simply skip to the [Caddyfile](#Caddyfile) section.
|
||||||
|
|
||||||
This post is Part 2 of a series of articles that show you how I set up Caddy and Tor hidden service on NixOS:
|
This post is Part 2 of a series of articles that show you how I set up Caddy and Tor hidden service on NixOS:
|
||||||
|
@ -26,11 +28,10 @@ This post is Part 2 of a series of articles that show you how I set up Caddy and
|
||||||
|
|
||||||
In NixOS, Caddy can be easily configured through "configuration.nix", without even touching a Caddyfile, if you have a rather simple setup. For example, to serve static files from "/var/www/" folder,
|
In NixOS, Caddy can be easily configured through "configuration.nix", without even touching a Caddyfile, if you have a rather simple setup. For example, to serve static files from "/var/www/" folder,
|
||||||
|
|
||||||
``` plain configuration.nix
|
``` nix configuration.nix
|
||||||
services.caddy = {
|
services.caddy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
email = example@example.com;
|
email = example@example.com;
|
||||||
agree = true;
|
|
||||||
config =
|
config =
|
||||||
''
|
''
|
||||||
example.com {
|
example.com {
|
||||||
|
@ -58,7 +59,7 @@ caddy.nix grants `CAP_NET_BIND_SERVICE` capability which is not needed in my use
|
||||||
|
|
||||||
I created another nix file which is similar to "caddy.nix", but without `CAP_NET_BIND_SERVICE` capability. I also removed Let's Encrypt-related options since I'm using Cloudflare origin certificate. I renamed the `options.services.caddy` to `options.services.caddyProxy` to avoid clash with "caddy.nix". Save the file to "/etc/caddy/caddyProxy.nix" with root as owner. We'll revisit this file in "[configuration.nix](#configuration.nix)" section later in this guide.
|
I created another nix file which is similar to "caddy.nix", but without `CAP_NET_BIND_SERVICE` capability. I also removed Let's Encrypt-related options since I'm using Cloudflare origin certificate. I renamed the `options.services.caddy` to `options.services.caddyProxy` to avoid clash with "caddy.nix". Save the file to "/etc/caddy/caddyProxy.nix" with root as owner. We'll revisit this file in "[configuration.nix](#configuration.nix)" section later in this guide.
|
||||||
|
|
||||||
``` plain /etc/caddy/caddyProxy.nix
|
``` nix /etc/caddy/caddyProxy.nix
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
@ -75,6 +76,16 @@ in {
|
||||||
description = "Path to Caddyfile";
|
description = "Path to Caddyfile";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
adapter = mkOption {
|
||||||
|
default = "caddyfile";
|
||||||
|
example = "nginx";
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Name of the config adapter to use.
|
||||||
|
See https://caddyserver.com/docs/config-adapters for the full list.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
dataDir = mkOption {
|
dataDir = mkOption {
|
||||||
default = "/var/lib/caddyProxy";
|
default = "/var/lib/caddyProxy";
|
||||||
type = types.path;
|
type = types.path;
|
||||||
|
@ -97,32 +108,32 @@ in {
|
||||||
systemd.services.caddyProxy = {
|
systemd.services.caddyProxy = {
|
||||||
description = "Caddy web server";
|
description = "Caddy web server";
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
environment = mkIf (versionAtLeast config.system.stateVersion "17.09")
|
|
||||||
{ CADDYPATH = cfg.dataDir; };
|
|
||||||
startLimitIntervalSec = 86400;
|
|
||||||
# 21.03+
|
# 21.03+
|
||||||
# https://github.com/NixOS/nixpkgs/pull/97512
|
# https://github.com/NixOS/nixpkgs/pull/97512
|
||||||
# startLimitBurst = 5;
|
# startLimitIntervalSec = 14400;
|
||||||
|
# startLimitBurst = 10;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = ''
|
ExecStart = "${cfg.package}/bin/caddy run --config ${cfg.config} --adapter ${cfg.adapter}";
|
||||||
${cfg.package}/bin/caddy -root=/var/tmp -conf=${cfg.config}
|
ExecReload = "${cfg.package}/bin/caddy reload --config ${cfg.config} --adapter ${cfg.adapter}";
|
||||||
'';
|
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
User = "caddyProxy";
|
User = "caddyProxy";
|
||||||
Group = "caddyProxy";
|
Group = "caddyProxy";
|
||||||
Restart = "on-failure";
|
Restart = "on-abnormal";
|
||||||
# <= 20.09
|
StartLimitIntervalSec = 14400;
|
||||||
StartLimitBurst = 5;
|
StartLimitBurst = 10;
|
||||||
NoNewPrivileges = true;
|
NoNewPrivileges = true;
|
||||||
LimitNPROC = 64;
|
LimitNPROC = 512;
|
||||||
LimitNOFILE = 1048576;
|
LimitNOFILE = 1048576;
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
PrivateDevices = true;
|
PrivateDevices = true;
|
||||||
ProtectHome = true;
|
ProtectHome = true;
|
||||||
ProtectSystem = "full";
|
ProtectSystem = "full";
|
||||||
ReadWriteDirectories = cfg.dataDir;
|
ReadWriteDirectories = cfg.dataDir;
|
||||||
|
KillMode = "mixed";
|
||||||
|
KillSignal = "SIGQUIT";
|
||||||
|
TimeoutStopSec = "5s";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,7 +141,7 @@ in {
|
||||||
home = cfg.dataDir;
|
home = cfg.dataDir;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
users.groups.caddyProxy = {
|
users.groups.caddyProxy = {
|
||||||
members = [ "caddyProxy" ];
|
members = [ "caddyProxy" ];
|
||||||
};
|
};
|
||||||
|
@ -188,7 +199,11 @@ Subsequent configurations (directives) shall be inside the curly braces. Let's s
|
||||||
```
|
```
|
||||||
mdleom.com:4430 www.mdleom.com:4430 {
|
mdleom.com:4430 www.mdleom.com:4430 {
|
||||||
tls /var/lib/caddyProxy/mdleom.com.pem /var/lib/caddyProxy/mdleom.com.key {
|
tls /var/lib/caddyProxy/mdleom.com.pem /var/lib/caddyProxy/mdleom.com.key {
|
||||||
clients /var/lib/caddyProxy/origin-pull-ca.pem
|
protocols tls1.3
|
||||||
|
client_auth {
|
||||||
|
mode require_and_verify
|
||||||
|
trusted_ca_cert_file /var/lib/caddyProxy/origin-pull-ca.pem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -198,10 +213,8 @@ mdleom.com:4430 www.mdleom.com:4430 {
|
||||||
Connection to www.mdleom.com is redirected to mdleom.com with HTTP 301 status.
|
Connection to www.mdleom.com is redirected to mdleom.com with HTTP 301 status.
|
||||||
|
|
||||||
```
|
```
|
||||||
redir 301 {
|
@www host www.mdleom.com
|
||||||
if {label1} is www
|
redir @www https://mdleom.com{uri} permanent
|
||||||
/ https://mdleom.com{uri}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`{label1}` placeholder refers to the first part of the request hostname, e.g. if hostname is `foo.bar.com`, `{label1}` is foo, `{label2}` is bar and so on.
|
`{label1}` placeholder refers to the first part of the request hostname, e.g. if hostname is `foo.bar.com`, `{label1}` is foo, `{label2}` is bar and so on.
|
||||||
|
@ -211,10 +224,8 @@ Connection to www.mdleom.com is redirected to mdleom.com with HTTP 301 status.
|
||||||
If you prefer to redirect apex to www,
|
If you prefer to redirect apex to www,
|
||||||
|
|
||||||
```
|
```
|
||||||
redir 301 {
|
@www host mdleom.com
|
||||||
if {label1} is mdleom
|
redir @www https://www.mdleom.com{uri} permanent
|
||||||
/ https://www.mdleom.com{uri}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Reverse proxy
|
### Reverse proxy
|
||||||
|
@ -229,103 +240,104 @@ Aside from reverse proxy to curben.netlify.app, I also configured my Netlify web
|
||||||
In Caddyfile, the config can be expressed as:
|
In Caddyfile, the config can be expressed as:
|
||||||
|
|
||||||
``` plain
|
``` plain
|
||||||
proxy /img https://cdn.statically.io/img/gitlab.com/curben/blog/raw/site {
|
handle_path /img/* {
|
||||||
without /img
|
rewrite * /img/gitlab.com/curben/blog/raw/site{path}
|
||||||
|
reverse_proxy https://cdn.statically.io
|
||||||
}
|
}
|
||||||
|
|
||||||
rewrite /screenshot {
|
handle_path /screenshot/* {
|
||||||
r (.*)
|
rewrite * /screenshot/curben.netlify.app{path}?mobile=true
|
||||||
to /screenshot{1}?mobile=true
|
|
||||||
|
reverse_proxy https://cdn.statically.io
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy /screenshot https://cdn.statically.io/screenshot/curben.netlify.app {
|
reverse_proxy https://curben.netlify.app
|
||||||
without /screenshot
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy / https://curben.netlify.app
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`without` directive is necessary to remove `libs/` from the path, so that "mdleom.com/libs/foo/bar.js" is linked to "https://cdn.statically.io/libs/foo/bar.js", not "https://cdn.statically.io/libs/libs/foo/bar.js".
|
`rewrite` directive is necessary to remove `img/` and `screenshot/*` from the path, so that "mdleom.com/img/foo.jpg" is linked to "https://cdn.statically.io/img/foo.jpg", not "https://cdn.statically.io/img/img/foo.jpg".
|
||||||
|
|
||||||
For `/screenshot`, since the `proxy` doesn't support variable like the Netlify `:splat`, to prepend "?mobile=true" to the link in the background (without using 301 redirection), I use `rewrite` directive which has a regex match function. I use the regex to capture the path after `screenshot` and call it using `{1}`.
|
|
||||||
|
|
||||||
### Host header
|
### Host header
|
||||||
|
|
||||||
To make sure Caddy sends the correct `Host:` header to the upstream/backend locations, I use `header_upstream` option,
|
To make sure Caddy sends the correct `Host:` header to the upstream/backend locations, I use `header_upstream` option,
|
||||||
|
|
||||||
``` plain
|
{% codeblock mark:5,13,18 %}
|
||||||
proxy /img https://cdn.statically.io/img/gitlab.com/curben/blog/raw/site {
|
handle_path /img/* {
|
||||||
without /img
|
rewrite * /img/gitlab.com/curben/blog/raw/site{path}
|
||||||
header_upstream Host cdn.statically.io
|
|
||||||
|
reverse_proxy https://cdn.statically.io {
|
||||||
|
header_up Host cdn.statically.io
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rewrite /screenshot {
|
handle_path /screenshot/* {
|
||||||
r (.*)
|
rewrite * /screenshot/curben.netlify.app{path}?mobile=true
|
||||||
to /screenshot{1}?mobile=true
|
|
||||||
|
reverse_proxy https://cdn.statically.io {
|
||||||
|
header_up Host cdn.statically.io
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy /screenshot https://cdn.statically.io/screenshot/curben.netlify.app {
|
reverse_proxy https://curben.netlify.app {
|
||||||
without /screenshot
|
header_up Host curben.netlify.app
|
||||||
header_upstream Host cdn.statically.io
|
|
||||||
}
|
}
|
||||||
|
{% endcodeblock %}
|
||||||
proxy / https://curben.netlify.app {
|
|
||||||
header_upstream Host cdn.statically.io
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
There are a few repetitions for rewriting the header for Statically. I can group that option as a global variable and call it using `import`.
|
|
||||||
|
|
||||||
```
|
|
||||||
(staticallyCfg) {
|
|
||||||
header_upstream Host cdn.statically.io
|
|
||||||
}
|
|
||||||
|
|
||||||
mdleom.com {
|
|
||||||
proxy /img ... {
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy /screenshot ... {
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Add or remove headers
|
### Add or remove headers
|
||||||
|
|
||||||
To prevent any unnecessary request headers from being sent to the upstreams, I use `header_upstream`. I use it to remove cookie, referer and [other headers](https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-) added by Cloudflare. Since there are many headers to remove, I group them as a global variable. I apply it to all `proxy` directive.
|
To prevent any unnecessary request headers from being sent to the upstreams, I use `header_up`. I use it to remove cookie, referer and [other headers](https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-) added by Cloudflare. Since there are many headers to remove, I group them as a global variable. I apply it to all `reverse_proxy` directives.
|
||||||
|
|
||||||
```
|
{% codeblock mark:25,34,40 %}
|
||||||
(removeHeaders) {
|
(removeHeaders) {
|
||||||
header_upstream -cookie
|
header_up -cdn-loop
|
||||||
header_upstream -referer
|
header_up -cf-cache-status
|
||||||
# Remove Cloudflare headers
|
header_up -cf-connecting-ip
|
||||||
# https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
|
header_up -cf-ipcountry
|
||||||
header_upstream -cf-ipcountry
|
header_up -cf-ray
|
||||||
header_upstream -cf-connecting-ip
|
header_up -cf-request-id
|
||||||
header_upstream -x-forwarded-for
|
header_up -cf-visitor
|
||||||
header_upstream -x-forwarded-proto
|
header_up -cookie
|
||||||
header_upstream -cf-ray
|
header_up -referer
|
||||||
header_upstream -cf-visitor
|
header_up -sec-ch-ua
|
||||||
header_upstream -true-client-ip
|
header_up -sec-ch-ua-mobile
|
||||||
header_upstream -cdn-loop
|
header_up -true-client-ip
|
||||||
header_upstream -cf-request-id
|
header_up -via
|
||||||
header_upstream -cf-cache-status
|
header_up -x-forwarded-for
|
||||||
|
header_up -x-forwarded-proto
|
||||||
|
header_up User-Agent "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
|
||||||
}
|
}
|
||||||
|
|
||||||
mdleom.com {
|
mdleom.com {
|
||||||
proxy /img ... {
|
handle_path /img/* {
|
||||||
|
rewrite * /img/gitlab.com/curben/blog/raw/site{path}
|
||||||
|
|
||||||
|
reverse_proxy https://cdn.statically.io {
|
||||||
|
import removeHeaders
|
||||||
|
header_up Host cdn.statically.io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /screenshot/* {
|
||||||
|
rewrite * /screenshot/curben.netlify.app{path}?mobile=true
|
||||||
|
|
||||||
|
reverse_proxy https://cdn.statically.io {
|
||||||
|
import removeHeaders
|
||||||
|
header_up Host cdn.statically.io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_proxy https://curben.netlify.app {
|
||||||
import removeHeaders
|
import removeHeaders
|
||||||
|
header_up Host curben.netlify.app
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
{% endcodeblock %}
|
||||||
|
|
||||||
The upstream locations insert some information into the response headers that are irrelevant to the site visitors. I use `header` directive to filter them out. It applies to all `proxy` directive.
|
The upstream locations insert some information into the response headers that are irrelevant to the site visitors. I use `header` directive to filter them out. It also applies to all `reverse_proxy` directives.
|
||||||
|
|
||||||
```
|
```
|
||||||
header / {
|
header {
|
||||||
-server
|
-access-control-allow-origin
|
||||||
|
-access-control-expose-headers
|
||||||
-alt-svc
|
-alt-svc
|
||||||
-cdn-cache
|
-cdn-cache
|
||||||
-cdn-cachedat
|
-cdn-cachedat
|
||||||
|
@ -334,121 +346,209 @@ The upstream locations insert some information into the response headers that ar
|
||||||
-cdn-requestcountrycode
|
-cdn-requestcountrycode
|
||||||
-cdn-requestid
|
-cdn-requestid
|
||||||
-cdn-uid
|
-cdn-uid
|
||||||
|
-cf-bgj
|
||||||
-cf-cache-status
|
-cf-cache-status
|
||||||
|
-cf-polished
|
||||||
-cf-ray
|
-cf-ray
|
||||||
-cf-request-id
|
-cf-request-id
|
||||||
|
-content-disposition
|
||||||
-etag
|
-etag
|
||||||
|
-expect-ct
|
||||||
|
-server
|
||||||
-set-cookie
|
-set-cookie
|
||||||
|
-timing-allow-origin
|
||||||
|
-via
|
||||||
-x-bytes-saved
|
-x-bytes-saved
|
||||||
-x-cache
|
-x-cache
|
||||||
|
-x-cache-hits
|
||||||
-x-nf-request-id
|
-x-nf-request-id
|
||||||
-x-served-by
|
-x-served-by
|
||||||
Cache-Control "max-age=604800, public"
|
-x-timer
|
||||||
|
Clear-Site-Data `"cookies", "storage"`
|
||||||
|
Content-Language "en-GB"
|
||||||
|
Content-Security-Policy "default-src 'self'; child-src 'none'; connect-src 'none'; font-src 'none'; frame-src 'none'; img-src 'self'; manifest-src 'none'; media-src 'none'; object-src 'none'; prefetch-src 'none'; script-src 'self'; style-src 'self'; worker-src 'none'; base-uri 'none'; form-action https://duckduckgo.com https://3g2upl4pq6kufc4m.onion; frame-ancestors 'none'; block-all-mixed-content"
|
||||||
|
Expires "0"
|
||||||
|
Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; display-capture 'none'; document-domain 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'none'; usb 'none'; vibrate 'none'; vr 'none'; wake-lock 'none'; webauthn 'none'; xr-spatial-tracking 'none'"
|
||||||
Referrer-Policy "no-referrer"
|
Referrer-Policy "no-referrer"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "DENY"
|
||||||
|
X-XSS-Protection "1; mode=block"
|
||||||
|
defer
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
I also add the `Cache-Control` and `Referrer-Policy` to the response header. Use minus (-) sign before each option to remove particular header. Without minus sign, the specified header is either added or replacing an existing one.
|
I also add the `Cache-Control` and `Referrer-Policy` to the response header. Use minus (-) sign before each option to remove particular header. Without minus sign, the specified header is either added or replacing an existing one.
|
||||||
|
|
||||||
### header and header_downstream
|
### Cache-Control
|
||||||
|
|
||||||
`/libs` folder contains third-party libraries. Since the library is usually requested by a specific version, we can safely assume that the response would remain the same. This means I can set long expiration and `immutable` on the response. [`immutable`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Revalidation_and_reloading) is to tell the browser that revalidation is not needed.
|
`/libs` folder contains third-party libraries. Since the library is usually requested by a specific version, we can safely assume that the response would remain the same. This means I can set long expiration and `immutable` on the response. [`immutable`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Revalidation_and_reloading) is to tell the browser that revalidation is not needed.
|
||||||
|
|
||||||
```
|
```
|
||||||
header / {
|
header {
|
||||||
Cache-Control "max-age=604800, public"
|
Cache-Control "max-age=86400, public"
|
||||||
}
|
}
|
||||||
|
|
||||||
header /libs {
|
header /libs/* {
|
||||||
Cache-Control "public, max-age=31536000, immutable"
|
Cache-Control "public, max-age=31536000, immutable"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Complete Caddyfile
|
### Complete Caddyfile
|
||||||
|
|
||||||
``` plain Caddyfile
|
Since I also set up reverse proxy for {% post_link tor-hidden-onion-nixos 'Tor Onion' %} and {% post_link i2p-eepsite-nixos 'I2P Eepsite' %}, I refactor most of the configuration into "common.conf" and import it into "caddyProxy.conf".
|
||||||
(removeHeaders) {
|
|
||||||
header_upstream -cookie
|
``` plain common.conf
|
||||||
header_upstream -referer
|
## Optional: disable admin endpoint and http->https redirect
|
||||||
# Remove Cloudflare headers
|
#{
|
||||||
# https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
|
# admin off
|
||||||
header_upstream -cf-ipcountry
|
# auto_https disable_redirects
|
||||||
header_upstream -cf-connecting-ip
|
#}
|
||||||
header_upstream -x-forwarded-for
|
|
||||||
header_upstream -x-forwarded-proto
|
(setHeaders) {
|
||||||
header_upstream -cf-ray
|
-access-control-allow-origin
|
||||||
header_upstream -cf-visitor
|
-access-control-expose-headers
|
||||||
header_upstream -true-client-ip
|
-alt-svc
|
||||||
header_upstream -cdn-loop
|
-cdn-cache
|
||||||
header_upstream -cf-request-id
|
-cdn-cachedat
|
||||||
header_upstream -cf-cache-status
|
-cdn-edgestorageid
|
||||||
|
-cdn-pullzone
|
||||||
|
-cdn-requestcountrycode
|
||||||
|
-cdn-requestid
|
||||||
|
-cdn-uid
|
||||||
|
-cf-bgj
|
||||||
|
-cf-cache-status
|
||||||
|
-cf-polished
|
||||||
|
-cf-ray
|
||||||
|
-cf-request-id
|
||||||
|
-content-disposition
|
||||||
|
-etag
|
||||||
|
-expect-ct
|
||||||
|
-server
|
||||||
|
-set-cookie
|
||||||
|
-timing-allow-origin
|
||||||
|
-via
|
||||||
|
-x-bytes-saved
|
||||||
|
-x-cache
|
||||||
|
-x-cache-hits
|
||||||
|
-x-nf-request-id
|
||||||
|
-x-served-by
|
||||||
|
-x-timer
|
||||||
|
Cache-Control "max-age=86400, public"
|
||||||
|
Clear-Site-Data `"cookies", "storage"`
|
||||||
|
Content-Language "en-GB"
|
||||||
|
Content-Security-Policy "default-src 'self'; child-src 'none'; connect-src 'none'; font-src 'none'; frame-src 'none'; img-src 'self'; manifest-src 'none'; media-src 'none'; object-src 'none'; prefetch-src 'none'; script-src 'self'; style-src 'self'; worker-src 'none'; base-uri 'none'; form-action https://duckduckgo.com https://3g2upl4pq6kufc4m.onion; frame-ancestors 'none'; block-all-mixed-content"
|
||||||
|
Expires "0"
|
||||||
|
Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; display-capture 'none'; document-domain 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; speaker 'none'; sync-xhr 'none'; usb 'none'; vibrate 'none'; vr 'none'; wake-lock 'none'; webauthn 'none'; xr-spatial-tracking 'none'"
|
||||||
|
Referrer-Policy "no-referrer"
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-Frame-Options "DENY"
|
||||||
|
X-XSS-Protection "1; mode=block"
|
||||||
}
|
}
|
||||||
|
|
||||||
(staticallyCfg) {
|
(removeHeaders) {
|
||||||
header_downstream Strict-Transport-Security "max-age=31536000"
|
header_up -cdn-loop
|
||||||
header_upstream Host cdn.statically.io
|
header_up -cf-cache-status
|
||||||
|
header_up -cf-connecting-ip
|
||||||
|
header_up -cf-ipcountry
|
||||||
|
header_up -cf-ray
|
||||||
|
header_up -cf-request-id
|
||||||
|
header_up -cf-visitor
|
||||||
|
header_up -cookie
|
||||||
|
header_up -referer
|
||||||
|
header_up -sec-ch-ua
|
||||||
|
header_up -sec-ch-ua-mobile
|
||||||
|
header_up -true-client-ip
|
||||||
|
header_up -via
|
||||||
|
header_up -x-forwarded-for
|
||||||
|
header_up -x-forwarded-proto
|
||||||
|
header_up User-Agent "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(oneWeekCache) {
|
||||||
|
Cache-Control "max-age=604800, public"
|
||||||
|
}
|
||||||
|
|
||||||
|
(pathProxy) {
|
||||||
|
header /js/* {
|
||||||
|
import oneWeekCache
|
||||||
|
defer
|
||||||
|
}
|
||||||
|
|
||||||
|
header /css/* {
|
||||||
|
import oneWeekCache
|
||||||
|
defer
|
||||||
|
}
|
||||||
|
|
||||||
|
header /svg/* {
|
||||||
|
import oneWeekCache
|
||||||
|
defer
|
||||||
|
}
|
||||||
|
|
||||||
|
header /libs/* {
|
||||||
|
Cache-Control "max-age=31536000, public, immutable"
|
||||||
|
defer
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /img/* {
|
||||||
|
rewrite * /img/gitlab.com/curben/blog/raw/site{path}
|
||||||
|
|
||||||
|
reverse_proxy https://cdn.statically.io {
|
||||||
|
import removeHeaders
|
||||||
|
header_up Host cdn.statically.io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header /img/* {
|
||||||
|
import oneWeekCache
|
||||||
|
defer
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /screenshot/* {
|
||||||
|
rewrite * /screenshot/curben.netlify.app{path}?mobile=true
|
||||||
|
|
||||||
|
reverse_proxy https://cdn.statically.io {
|
||||||
|
import removeHeaders
|
||||||
|
header_up Host cdn.statically.io
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header /screenshot/* {
|
||||||
|
import oneWeekCache
|
||||||
|
defer
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_proxy https://curben.netlify.app {
|
||||||
|
import removeHeaders
|
||||||
|
header_up Host curben.netlify.app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
``` plain caddyProxy.conf
|
||||||
|
import common.conf
|
||||||
|
|
||||||
## mdleom.com
|
## mdleom.com
|
||||||
mdleom.com:4430 www.mdleom.com:4430 {
|
mdleom.com:4430 www.mdleom.com:4430 {
|
||||||
tls /var/lib/caddyProxy/mdleom.com.pem /var/lib/caddyProxy/mdleom.com.key {
|
tls /var/lib/caddyProxy/mdleom.com.pem /var/lib/caddyProxy/mdleom.com.key {
|
||||||
clients /var/lib/caddyProxy/origin-pull-ca.pem
|
protocols tls1.3
|
||||||
|
client_auth {
|
||||||
|
mode require_and_verify
|
||||||
|
trusted_ca_cert_file /var/lib/caddyProxy/origin-pull-ca.pem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# www -> apex
|
# www -> apex
|
||||||
redir 301 {
|
@www host www.mdleom.com
|
||||||
if {label1} is www
|
redir @www https://mdleom.com{uri} permanent
|
||||||
/ https://mdleom.com{uri}
|
|
||||||
|
header {
|
||||||
|
import setHeaders
|
||||||
|
Onion-Location "http://xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion"
|
||||||
|
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||||
|
defer
|
||||||
}
|
}
|
||||||
|
|
||||||
header / {
|
import pathProxy
|
||||||
-server
|
|
||||||
-alt-svc
|
|
||||||
-cdn-cache
|
|
||||||
-cdn-cachedat
|
|
||||||
-cdn-edgestorageid
|
|
||||||
-cdn-pullzone
|
|
||||||
-cdn-requestcountrycode
|
|
||||||
-cdn-requestid
|
|
||||||
-cdn-uid
|
|
||||||
-cf-cache-status
|
|
||||||
-cf-ray
|
|
||||||
-cf-request-id
|
|
||||||
-etag
|
|
||||||
-set-cookie
|
|
||||||
-x-bytes-saved
|
|
||||||
-x-cache
|
|
||||||
-x-nf-request-id
|
|
||||||
-x-served-by
|
|
||||||
Cache-Control "max-age=604800, public"
|
|
||||||
Referrer-Policy "no-referrer"
|
|
||||||
}
|
|
||||||
|
|
||||||
header /libs {
|
|
||||||
Cache-Control "public, max-age=31536000, immutable"
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy /img https://cdn.statically.io/img/gitlab.com/curben/blog/raw/site {
|
|
||||||
without /img
|
|
||||||
import removeHeaders
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
rewrite /screenshot {
|
|
||||||
r (.*)
|
|
||||||
to /screenshot{1}?mobile=true
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy /screenshot https://cdn.statically.io/screenshot/curben.netlify.app {
|
|
||||||
without /screenshot
|
|
||||||
import removeHeaders
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy / https://curben.netlify.app {
|
|
||||||
import removeHeaders
|
|
||||||
header_upstream Host curben.netlify.app
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -456,7 +556,7 @@ mdleom.com:4430 www.mdleom.com:4430 {
|
||||||
|
|
||||||
One last thing to do is to import "[caddyProxy.nix](#caddyProxy.nix)" and enable `services.caddyProxy`.
|
One last thing to do is to import "[caddyProxy.nix](#caddyProxy.nix)" and enable `services.caddyProxy`.
|
||||||
|
|
||||||
``` js /etc/nixos/configuration.nix
|
``` nix /etc/nixos/configuration.nix
|
||||||
require = [ /etc/caddy/caddyProxy.nix ];
|
require = [ /etc/caddy/caddyProxy.nix ];
|
||||||
services.caddyProxy = {
|
services.caddyProxy = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
title: "How to make your website available over I2P Eepsite on NixOS"
|
title: "How to make your website available over I2P Eepsite on NixOS"
|
||||||
excerpt: "A guide on I2P Eepsite on NixOS"
|
excerpt: "A guide on I2P Eepsite on NixOS"
|
||||||
date: 2020-03-21
|
date: 2020-03-21
|
||||||
updated: 2020-09-09
|
updated: 2020-11-09
|
||||||
tags:
|
tags:
|
||||||
- server
|
- server
|
||||||
- linux
|
- linux
|
||||||
|
@ -12,6 +12,8 @@ tags:
|
||||||
- censorship
|
- censorship
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> 9 Nov 2020: Updated to Caddy 2.1 syntax. Refer to {% post_link caddy-upgrade-v2-proxy 'this article' %} for upgrade guide.
|
||||||
|
|
||||||
In this segment, I show you how I set up I2P Eepsite service that reverse proxy to curben.netlify.app. This website can be accessed using this [B32 address](http://ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p) or [mdleom.i2p](http://mdleom.i2p/)
|
In this segment, I show you how I set up I2P Eepsite service that reverse proxy to curben.netlify.app. This website can be accessed using this [B32 address](http://ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p) or [mdleom.i2p](http://mdleom.i2p/)
|
||||||
|
|
||||||
This post is Part 5 of a series of articles that show you how I set up Caddy, Tor hidden service and I2P Eepsite on NixOS:
|
This post is Part 5 of a series of articles that show you how I set up Caddy, Tor hidden service and I2P Eepsite on NixOS:
|
||||||
|
@ -123,6 +125,16 @@ in {
|
||||||
description = "Path to Caddyfile";
|
description = "Path to Caddyfile";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
adapter = mkOption {
|
||||||
|
default = "caddyfile";
|
||||||
|
example = "nginx";
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Name of the config adapter to use.
|
||||||
|
See https://caddyserver.com/docs/config-adapters for the full list.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
dataDir = mkOption {
|
dataDir = mkOption {
|
||||||
default = "/var/lib/caddyI2p";
|
default = "/var/lib/caddyI2p";
|
||||||
type = types.path;
|
type = types.path;
|
||||||
|
@ -145,40 +157,40 @@ in {
|
||||||
systemd.services.caddyI2p = {
|
systemd.services.caddyI2p = {
|
||||||
description = "Caddy web server";
|
description = "Caddy web server";
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
environment = mkIf (versionAtLeast config.system.stateVersion "17.09")
|
|
||||||
{ CADDYPATH = cfg.dataDir; };
|
|
||||||
startLimitIntervalSec = 86400;
|
|
||||||
# 21.03+
|
# 21.03+
|
||||||
# https://github.com/NixOS/nixpkgs/pull/97512
|
# https://github.com/NixOS/nixpkgs/pull/97512
|
||||||
# startLimitBurst = 5;
|
# startLimitIntervalSec = 14400;
|
||||||
|
# startLimitBurst = 10;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = ''
|
ExecStart = "${cfg.package}/bin/caddy run --config ${cfg.config} --adapter ${cfg.adapter}";
|
||||||
${cfg.package}/bin/caddy -root=/var/tmp -conf=${cfg.config}
|
ExecReload = "${cfg.package}/bin/caddy reload --config ${cfg.config} --adapter ${cfg.adapter}";
|
||||||
'';
|
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
User = "caddyProxy";
|
User = "caddyI2p";
|
||||||
Group = "caddyProxy";
|
Group = "caddyI2p";
|
||||||
Restart = "on-failure";
|
Restart = "on-abnormal";
|
||||||
# <= 20.09
|
StartLimitIntervalSec = 14400;
|
||||||
StartLimitBurst = 5;
|
StartLimitBurst = 10;
|
||||||
NoNewPrivileges = true;
|
NoNewPrivileges = true;
|
||||||
LimitNPROC = 64;
|
LimitNPROC = 512;
|
||||||
LimitNOFILE = 1048576;
|
LimitNOFILE = 1048576;
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
PrivateDevices = true;
|
PrivateDevices = true;
|
||||||
ProtectHome = true;
|
ProtectHome = true;
|
||||||
ProtectSystem = "full";
|
ProtectSystem = "full";
|
||||||
ReadWriteDirectories = cfg.dataDir;
|
ReadWriteDirectories = cfg.dataDir;
|
||||||
|
KillMode = "mixed";
|
||||||
|
KillSignal = "SIGQUIT";
|
||||||
|
TimeoutStopSec = "5s";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.caddyI2p = {
|
users.users.caddyI2p = {
|
||||||
home = cfg.dataDir;
|
home = cfg.dataDir;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
users.groups.caddyI2p = {
|
users.groups.caddyI2p = {
|
||||||
members = [ "caddyI2p" ];
|
members = [ "caddyI2p" ];
|
||||||
};
|
};
|
||||||
|
@ -188,11 +200,13 @@ in {
|
||||||
|
|
||||||
### File ownership and permissions
|
### File ownership and permissions
|
||||||
|
|
||||||
After you save the file to **/etc/caddy/caddyI2p.nix**, remember to restrict it to root.
|
After you save the file to **/etc/caddy/caddyI2p.nix**, remember to restrict it to `caddyI2p` user.
|
||||||
|
|
||||||
```
|
```
|
||||||
# chown root:root /etc/caddy/caddyI2p.nix
|
$ chown caddyI2p:caddyI2p /etc/caddy/caddyI2p.nix
|
||||||
# chown 600 /etc/caddy/caddyI2p.nix
|
$ chown 600 /etc/caddy/caddyI2p.nix
|
||||||
|
# "common.conf" must be readable by other users
|
||||||
|
$ chmod o+r /etc/caddy/common.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
## caddyFile
|
## caddyFile
|
||||||
|
@ -200,97 +214,36 @@ After you save the file to **/etc/caddy/caddyI2p.nix**, remember to restrict it
|
||||||
Create a new caddyFile in `/etc/caddy/caddyI2p.conf` and starts with the following config:
|
Create a new caddyFile in `/etc/caddy/caddyI2p.conf` and starts with the following config:
|
||||||
|
|
||||||
```
|
```
|
||||||
ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p:8081 mdleom.i2p:8081 {
|
http://ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p:8081 http://mdleom.i2p:8081 {
|
||||||
bind ::1
|
bind ::1
|
||||||
|
|
||||||
tls off
|
header {
|
||||||
|
|
||||||
header / {
|
|
||||||
-strict-transport-security
|
-strict-transport-security
|
||||||
|
defer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Update the B32 address as per the value derived from the [previous section](#B32-address). `mdleom.i2p` is my I2P domain that I registered with a jump service like [stats.i2p](http://stats.i2p/) and it acts as a shortcut to my B32 address. `tls` (HTTPS) is disabled here because it's not necessary as Tor hidden service already encrypts the traffic. Let's Encrypt doesn't support validating a .i2p address. Since HTTPS is not enabled, `strict-transport-security` (HSTS) no longer applies and the header needs to be removed to prevent the browser from attempting to connect to `https://`. It binds to loopback so it only listens to localhost.
|
Update the B32 address as per the value derived from the [previous section](#B32-address). `mdleom.i2p` is my I2P domain that I registered with a jump service like [stats.i2p](http://stats.i2p/) and it acts as a shortcut to my B32 address. HTTPS is disabled by specifying `http://` prefix, HTTPS is not necessary as Eepsite already encrypts the traffic. Let's Encrypt doesn't support validating a .i2p address. Since HTTPS is not enabled, `strict-transport-security` (HSTS) no longer applies and the header needs to be removed to prevent the browser from attempting to connect to `https://`. It binds to IPv6 loopback so it only listens to localhost, specify `bind 127.0.0.1 ::1` if you need IPv4.
|
||||||
|
|
||||||
The rest are similar to "[caddyTor.conf](/blog/2020/03/16/tor-hidden-onion-nixos/#caddyTor.conf)" and "[caddyProxy.conf](/blog/2020/03/14/caddy-nix-part-3/#caddyFile)".
|
The rest are similar to "[caddyTor.conf](/blog/2020/03/16/tor-hidden-onion-nixos/#caddyTor.conf)" and "[caddyProxy.conf](/blog/2020/03/14/caddy-nix-part-3/#Complete-Caddyfile)". Content of "common.conf" is available at [this section](/blog/2020/03/14/caddy-nix-part-3/#Complete-Caddyfile).
|
||||||
|
|
||||||
``` plain /etc/caddy/caddyI2p.conf
|
``` plain /etc/caddy/caddyI2p.conf
|
||||||
(removeHeaders) {
|
import common.conf
|
||||||
header_upstream -cookie
|
|
||||||
header_upstream -referer
|
|
||||||
header_upstream -cf-ipcountry
|
|
||||||
header_upstream -cf-connecting-ip
|
|
||||||
header_upstream -x-forwarded-for
|
|
||||||
header_upstream -x-forwarded-proto
|
|
||||||
header_upstream -cf-ray
|
|
||||||
header_upstream -cf-visitor
|
|
||||||
header_upstream -true-client-ip
|
|
||||||
header_upstream -cdn-loop
|
|
||||||
header_upstream -cf-request-id
|
|
||||||
header_upstream -cf-cache-status
|
|
||||||
}
|
|
||||||
|
|
||||||
(staticallyCfg) {
|
|
||||||
header_upstream Host cdn.statically.io
|
|
||||||
}
|
|
||||||
|
|
||||||
# I2P Eepsite
|
# I2P Eepsite
|
||||||
ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p:8081 mdleom.i2p:8081 {
|
http://ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p:8081 http://mdleom.i2p:8081 {
|
||||||
bind ::1
|
bind ::1
|
||||||
|
|
||||||
tls off
|
header {
|
||||||
|
import setHeaders
|
||||||
header / {
|
-strict-transport-origin
|
||||||
-server
|
defer
|
||||||
-alt-svc
|
|
||||||
-cdn-cache
|
|
||||||
-cdn-cachedat
|
|
||||||
-cdn-edgestorageid
|
|
||||||
-cdn-pullzone
|
|
||||||
-cdn-requestcountrycode
|
|
||||||
-cdn-requestid
|
|
||||||
-cdn-uid
|
|
||||||
-cf-cache-status
|
|
||||||
-cf-ray
|
|
||||||
-cf-request-id
|
|
||||||
-etag
|
|
||||||
-set-cookie
|
|
||||||
-strict-transport-security
|
|
||||||
-x-bytes-saved
|
|
||||||
-x-cache
|
|
||||||
-x-nf-request-id
|
|
||||||
-x-served-by
|
|
||||||
Cache-Control "max-age=604800, public"
|
|
||||||
Referrer-Policy "no-referrer"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header /libs {
|
import pathProxy
|
||||||
Cache-Control "public, max-age=31536000, immutable"
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy /img https://cdn.statically.io/img/gitlab.com/curben/blog/raw/site {
|
|
||||||
without /img
|
|
||||||
import removeHeaders
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
rewrite /screenshot {
|
|
||||||
r (.*)
|
|
||||||
to /screenshot{1}?mobile=true
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy /screenshot https://cdn.statically.io/screenshot/curben.netlify.app {
|
|
||||||
without /screenshot
|
|
||||||
import removeHeaders
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy / https://curben.netlify.app {
|
|
||||||
import removeHeaders
|
|
||||||
header_upstream Host curben.netlify.app
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Alternate Caddyfile
|
### Alternate Caddyfile
|
||||||
|
@ -299,17 +252,16 @@ There is another approach which is suitable if you have a website that you don't
|
||||||
|
|
||||||
```
|
```
|
||||||
# Do not use this approach unless you are absolutely sure
|
# Do not use this approach unless you are absolutely sure
|
||||||
ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p:8081 mdleom.i2p:8081 {
|
http://ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p:8081 http://mdleom.i2p:8081 {
|
||||||
bind ::1
|
bind ::1
|
||||||
|
|
||||||
tls off
|
header {
|
||||||
|
|
||||||
header / {
|
|
||||||
-strict-transport-security
|
-strict-transport-security
|
||||||
|
defer
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy / https://mdleom.com {
|
reverse_proxy https://mdleom.com {
|
||||||
header_upstream Host mdleom.com
|
header_up Host mdleom.com
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -318,7 +270,7 @@ ggucqf2jmtfxcw7us5sts3x7u2qljseocfzlhzebfpihkyvhcqfa.b32.i2p:8081 mdleom.i2p:808
|
||||||
|
|
||||||
Start the Caddy service.
|
Start the Caddy service.
|
||||||
|
|
||||||
``` js /etc/nixos/configuration.nix
|
``` nix /etc/nixos/configuration.nix
|
||||||
require = [ /etc/caddy/caddyProxy.nix /etc/caddy/caddyTor.nix /etc/caddy/caddyI2p.nix ];
|
require = [ /etc/caddy/caddyProxy.nix /etc/caddy/caddyTor.nix /etc/caddy/caddyI2p.nix ];
|
||||||
services.caddyI2p = {
|
services.caddyI2p = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
title: "How to make your website available over Tor hidden service on NixOS"
|
title: "How to make your website available over Tor hidden service on NixOS"
|
||||||
excerpt: "A guide on Tor hidden service on NixOS"
|
excerpt: "A guide on Tor hidden service on NixOS"
|
||||||
date: 2020-03-16
|
date: 2020-03-16
|
||||||
updated: 2020-09-09
|
updated: 2020-11-09
|
||||||
tags:
|
tags:
|
||||||
- server
|
- server
|
||||||
- linux
|
- linux
|
||||||
|
@ -12,6 +12,8 @@ tags:
|
||||||
- censorship
|
- censorship
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> 9 Nov 2020: Updated to Caddy 2.1 syntax. Refer to {% post_link caddy-upgrade-v2-proxy 'this article' %} for upgrade guide.
|
||||||
|
|
||||||
In this segment, I show you how I set up Tor hidden (.onion) service that reverse proxy to curben.netlify.app. This website can be accessed through the following [.onion address](http://xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion).
|
In this segment, I show you how I set up Tor hidden (.onion) service that reverse proxy to curben.netlify.app. This website can be accessed through the following [.onion address](http://xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion).
|
||||||
|
|
||||||
This post is Part 4 of a series of articles that show you how I set up Caddy, Tor hidden service and I2P Eepsite on NixOS:
|
This post is Part 4 of a series of articles that show you how I set up Caddy, Tor hidden service and I2P Eepsite on NixOS:
|
||||||
|
@ -32,7 +34,7 @@ Note that this only applies to the traffic between visitor and the (Caddy) web s
|
||||||
|
|
||||||
The first step is to bring up a Tor hidden service to get an onion address. Add the following options to **configuration.nix**:
|
The first step is to bring up a Tor hidden service to get an onion address. Add the following options to **configuration.nix**:
|
||||||
|
|
||||||
``` plain /etc/nixos/configuration.nix
|
``` nix /etc/nixos/configuration.nix
|
||||||
## Tor onion
|
## Tor onion
|
||||||
services.tor = {
|
services.tor = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -87,19 +89,29 @@ I set up another Caddy-powered reverse proxy which is separate from the {% post_
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.caddyTor;
|
cfg = config.services.caddyProxy;
|
||||||
in {
|
in {
|
||||||
options.services.caddyTor = {
|
options.services.caddyProxy = {
|
||||||
enable = mkEnableOption "Caddy web server";
|
enable = mkEnableOption "Caddy web server";
|
||||||
|
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
default = "/etc/caddy/caddyTor.conf";
|
default = "/etc/caddy/caddyProxy.conf";
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "Path to Caddyfile";
|
description = "Path to Caddyfile";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
adapter = mkOption {
|
||||||
|
default = "caddyfile";
|
||||||
|
example = "nginx";
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Name of the config adapter to use.
|
||||||
|
See https://caddyserver.com/docs/config-adapters for the full list.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
dataDir = mkOption {
|
dataDir = mkOption {
|
||||||
default = "/var/lib/caddyTor";
|
default = "/var/lib/caddyProxy";
|
||||||
type = types.path;
|
type = types.path;
|
||||||
description = ''
|
description = ''
|
||||||
The data directory, for storing certificates. Before 17.09, this
|
The data directory, for storing certificates. Before 17.09, this
|
||||||
|
@ -117,45 +129,45 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
systemd.services.caddyTor = {
|
systemd.services.caddyProxy = {
|
||||||
description = "Caddy web server";
|
description = "Caddy web server";
|
||||||
after = [ "network-online.target" ];
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
environment = mkIf (versionAtLeast config.system.stateVersion "17.09")
|
|
||||||
{ CADDYPATH = cfg.dataDir; };
|
|
||||||
startLimitIntervalSec = 86400;
|
|
||||||
# 21.03+
|
# 21.03+
|
||||||
# https://github.com/NixOS/nixpkgs/pull/97512
|
# https://github.com/NixOS/nixpkgs/pull/97512
|
||||||
# startLimitBurst = 5;
|
# startLimitIntervalSec = 14400;
|
||||||
|
# startLimitBurst = 10;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = ''
|
ExecStart = "${cfg.package}/bin/caddy run --config ${cfg.config} --adapter ${cfg.adapter}";
|
||||||
${cfg.package}/bin/caddy -root=/var/tmp -conf=${cfg.config}
|
ExecReload = "${cfg.package}/bin/caddy reload --config ${cfg.config} --adapter ${cfg.adapter}";
|
||||||
'';
|
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
User = "caddyProxy";
|
User = "caddyProxy";
|
||||||
Group = "caddyProxy";
|
Group = "caddyProxy";
|
||||||
Restart = "on-failure";
|
Restart = "on-abnormal";
|
||||||
# <= 20.09
|
StartLimitIntervalSec = 14400;
|
||||||
StartLimitBurst = 5;
|
StartLimitBurst = 10;
|
||||||
NoNewPrivileges = true;
|
NoNewPrivileges = true;
|
||||||
LimitNPROC = 64;
|
LimitNPROC = 512;
|
||||||
LimitNOFILE = 1048576;
|
LimitNOFILE = 1048576;
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
PrivateDevices = true;
|
PrivateDevices = true;
|
||||||
ProtectHome = true;
|
ProtectHome = true;
|
||||||
ProtectSystem = "full";
|
ProtectSystem = "full";
|
||||||
ReadWriteDirectories = cfg.dataDir;
|
ReadWriteDirectories = cfg.dataDir;
|
||||||
|
KillMode = "mixed";
|
||||||
|
KillSignal = "SIGQUIT";
|
||||||
|
TimeoutStopSec = "5s";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.caddyTor = {
|
users.users.caddyProxy = {
|
||||||
home = cfg.dataDir;
|
home = cfg.dataDir;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
users.groups.caddyTor = {
|
users.groups.caddyProxy = {
|
||||||
members = [ "caddyTor" ];
|
members = [ "caddyProxy" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -175,96 +187,40 @@ After you save the file to **/etc/caddy/CaddyTor.nix**, remember to restrict it
|
||||||
Create a new caddyFile in `/etc/caddy/caddyTor.conf` and starts with the following config:
|
Create a new caddyFile in `/etc/caddy/caddyTor.conf` and starts with the following config:
|
||||||
|
|
||||||
```
|
```
|
||||||
xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion:8080 {
|
import common.conf
|
||||||
|
|
||||||
|
# Tor onion
|
||||||
|
http://xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion:8080 {
|
||||||
bind ::1
|
bind ::1
|
||||||
|
|
||||||
tls off
|
header {
|
||||||
|
import setHeaders
|
||||||
header / {
|
-strict-transport-origin
|
||||||
-strict-transport-security
|
defer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import pathProxy
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Update the onion address to the value shown in "[/var/lib/tor/onion/myOnion/hostname](#configuration.nix)". `tls` (HTTPS) is disabled here because it's not necessary as Tor hidden service already encrypts the traffic. Let's Encrypt doesn't support validating a .onion address. The only way is to purchase the cert from [Digicert](https://www.digicert.com/blog/ordering-a-onion-certificate-from-digicert/). Since HTTPS is not enabled, `strict-transport-security` (HSTS) no longer applies and the header needs to be removed to prevent the browser from attempting to connect to `https://`. It binds to loopback so it only listens to localhost.
|
Update the onion address to the value shown in "[/var/lib/tor/onion/myOnion/hostname](#configuration.nix)". HTTPS is disabled by specifying `http://` prefix, HTTPS is not necessary as Tor hidden service already encrypts the traffic. Let's Encrypt doesn't support validating a .onion address. The only way is to purchase the cert from [Digicert](https://www.digicert.com/blog/ordering-a-onion-certificate-from-digicert/). Since HTTPS is not enabled, `strict-transport-security` (HSTS) no longer applies and the header needs to be removed to prevent the browser from attempting to connect to `https://`. It binds to IPv6 loopback so it only listens to localhost, specify `bind 127.0.0.1 ::1` if you need IPv4.
|
||||||
|
|
||||||
The rest are similar to "[caddyProxy.conf](/blog/2020/03/14/caddy-nix-part-3/#caddyFile)".
|
The rest are similar to "[caddyProxy.conf](blog/2020/03/14/caddy-nix-part-3/#Complete-Caddyfile)". Content of "common.conf" is available at [this section](/blog/2020/03/14/caddy-nix-part-3/#Complete-Caddyfile).
|
||||||
|
|
||||||
``` plain /etc/caddy/caddyTor.conf
|
``` plain /etc/caddy/caddyTor.conf
|
||||||
(removeHeaders) {
|
import common.conf
|
||||||
header_upstream -cookie
|
|
||||||
header_upstream -referer
|
|
||||||
header_upstream -cf-ipcountry
|
|
||||||
header_upstream -cf-connecting-ip
|
|
||||||
header_upstream -x-forwarded-for
|
|
||||||
header_upstream -x-forwarded-proto
|
|
||||||
header_upstream -cf-ray
|
|
||||||
header_upstream -cf-visitor
|
|
||||||
header_upstream -true-client-ip
|
|
||||||
header_upstream -cdn-loop
|
|
||||||
header_upstream -cf-request-id
|
|
||||||
header_upstream -cf-cache-status
|
|
||||||
}
|
|
||||||
|
|
||||||
(staticallyCfg) {
|
|
||||||
header_upstream Host cdn.statically.io
|
|
||||||
}
|
|
||||||
|
|
||||||
# Tor onion
|
# Tor onion
|
||||||
xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion:8080 {
|
http://xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion:8080 {
|
||||||
bind ::1
|
bind ::1
|
||||||
|
|
||||||
tls off
|
header {
|
||||||
|
import setHeaders
|
||||||
header / {
|
-strict-transport-origin
|
||||||
-server
|
defer
|
||||||
-alt-svc
|
|
||||||
-cdn-cache
|
|
||||||
-cdn-cachedat
|
|
||||||
-cdn-edgestorageid
|
|
||||||
-cdn-pullzone
|
|
||||||
-cdn-requestcountrycode
|
|
||||||
-cdn-requestid
|
|
||||||
-cdn-uid
|
|
||||||
-cf-cache-status
|
|
||||||
-cf-ray
|
|
||||||
-cf-request-id
|
|
||||||
-etag
|
|
||||||
-set-cookie
|
|
||||||
-strict-transport-security
|
|
||||||
-x-bytes-saved
|
|
||||||
-x-cache
|
|
||||||
-x-nf-request-id
|
|
||||||
-x-served-by
|
|
||||||
Cache-Control "max-age=604800, public"
|
|
||||||
Referrer-Policy "no-referrer"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header /libs {
|
import pathProxy
|
||||||
Cache-Control "public, max-age=31536000, immutable"
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy /img https://cdn.statically.io/img/gitlab.com/curben/blog/raw/site {
|
|
||||||
without /img
|
|
||||||
import removeHeaders
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
rewrite /screenshot {
|
|
||||||
r (.*)
|
|
||||||
to /screenshot{1}?mobile=true
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy /screenshot https://cdn.statically.io/screenshot/curben.netlify.app {
|
|
||||||
without /screenshot
|
|
||||||
import removeHeaders
|
|
||||||
import staticallyCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy / https://curben.netlify.app {
|
|
||||||
import removeHeaders
|
|
||||||
header_upstream Host curben.netlify.app
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -276,17 +232,16 @@ This is also suitable if you have a website that you can't root access.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Do not use this approach unless you are absolutely sure
|
# Do not use this approach unless you are absolutely sure
|
||||||
xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion:8080 {
|
http://xw226dvxac7jzcpsf4xb64r4epr6o5hgn46dxlqk7gnjptakik6xnzqd.onion:8080 {
|
||||||
bind ::1
|
bind ::1
|
||||||
|
|
||||||
tls off
|
header {
|
||||||
|
|
||||||
header / {
|
|
||||||
-strict-transport-security
|
-strict-transport-security
|
||||||
|
defer
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy / https://mdleom.com {
|
reverse_proxy https://mdleom.com {
|
||||||
header_upstream Host mdleom.com
|
header_up Host mdleom.com
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in New Issue