Home / Linux Servers
- Apache
 - Apticron
 - Avahi Daemon
 - AWS CLI
 - BIND
 - VaultWarden (Formerly bitwarden_rs)
 - Ceph
 - Certbot
 - Chrony
 - DDNS
 - Fail2ban
 - Google Authenticator
 - Home Assistant
 - Intel SSD Data Center Tool (isdct)
 - ISC DHCP Server
 - lm_sensors
 - Linux PTP
 - MariaDB
 - NFS
 - ntopng
 - ntpd
 - Network UPS Tools (NUT)
 - OpenLDAP
 - OpenSSL
 - Pi-hole (Docker)
 - Processor Counter Monitor (PCM)
 - Portainer
 - Postfix
 - Pterodactyl
 - Router Advertisement Daemon (radvd)
 - Samba (CIFS)
 - smartmontools
 - NetSNMP
 - SSHD
 - TFTP-HPA
 - Unbound
 - UniFi
 - WireGuard
 - ZFS
 
If not stated then the instructions are for Debian. Some may be for CentOS (5?) and extremely outdated. Some applications may be located in different sections/pages on this wiki.
Outdated
apt install apache2security.conf:
     ServerTokens Prod
 ServerSignature Off
a2<en|dis><conf|mod|site> <...>apache2ctlSends an emails when APT updates are available.
apt install apticron/etc/apticron/apticron.conf
    cp /usr/lib/apticron/apticron.conf /etc/apticron/apticron.conf/etc/cron.d/apticron (e.g. 30 23 * * *).IPADDRESSNUM and always print all IP adresses:
    /usr/sbin/apticron.IPADDRESSES=`(echo $( /bin/hostname --all-ip-addresses ) ;IPADDRESSES=`(apticronTODO
apt install avahi-daemonPossibly outdated
awscli through pip3chmod +x /usr/local/bin/awsaws configure [--profile <profile>]
    eu-west-2jsonaws s3 cp <local_file> s3://<bucket>/-g CLI arg forces all output to stderr, which breaks logging. Use -f instead.named-checkconf -pbind9utils package.named-compilezone -f raw -F text -o zone.tmp <zone> <zone-file>.signeddnssec-dsfromkey <dnskey-file> (use the one with digest type 2 (SHA-256))named-checkconfdig cloudflare.com @<server> should give status NOERROR and contain the ad flag (for “authentic data”, i.e. it passed DNSSEC validation).dig www.dnssec-failed.org @<server> should give status SERVFAIL.dig www.dnssec-failed.org @<server> +cd (for “checking disabled”, useful for DNSSEC debugging) should give status NOERROR but no ad flag.dig chaos txt version.bind @<server>dig chaos txt hostname.bind @<server>A free community backend for Bitwarden.
TODO
See Storage: Ceph.
apt install certbot/etc/letsencrypt/cli.ini, add renew-hook = systemctl reload nginx or equivalent.certbot -d <domain> --preferred-challenges=http --webroot --webroot-path=<webroot> certonlycertbot -d <domain> --preferred-challenges=dns --manual certonlycertbot renew --dry-run [--staging]certbot revoke --cert-path <cert>An NTP client and server. By design more accurate than e.g. ntpd and systemd-timesyncd.
See NTP for more info about NTP.
apt install chrony/etc/chrony/chrony.conf):
    server <address> iburstpool <address> iburstallow {all|<network>}systemctl restart chronychronyc trackingchronyc sourceschronyc ntpdatachronyc serverstatschronyc clientsfail2ban.fail2ban-client status [sshd].Possibly outdated
This setup requires pubkey plus MFA (if configured) plus password.
apt install libpam-google-authenticator/etc/pam.d/sshd, add auth required pam_google_authenticator.so nullok after @include common-auth./etc/ssh/sshd_config, set:
      ChallengeResponseAuthentication yes
  UsePAM yes
  AuthenticationMethods publickey,keyboard-interactive
