···7 torDirectory = "/var/lib/tor";
89 opt = name: value: optionalString (value != null) "${name} ${value}";
10- optint = name: value: optionalString (value != 0) "${name} ${toString value}";
1112 torRc = ''
13 User tor
···17 GeoIPv6File ${pkgs.tor.geoip}/share/tor/geoip6
18 ''}
1920- ${optint "ControlPort" cfg.controlPort}
21 ''
22 # Client connection config
23 + optionalString cfg.client.enable ''
···27 ''
28 # Relay config
29 + optionalString cfg.relay.enable ''
30- ORPort ${cfg.relay.portSpec}
031 ${opt "Nickname" cfg.relay.nickname}
32 ${opt "ContactInfo" cfg.relay.contactInfo}
33···36 ${opt "AccountingMax" cfg.relay.accountingMax}
37 ${opt "AccountingStart" cfg.relay.accountingStart}
3839- ${if cfg.relay.isExit then
40 opt "ExitPolicy" cfg.relay.exitPolicy
41 else
42 "ExitPolicy reject *:*"}
4344- ${optionalString cfg.relay.isBridge ''
45 BridgeRelay 1
46 ServerTransportPlugin obfs2,obfs3 exec ${pkgs.pythonPackages.obfsproxy}/bin/obfsproxy managed
0000047 ''}
48 ''
49- + hiddenServices
00000050 + cfg.extraConfig;
5152- hiddenServices = concatStrings (mapAttrsToList (hiddenServiceDir: hs:
53- let
54- hsports = concatStringsSep "\n" (map mkHiddenServicePort hs.hiddenServicePorts);
55- in
56- "HiddenServiceDir ${hiddenServiceDir}\n${hsports}\n${hs.extraConfig}\n"
57- ) cfg.hiddenServices);
5859- mkHiddenServicePort = hsport: let
60- trgt = optionalString (hsport.target != null) (" " + hsport.target);
61- in "HiddenServicePort ${toString hsport.virtualPort}${trgt}";
62-63- torRcFile = pkgs.writeText "torrc" torRc;
64in
65{
66 options = {
···96 };
9798 controlPort = mkOption {
99- type = types.int;
100- default = 0;
101 example = 9051;
102 description = ''
103 If set, Tor will accept connections on the specified port
···133 example = "192.168.0.1:9101";
134 description = ''
135 Bind to this address to listen for connections from
136- Socks-speaking applications. Same as socksListenAddress
137- but uses weaker circuit isolation to provide performance
138- suitable for a web browser.
0139 '';
140 };
141···145 example = "accept 192.168.0.0/16, reject *";
146 description = ''
147 Entry policies to allow/deny SOCKS requests based on IP
148- address. First entry that matches wins. If no SocksPolicy
149 is set, we accept all (and only) requests from
150- SocksListenAddress.
151 '';
152 };
153···176 description = ''
177 Whether to enable relaying TOR traffic for others.
178179- See https://www.torproject.org/docs/tor-doc-relay for details.
0000000180 '';
181 };
182183- isBridge = mkOption {
184- type = types.bool;
185- default = false;
186 description = ''
187- Bridge relays (or "bridges") are Tor relays that aren't
188- listed in the main directory. Since there is no complete
189- public list of them, even if an ISP is filtering
190- connections to all the known Tor relays, they probably
191- won't be able to block all the bridges.
00000000000000000000000000000000000192193- A bridge relay can't be an exit relay.
0000194195- You need to set relay.enable to true for this option to
196- take effect.
00000197198- The bridge is set up with an obfuscated transport proxy.
0000000199200- See https://www.torproject.org/bridges.html.en for more info.
201- '';
202- };
00203204- isExit = mkOption {
205- type = types.bool;
206- default = false;
207- description = ''
208- An exit relay allows Tor users to access regular Internet
209- services.
210211- Unlike running a non-exit relay, running an exit relay may
212- expose you to abuse complaints. See
213- https://www.torproject.org/faq.html.en#ExitPolicies for
214- more info.
0000215216- You can specify which services Tor users may access via
217- your exit relay using exitPolicy option.
0000000000000000000000000000000000000000218 '';
219 };
220···268 };
269270 bandwidthRate = mkOption {
271- type = types.int;
272- default = 0;
273 example = 100;
274 description = ''
275 Specify this to limit the bandwidth usage of relayed (server)
···278 };
279280 bandwidthBurst = mkOption {
281- type = types.int;
282 default = cfg.relay.bandwidthRate;
283 example = 200;
284 description = ''
···288 '';
289 };
290291- portSpec = mkOption {
292- type = types.str;
293- example = "143";
0000000000294 description = ''
295 What port to advertise for Tor connections. This corresponds to the
296 <literal>ORPort</literal> section in the Tor manual; see
···313 considered first to last, and the first match wins. If you
314 want to _replace_ the default exit policy, end this with
315 either a reject *:* or an accept *:*. Otherwise, you're
316- _augmenting_ (prepending to) the default exit
317- policy. Leave commented to just use the default, which is
318 available in the man page or at
319- https://www.torproject.org/documentation.html
320321- Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
322- for issues you might encounter if you use the default exit policy.
00323324 If certain IPs and ports are blocked externally, e.g. by
325 your firewall, you should update your exit policy to
···330 };
331332 hiddenServices = mkOption {
333- type = types.attrsOf (types.submodule ({
000000000000000000000000000000000000334 options = {
335- hiddenServicePorts = mkOption {
336- type = types.listOf (types.submodule {
337- options = {
338- virtualPort = mkOption {
339- type = types.int;
340- example = 80;
341- description = "Virtual port.";
342- };
343- target = mkOption {
344- type = types.nullOr types.str;
345- default = null;
346- example = "127.0.0.1:8080";
347- description = ''
348- Target virtual Port shall be mapped to.
0000000000000000000349350- You may override the target port, address, or both by
351- specifying a target of addr, port, addr:port, or
352- unix:path. (You can specify an IPv6 target as
353- [addr]:port. Unix paths may be quoted, and may use
354- standard C escapes.)
355- '';
356- };
357- };
358- });
359- example = [ { virtualPort = 80; target = "127.0.0.1:8080"; } { virtualPort = 6667; } ];
360- description = ''
361- If target is <literal>null</literal> the virtual port is mapped
362- to the same port on 127.0.0.1 over TCP. You may use
363- <literal>target</literal> to overwrite this behaviour (see
364- description of target).
365366- This corresponds to the <literal>HiddenServicePort VIRTPORT
367- [TARGET]</literal> option by looking at the tor manual
368- <citerefentry><refentrytitle>tor</refentrytitle>
369- <manvolnum>1</manvolnum></citerefentry> for more information.
370- '';
371- };
372- extraConfig = mkOption {
373- type = types.str;
374- default = "";
375- description = ''
376- Extra configuration. Contents will be added in the current
377- hidden service context.
378- '';
379- };
380- };
381- }));
382- default = {};
383- example = {
384- "/var/lib/tor/webserver" = {
385- hiddenServicePorts = [ { virtualPort = 80; } ];
386 };
387- };
388- description = ''
389- Configure hidden services.
390391- Please consult the tor manual
392- <citerefentry><refentrytitle>tor</refentrytitle>
393- <manvolnum>1</manvolnum></citerefentry> for a more detailed
394- explanation. (search for 'HIDDEN').
395- '';
396 };
397 };
398 };
399400 config = mkIf cfg.enable {
401- assertions = singleton
402- { message = "Can't be both an exit and a bridge relay at the same time";
403- assertion =
404- cfg.relay.enable -> !(cfg.relay.isBridge && cfg.relay.isExit);
405- };
0000000406407 users.extraGroups.tor.gid = config.ids.gids.tor;
408 users.extraUsers.tor =
···422 restartTriggers = [ torRcFile ];
423424 # Translated from the upstream contrib/dist/tor.service.in
00000425 serviceConfig =
426 { Type = "simple";
427- ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config";
428 ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0";
429 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
430 KillSignal = "SIGINT";
···7 torDirectory = "/var/lib/tor";
89 opt = name: value: optionalString (value != null) "${name} ${value}";
10+ optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}";
1112 torRc = ''
13 User tor
···17 GeoIPv6File ${pkgs.tor.geoip}/share/tor/geoip6
18 ''}
1920+ ${optint "ControlPort" (toString cfg.controlPort)}
21 ''
22 # Client connection config
23 + optionalString cfg.client.enable ''
···27 ''
28 # Relay config
29 + optionalString cfg.relay.enable ''
30+ ORPort ${toString cfg.relay.port}
31+ ${opt "Address" cfg.relay.address}
32 ${opt "Nickname" cfg.relay.nickname}
33 ${opt "ContactInfo" cfg.relay.contactInfo}
34···37 ${opt "AccountingMax" cfg.relay.accountingMax}
38 ${opt "AccountingStart" cfg.relay.accountingStart}
3940+ ${if (cfg.relay.role == "exit") then
41 opt "ExitPolicy" cfg.relay.exitPolicy
42 else
43 "ExitPolicy reject *:*"}
4445+ ${optionalString (elem cfg.relay.role ["bridge" "private-bridge"]) ''
46 BridgeRelay 1
47 ServerTransportPlugin obfs2,obfs3 exec ${pkgs.pythonPackages.obfsproxy}/bin/obfsproxy managed
48+ ExtORPort auto
49+ ${optionalString (cfg.relay.role == "private-bridge") ''
50+ ExtraInfoStatistics 0
51+ PublishServerDescriptor 0
52+ ''}
53 ''}
54 ''
55+ # Hidden services
56+ + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: ''
57+ HiddenServiceDir ${torDirectory}/onion/${v.name}
58+ ${flip concatMapStrings v.map (p: ''
59+ HiddenServicePort ${toString p.port} ${p.destination}
60+ '')}
61+ ''))
62 + cfg.extraConfig;
6364+ torRcFile = pkgs.writeText "torrc" torRc;
00000650000066in
67{
68 options = {
···98 };
99100 controlPort = mkOption {
101+ type = types.nullOr (types.either types.int types.str);
102+ default = null;
103 example = 9051;
104 description = ''
105 If set, Tor will accept connections on the specified port
···135 example = "192.168.0.1:9101";
136 description = ''
137 Bind to this address to listen for connections from
138+ Socks-speaking applications. Same as
139+ <option>socksListenAddress</option> but uses weaker
140+ circuit isolation to provide performance suitable for a
141+ web browser.
142 '';
143 };
144···148 example = "accept 192.168.0.0/16, reject *";
149 description = ''
150 Entry policies to allow/deny SOCKS requests based on IP
151+ address. First entry that matches wins. If no SocksPolicy
152 is set, we accept all (and only) requests from
153+ <option>socksListenAddress</option>.
154 '';
155 };
156···179 description = ''
180 Whether to enable relaying TOR traffic for others.
181182+ See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" />
183+ for details.
184+185+ Setting this to true requires setting
186+ <option>services.tor.relay.role</option>
187+ and
188+ <option>services.tor.relay.port</option>
189+ options.
190 '';
191 };
192193+ role = mkOption {
194+ type = types.enum [ "exit" "relay" "bridge" "private-bridge" ];
0195 description = ''
196+ Your role in Tor network. There're several options:
197+198+ <variablelist>
199+ <varlistentry>
200+ <term><literal>exit</literal></term>
201+ <listitem>
202+ <para>
203+ An exit relay. This allows Tor users to access regular
204+ Internet services through your public IP.
205+ </para>
206+207+ <important><para>
208+ Running an exit relay may expose you to abuse
209+ complaints. See
210+ <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies" />
211+ for more info.
212+ </para></important>
213+214+ <para>
215+ You can specify which services Tor users may access via
216+ your exit relay using <option>exitPolicy</option> option.
217+ </para>
218+ </listitem>
219+ </varlistentry>
220+221+ <varlistentry>
222+ <term><literal>relay</literal></term>
223+ <listitem>
224+ <para>
225+ Regular relay. This allows Tor users to relay onion
226+ traffic to other Tor nodes, but not to public
227+ Internet.
228+ </para>
229+230+ <important><para>
231+ Note that some misconfigured and/or disrespectful
232+ towards privacy sites will block you even if your
233+ relay is not an exit relay. That is, just being listed
234+ in a public relay directory can have unwanted
235+ consequences.
236237+ Which means you might not want to use
238+ this role if you browse public Internet from the same
239+ network as your relay, unless you want to write
240+ e-mails to those sites (you should!).
241+ </para></important>
242243+ <para>
244+ See
245+ <link xlink:href="https://www.torproject.org/docs/tor-doc-relay.html.en" />
246+ for more info.
247+ </para>
248+ </listitem>
249+ </varlistentry>
250251+ <varlistentry>
252+ <term><literal>bridge</literal></term>
253+ <listitem>
254+ <para>
255+ Regular bridge. Works like a regular relay, but
256+ doesn't list you in the public relay directory and
257+ hides your Tor node behind obfsproxy.
258+ </para>
259260+ <para>
261+ Using this option will make Tor advertise your bridge
262+ to users through various mechanisms like
263+ <link xlink:href="https://bridges.torproject.org/" />, though.
264+ </para>
265266+ <important>
267+ <para>
268+ WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVISE.
269+ Consult with your lawer when in doubt.
270+ </para>
0271272+ <para>
273+ This role should be safe to use in most situations
274+ (unless the act of forwarding traffic for others is
275+ a punishable offence under your local laws, which
276+ would be pretty insane as it would make ISP
277+ illegal).
278+ </para>
279+ </important>
280281+ <para>
282+ See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
283+ for more info.
284+ </para>
285+ </listitem>
286+ </varlistentry>
287+288+ <varlistentry>
289+ <term><literal>private-bridge</literal></term>
290+ <listitem>
291+ <para>
292+ Private bridge. Works like regular bridge, but does
293+ not advertise your node in any way.
294+ </para>
295+296+ <para>
297+ Using this role means that you won't contribute to Tor
298+ network in any way unless you advertise your node
299+ yourself in some way.
300+ </para>
301+302+ <para>
303+ Use this if you want to run a private bridge, for
304+ example because you'll give out your bridge address
305+ manually to your friends.
306+ </para>
307+308+ <para>
309+ Switching to this role after measurable time in
310+ "bridge" role is pretty useless as some Tor users
311+ would have learned about your node already. In the
312+ latter case you can still change
313+ <option>port</option> option.
314+ </para>
315+316+ <para>
317+ See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
318+ for more info.
319+ </para>
320+ </listitem>
321+ </varlistentry>
322+ </variablelist>
323 '';
324 };
325···373 };
374375 bandwidthRate = mkOption {
376+ type = types.nullOr types.int;
377+ default = null;
378 example = 100;
379 description = ''
380 Specify this to limit the bandwidth usage of relayed (server)
···383 };
384385 bandwidthBurst = mkOption {
386+ type = types.nullOr types.int;
387 default = cfg.relay.bandwidthRate;
388 example = 200;
389 description = ''
···393 '';
394 };
395396+ address = mkOption {
397+ type = types.nullOr types.str;
398+ default = null;
399+ example = "noname.example.com";
400+ description = ''
401+ The IP address or full DNS name for advertised address of your relay.
402+ Leave unset and Tor will guess.
403+ '';
404+ };
405+406+ port = mkOption {
407+ type = types.either types.int types.str;
408+ example = 143;
409 description = ''
410 What port to advertise for Tor connections. This corresponds to the
411 <literal>ORPort</literal> section in the Tor manual; see
···428 considered first to last, and the first match wins. If you
429 want to _replace_ the default exit policy, end this with
430 either a reject *:* or an accept *:*. Otherwise, you're
431+ _augmenting_ (prepending to) the default exit policy.
432+ Leave commented to just use the default, which is
433 available in the man page or at
434+ <link xlink:href="https://www.torproject.org/documentation.html" />.
435436+ Look at
437+ <link xlink:href="https://www.torproject.org/faq-abuse.html#TypicalAbuses" />
438+ for issues you might encounter if you use the default
439+ exit policy.
440441 If certain IPs and ports are blocked externally, e.g. by
442 your firewall, you should update your exit policy to
···447 };
448449 hiddenServices = mkOption {
450+ description = ''
451+ A set of static hidden services that terminate their Tor
452+ circuits at this node.
453+454+ Every element in this set declares a virtual onion host.
455+456+ You can specify your onion address by putting corresponding
457+ private key to an appropriate place in ${torDirectory}.
458+459+ For services without private keys in ${torDirectory} Tor
460+ daemon will generate random key pairs (which implies random
461+ onion addresses) on restart. The latter could take a while,
462+ please be patient.
463+464+ <note><para>
465+ Hidden services can be useful even if you don't intend to
466+ actually <emphasis>hide</emphasis> them, since they can
467+ also be seen as a kind of NAT traversal mechanism.
468+469+ E.g. the example will make your sshd, whatever runs on
470+ "8080" and your mail server available from anywhere where
471+ the Tor network is available (which, with the help from
472+ bridges, is pretty much everywhere), even if both client
473+ and server machines are behind NAT you have no control
474+ over.
475+ </para></note>
476+ '';
477+ default = {};
478+ example = literalExample ''
479+ { "my-hidden-service-example".map = [
480+ { port = 22; } # map ssh port to this machine's ssh
481+ { port = 80; toPort = 8080; } # map http port to whatever runs on 8080
482+ { port = "sip"; toHost = "mail.example.com"; toPort = "imap"; } # because we can
483+ ];
484+ }
485+ '';
486+ type = types.loaOf (types.submodule ({name, config, ...}: {
487 options = {
488+489+ name = mkOption {
490+ type = types.str;
491+ description = ''
492+ Name of this tor hidden service.
493+494+ This is purely descriptive.
495+496+ After restarting Tor daemon you should be able to
497+ find your .onion address in
498+ <literal>${torDirectory}/onion/$name/hostname</literal>.
499+ '';
500+ };
501+502+ map = mkOption {
503+ default = [];
504+ description = "Port mapping for this hidden service.";
505+ type = types.listOf (types.submodule ({config, ...}: {
506+ options = {
507+508+ port = mkOption {
509+ type = types.either types.int types.str;
510+ example = 80;
511+ description = ''
512+ Hidden service port to "bind to".
513+ '';
514+ };
515+516+ destination = mkOption {
517+ internal = true;
518+ type = types.str;
519+ description = "Forward these connections where?";
520+ };
521522+ toHost = mkOption {
523+ type = types.str;
524+ default = "127.0.0.1";
525+ description = "Mapping destination host.";
526+ };
0000000000527528+ toPort = mkOption {
529+ type = types.either types.int types.str;
530+ example = 8080;
531+ description = "Mapping destination port.";
532+ };
533+534+ };
535+536+ config = {
537+ toPort = mkDefault config.port;
538+ destination = mkDefault "${config.toHost}:${toString config.toPort}";
539+ };
540+ }));
541+ };
542+00000543 };
000544545+ config = {
546+ name = mkDefault name;
547+ };
548+ }));
0549 };
550 };
551 };
552553 config = mkIf cfg.enable {
554+ # Not sure if `cfg.relay.role == "private-bridge"` helps as tor
555+ # sends a lot of stats
556+ warnings = optional (cfg.relay.enable && cfg.hiddenServices != {})
557+ ''
558+ Running Tor hidden services on a public relay makes the
559+ presence of hidden services visible through simple statistical
560+ analysis of publicly available data.
561+562+ You can safely ignore this warning if you don't intend to
563+ actually hide your hidden services. In either case, you can
564+ always create a container/VM with a separate Tor daemon instance.
565+ '';
566567 users.extraGroups.tor.gid = config.ids.gids.tor;
568 users.extraUsers.tor =
···582 restartTriggers = [ torRcFile ];
583584 # Translated from the upstream contrib/dist/tor.service.in
585+ preStart = ''
586+ install -o tor -g tor -d ${torDirectory}/onion
587+ ${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config
588+ '';
589+590 serviceConfig =
591 { Type = "simple";
0592 ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0";
593 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
594 KillSignal = "SIGINT";