Bash script to ssh to specific urls of a common format? - bash

All the vms at work I need to ssh into are of a common format (stuff014.stuff.com) with differing numbers. Is there a quick way to connect to them without making a big ssh config file and without using alias?

(Replace <your_user_name> with your user name.)
#!/bin/bash
ssh <your_user_name>#stuff$1.stuff.com
The $1 is the first parameter given, so if this was named easyssh.sh and you needed to get to 014 do
./easyssh.sh 014
To make this even better add it to a folder on your PATH (or add the directory to your path, whichever suits your needs).

You wouldn't need a big config file. A minimal implementation only requires two lines.
host stuff*
HostName %h.stuff.com
Any host you try to connect to is matched against the host patterns in your config file, stopping at the first one that matches. The HostName directive uses the matched host (%h) to construct the actual host name to connect to.
Then you can abbreviate the host name when running ssh:
$ ssh stuff014
# Connects to stuff014.stuff.com

Related

Copy file to multiple hosts from a shared file server with password

I have about 20 Macs on my network that always need fonts installed.
I have a folder location where I ask them to put the fonts they need synced to every machine (as to save time i will install the font on every machine so that if they move machines, i don't need to do it again)
at the moment I am just manually rsyncing the fonts from this server location to all the machines one by one using
rsync -avrP /server/fonts/ /Library/Fonts/
this requires me to ssh into every machine
is there a way i can script this using a hosts.txt file with the ips? the password is the same for every machine and i'd rather not type it 20 times. Security isn't an issue.
something that allows me to call the script and point it at a font i.e.
./install-font font.ttf
I've looked into scp but I don't see any example of specifying a password anywhere in the script.
cscp.sh
#!/bin/bash
while read host; do
scp $1 ${host}:
done
project-prod-web1
project-prod-web2
project-prod-web3
Usage
Copy file to multiple hosts:
cscp.sh file < hosts
But this asks me to type a password every time and doesn't specify the target location on the host.
I don't see any example of specifying a password anywhere in the script.
Use ssh-copy-id command to install your public key to each of these hosts. After that ssh and scp will use public-private key authentication without requiring you to enter the password.

SSH config file limited to 100 identity files

I have to connect to more than 100 machines through SSH. I made an script to make all the connections and perform the changes that i need. The problem is that i cant type the password every time i execute the script for each of the remote machines. Then, I found out that I could create a file in the /root/.ssh/ directory named config where I can store lines like this:
IdentityFile /root/.ssh/id_rsa_XXXX
The key pair is saved also in /root/.ssh/ but the problem is that there is a limit of 100 identity files that I can write in the config file.
Do u know if there's a workaround to make this possible?
Thanks to all, first question here! :)
First of all, if you have 100 servers to connect and 100 keys, you are doing it wrong. You can reuse the public key for other servers if you make sure the private key is safe.
If you are trying to load all the keys to ssh at once, you are doing it also wrong. The ssh config has a Host keyword, which can be made to filter which key is supposed to be used on which server. And I advise you to use it. Otherwise ssh will not know what key to use to which server and it also overcomes the limit.
Do you have separate ssh keys for each and every server? You could bundle them (one key for each type/function of server). Then you wouldn't need to specify each inside a config file.
Another way around this, would be to call the key from the command line, instead of a config file like so:
ssh -i /root/.ssh/id_rsa_XXX -l user.name server.example.com
If you do it carefully, you could create /root/.ssh/hostname where hostname is the actual hostname of the server you want to connect to. For example:
/root/.ssh/server.example.com
You could then script (BASH) like so (assuming you call the script dossh.sh):
key_and_hostname=$1
ssh -i /root/.ssh/${key_and_hostname} -l user.name ${key_and_hostname}
call the script like:
dossh.sh server.example.com

How to autocomplete or use abbreviations in bash command