sshd and check that you can login with pubkey and MFA now./etc/profile.d/ to ask user to configure Google Auth on login./etc/ssh/sshd_config, add Match Group no-mfa containing AuthenticationMethods publickey (indented) at the bottom.no-mfa and add special users to it.google-authenticator -tduWSee Home Assistant.
See Storage: isdct.
isc-dhcp-server./etc/dhcp/dhcpd.conf/etc/dhcp/dhcpd6.confauthorative statement in subnet declarations so that the server will reply with DHCPNAK for misconfigured clients.
This may significantly reduce reconfiguration delay when a client moves between subnets.range6, prefer using CIDR notation.
If using range notation, try to align the start and end on a CIDR block to avoid excessive memory usage./116 gives 8191 addresses.pool[6] are not applied to e.g. hosts with addresses in the same defined subnet. Don’t use pool[6]s if you don’t need to.Get sensor values like temperature, voltage, fan speeds, etc.
apt install lm-sensorssensorssensors-detect. When it asks, add the modules to /etc/modules.systemctl restart kmodsensorsjournalctl:
    chip "<chip>"\n    ignore <sensor> in /etc/sensors3.conf. Re-run sensors. (See Kernel ACPI Error SMBus/IPMI/GenericSerialBus (ServerAdminBlog) for an example on certain HP servers.)sensors. If it worked, then remove it from /etc/modules to make it permanent.Link: linuxptp.sourceforge.net
See PTP for more info about PTP.
Configure LinuxPTP as a GM using the default PTPv2 profile, with Chrony as the time source.
ethtool -T <interface>
    git clone --depth=1 --branch=v4.1 http://git.code.sf.net/p/linuxptp/code linuxptpcd linuxptpmakesudo make installcd ..cp linuxptp/configs/default.cfg /etc/ptp4l.confsudo systemctl daemon-reload && sudo systemctl enable --now ptp4l.servicesudo journalctl -u ptp4l.service -f
    sudo tcpdump -nn -i <interface> host 224.0.1.129Service config (/etc/systemd/system/ptp4l.service):
[Unit]
Description=LinuxPTP daemon
After=network.target
[Service]
ExecStart=ptp4l -4S -f /etc/ptp4l.conf -i eth0
[Install]
WantedBy=multi-user.target
A MySQL fork that is generally MySQL compatible.
apt install mariadb-servermysql_secure_installation
    mariadb [-u <user> [-p]]
    root.-p.GRANT ALL ON *.* TO '<user>'@'127.0.0.1' IDENTIFIED BY '<password>' WITH GRANT OPTION;The instructions below use NFSv4 without Kerberos. This should only be used on trusted networks and requires manual user and group ID management.
As a general guide, a home directory filesystem, which is normally exported at the root and may see lots of file renames, should be exported with subtree checking disabled. A filesystem which is mostly readonly, and at least doesn’t see many file renames (e.g. /usr or /var) and for which subdirectories may be exported, should probably be exported with subtree checks enabled.
apt install nfs-kernel-server
    portmap if you need support for NFSv2 and v3 (not NFSv4)./etc/default/nfs-common, set:
           NEED_STATD="no"
   NEED_IDMAPD="yes"
/etc/default/nfs-kernel-server, set:
           RPCNFSDOPTS="-N 2 -N 3"
   RPCMOUNTDOPTS="--manage-gids -N 2 -N 3"
   systemctl disable --now rpcbind.service
   systemctl mask rpcbind.service
   systemctl mask rpcbind.socket
systemctl restart nfs-server.servicecat /proc/fs/nfsd/versions (- means disabled)mkdir /export/zfspool/alpha /export/alpha none bind,defaults,nofail,x-systemd.requires=zfs-mount.service 0 0/etc/exports.
    exports(5).exportfs -ra
    systemctl restart nfs-server.serviceexportfs -vExample /etc/exports:
# "fsid=root" is a special root export in NFSv4 where other exports are accessible relative to it.
# "sync" should generally always be used. While "async" gives better performance, it violates the spec and may cause data loss in case of power loss.
# "root_squash" maps client root users to an anon user to prevent remote root access. If that's desired, set "no_root_squash" instead.
# "no_subtree_check" disables subtree checking. Subtree checking may be appropriate for certain file systems, but in general it may cause more problems than it solves.
# "insecure" allows clients connecting from non-well-known ports.
/export/ *(fsid=root,ro,sync,root_squash,no_subtree_check,insecure)
/export/projects/ *(rw,sync,root_squash,no_subtree_check,insecure)
apt install nfs-commonmount -t nfs4 <server-hostname>:<export> <mountpoint>/etc/fstab entry: <nfs-server>:<export> <local-dir> nfs4 defaults 0 0ntopng.ntopng is enabled and running.chown nobody:nogroup /var/log/ntopng/etc/ntopng.conf.-W=<new_port> to enable HTTPS.-w=0 to disable HTTP.Note: I recommend Chrony instead of ntpd. It’s newer and by design more accurate.
systemd-timesyncd.ntp./etc/ntp.conf, with the iburst option.ntpq -pn (it may take a minute to synchronize).Instructions for both primary nodes (netserver mode) and secondary nodes (netclient mode). Exclusive steps are marked “(Primary)” or “(Secondary)”. (Since “primary/secondary” was only recently introduced as a replacement, we’re using “master/slave” in the configs to avoid silent errors.)
apt install nut
    /etc/nut/nut.conf and set MODE=netserver for primaries or MODE=netclient for secondaries./etc/nut/ups.conf and add a declaration for all UPSes (see example below).
    usbhid-ups driver if using USB. Otherwise, check the hardware compatibility list to find the correct driver. If the exact model isn’t there, try a similar one.usbhid-ups, see the example below and usbhid-ups(8).systemctl restart nut-driver.service/etc/nut/upsd.conf and set LISTEN :: 3493 and LISTEN 0.0.0.0 (unrestricted access).
    LISTEN ::1 3493 and LISTEN 127.0.0.1./etc/nut/upsd.users and add users (see example below).
    systemctl restart nut-server.service/etc/nut/upsmon.conf and add MONITOR <ups>@<host>[:<port>] <powervalue> <user> <password> <master|slave>.
    powervalue is how many power supplies this system has which is supplied by the UPS. It’s used to calculate how many supplies are allowed to go offline. For single-PSU systems, use 1. For dual-PSU systems with both connected to this PSU, use 2. If this system is not powered by the UPS but you want to monitor it without shutting down when it goes critical, set it to 0.RBWARNTIME (how often upsmon should complain about batteries needing replacement) to an appropriate value, e.g. 604800 (1 week)./etc/nut/upsmon.conf, add EXEC to all NOTIFYFLAG entries you want to run the script for (typically all except LOWBATT)./etc/nut/upsmon.conf, set the script to run using format NOTIFYCMD /opt/scripts/nut-notify.sh.systemctl restart nut-monitor.servicenut-monitor successfully connected to the server.
    journalctl -u nut-monitor.serviceupsc uses the driver directly, so it’s not useful for debugging the server or monitoring services.upsrw -s battery.runtime.low=<seconds> <ups> and upsrw -s battery.charge.low=<percent> <ups>
        usbhid-ups, this is set using offdelay and ondelay. Otherwise, it’s set using ups.delay.shutdown and ups.delay.start. The start delay must be greater than the stop delay.
        upsmon -c fsdExample /etc/nut/ups.conf (uding usbhid-ups driver):
[alpha]
    desc = "PowerWalker VI 3000 RLE"
    # usbhid-ups should work for most UPSes with
    driver = usbhid-ups
    # Required but ignored by this driver
    port = auto
    # Sets "ups.delay.shutdown", the delay between the shutdown command and when the UPS powers off (default 20s)
    offdelay = 60
    # Sets "ups.delay.start", which has something to do with letting the UPS charge enough to make sure devices may fully boot (default 30s, must be greater than offdelay)
    ondelay = 120
Example /etc/nut/upsd.users:
[admin]
    password = <password>
    actions = set
    actions = fsd
    instcmds = all
[upsmon_local]
    password = <password>
    upsmon master
[upsmon_remote]
    password = <password>
    upsmon slave