Everyday I have to transfer files to many (6) AWS EC2 instances via SCP, from my bash terminal, on Linux Debian 8. I have to hand write:
i) files to transfer;
ii) destination folder;
iii) url to my .pem certificate;
iv) openning urls on the servers: ec2-user#XX.XX.XXX....
As a lazy programmer I want to use some kind of abbreviation in order to type less, having in mind that iii) and iv) are the same generally.
First I wrote a bash script which asks me for files to be transferred and folder on my server, however it takes more time due to the fact that prompts for an answer every time I transfer. Instead, I can just use arrow to repeat the bash command previously introduced.
Here is an example of the current command I use to run:
scp -i /pem/aws.pem file_to_upload.txt ec2-user#XX-XX-XX-XX.amazonwas.com:/var/www/html/folder/
the following strings require repeated typing:
scp -i /pem/aws.pem
ec2-user#..... // this is a large string of 64 characters.
I'd love some sort of placeholder, where I just type the path to files to upload and the remote folder.
How can I autocomplete or use abbreviations, like VIM to insert the same recurrent text in a bash command?
All the solutions already posted work, but they are really ugly and not the way how it should be. Remember, we still have ~/.ssh/config?
scp -i /pem/aws.pem file_to_upload.txt ec2-user#XX-XX-XX-XX.amazonwas.com:/var/www/html/folder/
will boil down to
scp file_to_upload.txt am:/var/www/html/folder/
if you set up your ~/.ssh/config:
Host am:
Hostname XX-XX-XX-XX.amazonwas.com
User ec2-user
IdentityFile /pem/aws.pem
There your local file gets auto-completed and remote directory also if you don't use passphrase (or set up ControlMaster and ControlPersist options - this will even be fast!).
Sounds like you could take advantage of using some bash aliases in your bashrc or bash_profile.
Take a look at my .bashrc file on githut
I often need to know what is my ip address. One example of a bash alias is my showip alias.
alias showip='ifconfig | grep "inet" | grep -v 127.0.0.1'
I have also created aliases to ssh into my Linux boxes. You could create a bash alias that should solve your problem.
Copying directory recursively from host:
scp -r user#host:/directory/SourceFolder TargetFolder
NOTE: If the host is using a port other than port 22, you can specify it with the -P option:
scp -P 2222 user#host:/directory/SourceFile TargetFile
When you are connecting to your bash terminal with a ssh program, see what keyboard mappings your ssh supports.
Other options, based on
echo "This is a line I do not want to type twice"
Look how you can use the bash history
!!
^twice^two times^
You can put your abbreviations in shell variables
no2="This is a line I do not want to type twice"
echo "${no2}"
And you can use an alias
my2='echo "This is a line I do not want to type twice"'
my2
The shell variables and aliases can be put in ${HOME}/.bashrc.

Bash script to ssh to particular server

I'm wondering how I would go about creating my own bash script to ssh to a server. I know it's lazy, but I would ideally want not to have to type out:
ssh username#server
And just have my own two letter command instead (i.e. no file extension, and executable from any directory).
Any help would be much appreciated. If it helps with specifying file paths etc, I am using Mac OS X.
You can set configs for ssh in file ~/.ssh/config:
Host dev
HostName mydom.example.com
User myname
Then, just type
$> ssh dev
And you're done. Also, you can add your public key to the file ~/.ssh/authorized_keys so you won't get prompted for your password every time you want to connect via ssh.
Use an alias.
For example: alias sv='ssh user#hostname', then you can simply type sv.
Be sure to put a copy of the aliases in your profile, otherwise they will disappear at the end of your session.
you could create an alias like this:
alias ss="ssh username#server" and write it into your .bash_profile. ".bash_profile" is a hidden file is located in your home directory. If .bash_profile doesn't exist yet (check by typing ls -a in your home directory), you can create it yourself.
The bash_profile file will be read and executed every time you open a new shell.
You can use ssh-argv0 to avoid typing ssh.
To do this, you need to create a link to ssh-argv0 with the name of the host you want to connect, including the user if needed. Then you can execute that link, and ssh will connect you to the host of the link name.
Example
Setup the link:
ln -s /usr/bin/ssh-argv0 ~/bin/my-server
/usr/bin/ssh-argv0 is the path of ssh-argv0 on my system, yours could be different, check with which ssh-argv0
I have put it in ~/bin/ to be able to execute it from any directory (in OS X you may need to add ~/bin/ manually to your path on .bash_profile)
my-server is the name of my server, and if needed to set the user, it would be user#my-server
Execute it:
my-server
Even more
You can also combine this with mogeb answer to configure your server connection, so that you can call it with a shorter name, and avoid to include the user even if it is different than on the local system.
Host serv
HostName my-server
User my-user
Port 22
then set a link to ssh-argv0 with the name serv, and connect to it with
serv