(Notice the lack of = for upsmon.)
Example /etc/nut/upsmon.conf:
MONITOR alpha@localhost:3493 1 upsmon_local password1234 master
MINSUPPLIES 1
POLLFREQ 5
POLLFREQALERT 5
DEADTIME 20
HOSTSYNC 20
FINALDELAY 5
POWERDOWNFLAG /etc/killpower
NOTIFYCMD "/usr/bin/true"
SHUTDOWNCMD "/sbin/shutdown -h +0"
NOCOMMWARNTIME 3600
RBWARNTIME 604800
# See the original for NOTIFYMSG and NOTIFYFLAG examples.
Example notify script:
#!/bin/bash
echo -e "Time: $(date)\nMessage: $@" | mail -s "NUT: $@" root
upsc -lupsc <ups>upsdrvctl -t shutdownupsmon -c fsdNote: Anonymous users have read-only access to everything.
telnet localhost 3493LIST UPSLIST VAR <ups>sudo pacman -S openldapsudo apt install ldap-utilsldapsearch -x -b ou=people,dc=example,dc=net -H ldap://ldap.example.net uid=hon-noout -text prints the data as formatted text instead of raw Base64.openssl x509 -in <cert-file> [-inform der] -noout -textopenssl s_client -servername <host> -connect <site>:443 </dev/null | openssl x509 -noout -textopenssl pkcs12 -in hon.wtf.pfx -clcerts -nokeys -out hon.wtf.key-2023openssl pkcs12 -in hon.wtf.pfx -nocerts -out hon.wtf.key.enc-2023openssl rsa -in hon.wtf.key.enc-2023 -out hon.wtf.key-2023  openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -out localhost.crt -keyout localhost.key -config <(
  cat <<-EOF
  [req]
  default_bits = 2048
  prompt = no
  default_md = sha256
  x509_extensions = ext
  distinguished_name = dn
  [ext]
  subjectAltName = @alt_names
  basicConstraints = CA:FALSE
  #keyUsage = digitalSignature, keyEncipherment
  #extendedKeyUsage = serverAuth
  [dn]
  C = ZZ
  ST = Localhost
  L = Localhost
  O = Localhost
  OU = Localhost
  emailAddress = webmaster@localhost
  CN = localhost
  [alt_names]
  DNS.1 = *.localdomain.
  EOF
  )
docker logs pihole 2>&1 | grep "random password"/etc/pihole/adlists.list./etc/pihole/whitelist.txt.pihole -g to update lists.modprobe msr
    apt install linux-tools-genericgit clone https://github.com/opcm/pcmmake
    .x suffixes.pcmpcm-memorypcm-latencypcm-pciepcm-iiopcm-numapcm-powerpcm-tsxpcm-corepcm-querypcm-rawpcm-hw-histogrampcm-sensor-server).pcm-sensorpcm-servicepcm-sensor-serverIs typically run on a Docker host. Includes the agent.
docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v ./data:/data portainer/portainer:<version>
    /var/run/docker.sock was mounted, use “local”.Must be run on a Docker host. For extra Docker hosts you want to control with another Portainer server.
docker run -d -p 9001:9001 --name portainer_agent --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/volumes:/var/lib/docker/volumes portainer/agent:<version>_dmarc subdomain: v=DMARC1; adkim=r; aspf=r; p=quarantine;postfix libsasl2-modules mailutils
    /etc/aliases, add root: [email protected] (to forward everything to [email protected]).newaliases to update the alias DB file. (Optionally restart postfix.service to make it pick up the change instantly.)main.cf config.
    inet_interfaces = loopback-onlymynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128smtpd_banner = $myhostname ESMTPcompatibility_level = 2apikey as the username for API key access.touch sasl_passwd && chmod 600 sasl_passwd[relay_domain]:port user@domain:password
        postmap sasl_passwdpostfix.echo "Test from $(hostname) at time $(date)." | mail -s "Test" rootUse this mess to change the ugly From: [email protected] and To: [email protected] to From: "Node" <[email protected]> and To: "Admin" <[email protected]> when most/all email coming from the system is from root to some root alias.
smtp_header_checks file (arbitrary name).
    main.cf: smtp_header_checks = regexp:/etc/postfix/smtp_header_checkspostmap -fq "From: root@$(hostname --fqdn)" regexp:smtp_header_checkspostfix.echo "Test from $HOSTNAME at time $(date)." | mail -s "Test" rootpostconf > /dev/nullpostconf -nmailq tells you mails are stuck in the mail queue because of previous errors, run postqueue -f to flush them.TODO
Logs are located in /app/storage/logs/laravel/ inside the container.
unzip.{ "dns": ["1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"] } to /etc/docker/daemon.json.See Counter-Strike: Global Offensive (CS:GO).
radvd./etc/radvd.confapt install sambasystemctl disable --now nmbd and systemctl mask nmbdglobal section.server stringsecurity = userserver min protocol = SMB3map to guest = neverguest account = <username> (typically defaults to nobody)guest) to use the guest user: map to guest = bad userguest ok = {yes|no}guest ok is set) (share option): only guest = yesdisable netbios = yesnetbios name = <name> (defaults to hostname)workgroup = <workgroup>smb encrypt = requiredserver smb encrypt = requiredserver multi channel supportrss interface option and stuff. Maybe multiple NICs/IP addresses are required.socket options = SO_KEEPALIVE TCP_NODELAY IPTOS_LOWDELAYsocket options = SO_KEEPALIVE IPTOS_THROUGHPUTaio read size = 1 and aio write size = 1use sendfile = yesmin receivefile size = 16384/etc/samba/smb.conftestparm -tsystemctl restart smbduseradd -r <name>smbpasswd -a <user>sudo pdbedit -L -vapt install cifs-utils/root/.credentials/smb/<whatever>):
        user=<user>
password=<password>
/etc/fstab, add: //<share> <mountpoint> cifs vers=3.1.1,uid=<uid>,gid=<gid>,credentials=<file>,iocharset=utf8 0 0mount -amount -a)./etc/fstab entry, add ,noauto,x-systemd.automount,x-systemd.idle-timeout=30.systemctl daemon-reload && systemctl restart remote-fs.targetapt install smartmontoolssmartctl -a <dev>smartctl -t <short|long|conveyance|select> [-C] <dev>
    -C: Foreground mode.apt install snmpd/etc/snmp/snmpd.confsystemctl enable --now snmpdPermitRootLogin without-password in case you need root access to the server with tools that don’t play nice with sudo.apt install tftpd-hpa (note the d)/etc/default/tftpd-hpaTFTP_DIRECTORY="<dir>" (e.g. /var/tftp)TFTP_OPTIONS="[opt]*" (see the most relevant options below)--secure: Change the root directory to the specified TFTP_DIRECTORY directory.--create: Allow clients to upload new files. Existing files may be changed regardless.tftp:tftp has read access.tftp:tftp has write access to it.systemctl restart tftpd-hpaapt install unbound dns-root-data
    /etc/unbound/unbound.conf/etc/hosts contains the short and FQDN hostnames./etc/resolv.conf.DNSStubListener=no.DNS=::1.systemd-resolved./etc/resolv.conf. nameserver 127.0.0.1
 nameserver ::1
 domain <domain>
 search <domain-list>
systemctl restart unbounddrill sigfail.verteiltesysteme.net should give an rcode of SERVFAIL.drill sigok.verteiltesysteme.net should give an rcode of NOERROR./usr/share/dns/root.hints.See Ubiquiti UniFi Controllers.
apt install wireguardresolvconf: ln -s /usr/bin/resolvectl /usr/local/bin/resolvconf/etc/wireguard/*.confwg-quick {up|down} <conf>systemctl enable [email protected] (for config /etc/wireguard/wg0.conf)Example tunnel config:
[Interface]
# Generate with "wg genkey"
PrivateKey = <HIDDEN>
# Address for the local tunnel interface
Address = 10.234.0.3/31, 2a0f:9400:800f:ff01::1/127
DNS = 1.1.1.1, 2606:4700:4700::1111
[Peer]
# Get with "echo <privkey> | wg pubkey"
PublicKey = <HIDDEN>
# Add static route and reverse path filtering
# "0.0.0.0/0, ::/0" means this will be the default gateway, capturing all traffic
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = vpn.oolacile.hon.systems.:51823
# Keep the connection alive to keep firewall state alive (not very stealthy, though)
PersistentKeepalive = 25
See Storage: ZFS.