Can we set easy-to-remember hostnames for EC2 instances?

I'm running a couple of standard Fedora instances on EC2. I feel the public hostnames of the instances assigned by Amazon are too weird and hard to remember. I'd like to change them to something short (like red/blue/green/etc).
Is there any draw back in doing this? And how do I set it up such that it persists after reboots?
Thanks.
Before you get started, try running hostname and hostname --fqdn and take note of what the responses are.
You can edit /etc/hostname and set a hostname, which will stick around after rebooting. You can force the hostname to be "reloaded" by using hostname -F /etc/hostname to read that value into the hostname. The bash prompt will change after you logout and login.
warning / note:
Yes, it is nice to have the hostname in the bash prompt set to something more useful than ip-123-123-123-123 but I've decided to leave mine (at least for now) because it seems like a lot of things really count on having the hostname on ec2 instances set in a standard way. After editing /etc/hostname and changing the hostname to webserver a lot of the services seems to fail because the hostname would not resolve, and apache wouldn't start. Next I edited /etc/hosts and added in
127.0.0.1 webserver
as the second line. Apache would then start but complained that it couldn't find the FQDN. I confirmed that running hostname --fqdn no longer worked.
Next I consulted man hostname and learned that while you can set the hostname it appears that the FQDN is what is returned via a DNS lookup.
THE FQDN
You can't change the FQDN (as returned by hostname --fqdn) or the DNS domain name (as returned by dnsdomainname) with this command. The FQDN of the system is the name that the resolver(3) returns for the host name.
Technically: The FQDN is the name getaddrinfo(3) returns for the host name returned by gethostname(2). The DNS domain name is the part after the first dot.
Therefore it depends on the configuration (usually in /etc/host.conf) how you can change it. Usually (if the hosts file is parsed before DNS or NIS) you can change it in /etc/hosts.
I think it might be possible to set the system / fool the system into return the FQDN, something like ip-123-123-123-123.ec2.internal even though the hostname is webserver but at this point it started to seem like more trouble than it was worth, and that for me to have a nicer bash prompt might cause a lot software and configuration problems down the road and so I decided to give up.
I also learned that a lot of amazon ec2 instances use something called cloud-init:
cloud-init is the Ubuntu package that handles early initialization of a cloud instance. It is installed in the Ubuntu Cloud Images and also in the official Ubuntu images available on EC2.
Some of the things it configures are:
setting a default locale
setting hostname
generate ssh private keys
adding ssh keys to user's .ssh/authorized_keys so they can log in
setting up ephemeral mount points
cloud-init's behavior can be configured via user-data. User-data can be given by the user at instance launch time. This is done via the --user-data or --user-data-file argument to ec2-run-instances
I also found this which talks about how the hostname is configured with cloud-init:
On EBS instances, a shutdown and later start would end up with a different IP address.
In the case where the user has not modified /etc/hostname from its original value (seeded by metadata's 'local-hostname'), then cloud-init will again set the hostname and update /etc/hostname.
In the case where the user has modified /etc/hostname, it will remain user managed.
Additionally, if /etc/cloud/cloud.cfg contains 'preserve_hostname' value set to a True value, then /etc/hostname will not ever be touched.
The interesting takeaway is that if you don't change the hostname the cloud-init package will keep it up to date for you.
If someone else has a workaround or can address some of the issues mentioned and help reassure that nothing will break on ec2 instances because of changing the hostname I would be happy to hear it.
Another way is to simply edit ~/.bashrc and prepend PS1 with the nickname of the machine.
Edit: perhaps more correctly, machine-wide, e.g. on the AWS Linux AMI (an example) (paste this into console or add to your arbitrary install .sh):
cat << EOF | sudo tee /etc/profile.d/ps1.sh
if [ "$PS1" ]; then
PS1="[\u#myinst1:\l \t \! \W]\\$ "
fi
EOF
Edit /etc/sysconfig/network as root.
Replace
HOSTNAME=localhost.localdomain
with
HOSTNAME=hostname.DOMAIN_NAME
Then, either reboot or run /etc/init.d/network restart
The server then should report its name as a FQDN.
From this site:
Change the hostname on a running system
On any Linux system you can change its hostname with the command hostname (surprised?)…
Here are some quick usages of the command line hostname:
$> hostname
without any parameter it will output the current hostname of the system.
$> hostname --fqd
it will output the fully qualified domain name (or FQDN) of the system.
$> hostname NEW_NAME
will set the hostname of the system to NEW_NAME.
You can also edit /etc/hostname (at least on Ubuntu).
To make sure it stays after a reboot in AWS, either add the command in /etc/rc.local so it runs when the machine starts.
There's also a way to set the hostname dynamically via USER_DATA:
USER_DATA=`/usr/bin/curl -s http://169.254.169.254/latest/user-data`
HOSTNAME=`echo $USER_DATA`
IPV4=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
hostname $HOSTNAME
echo $HOSTNAME > /etc/hostname
To change the system hostname to a public DNS name
Follow this procedure if you already have a public DNS name registered
Open the /etc/sysconfig/network configuration file in your favorite text editor and change the HOSTNAME entry to reflect the fully qualified domain name (such as webserver.mydomain.com).
HOSTNAME=webserver.mydomain.com
Reboot the instance to pick up the new hostname.
[ec2-user ~]$ sudo reboot
Log into your instance and verify that the hostname has been updated. Your prompt should show the new hostname (up to the first ".") and the hostname command should show the fully qualified domain name.
[ec2-user#webserver ~]$ hostname
webserver.mydomain.com
To change the system hostname without a public DNS name
Open the /etc/sysconfig/network configuration file in your favorite text editor and change the HOSTNAME entry to reflect the desired system hostname (such as webserver).
HOSTNAME=webserver.localdomain
Open the /etc/hosts file in your favorite text editor and add an entry beginning with 127.0.1.1 (on DHCP systems) or eth0's address (on static IP systems) to match the example below, substituting your own hostname. (127.0.0.1 should be left as the localhost line.)
127.0.0.1 localhost localhost.localdomain
127.0.1.1 webserver.example.com webserver
Reboot the instance to pick up the new hostname.
[ec2-user ~]$ sudo reboot
Log into your instance and verify that the hostname has been updated. Your prompt should show the new hostname (up to the first ".") and the hostname command should show the fully qualified domain name.
[ec2-user#webserver ~]$ hostname
webserver.localdomain
Note: You can also change the shell prompt without affecting the hostname. Refer to this AWS documentation.
Sure, you can do that if you have your own domain (setup a CNAME to point to the Amazon hostname). Otherwise, you're pretty much stuck with the one they give you (or an Elastic IP, if you set one of those up).
The /etc/rc.local solution worked for me for a basic hostname but does not give me a FQDN.
In my Linux AMI (a snapshot of other instance).. none of the above formula worked. Then, I simply changed HOSTNAME field in file: /etc/init.d/modifyhostname and did a normal reboot.
You will need to do multiple things to set the hostname:
hostname newname - sets the hostname, but is volatile
edit /etc/hostname - sets the hostname for the next reboot
edit /etc/hosts - to keep sudo from complaining
I put these together into a script and uploaded it as a gist:
https://gist.github.com/mnebuerquo/5443532036af8b48995547e2817dba85
sudo hostname *yourdesiredhostnamehere*
sudo /etc/init.d/networking restart
then the hostname is changed. On my server all other services like apache and postfix works. Server is Ubuntu 12.04 LTS

Resources